Spaces:
Sleeping
Sleeping
Commit
·
3ab7fe5
1
Parent(s):
71910b1
Add author search functionality and display latest affiliation in author detail view
Browse files- core/templates/author/detail.html +1 -0
- core/templates/home.html +31 -0
- core/urls.py +3 -1
- core/views.py +30 -1
core/templates/author/detail.html
CHANGED
|
@@ -2,6 +2,7 @@
|
|
| 2 |
{% block title %}{{ item.name }}{% endblock %}
|
| 3 |
{% block content %}
|
| 4 |
<h2>{{ item.name }}</h2>
|
|
|
|
| 5 |
|
| 6 |
<p><strong>Research Profile:</strong>
|
| 7 |
<a href="https://scholar.google.com/scholar?q={{ item.name|urlencode }}" target="_blank">Google Scholar</a> |
|
|
|
|
| 2 |
{% block title %}{{ item.name }}{% endblock %}
|
| 3 |
{% block content %}
|
| 4 |
<h2>{{ item.name }}</h2>
|
| 5 |
+
<p><strong>Latest Affiliation:</strong> {{ affiliation }}</p>
|
| 6 |
|
| 7 |
<p><strong>Research Profile:</strong>
|
| 8 |
<a href="https://scholar.google.com/scholar?q={{ item.name|urlencode }}" target="_blank">Google Scholar</a> |
|
core/templates/home.html
CHANGED
|
@@ -9,6 +9,10 @@
|
|
| 9 |
<input type="text" id="search-input" placeholder="Type something..." autocomplete="off" />
|
| 10 |
<ul id="results-list"></ul>
|
| 11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
{% endblock %}
|
| 13 |
|
| 14 |
{% block js %}
|
|
@@ -39,5 +43,32 @@
|
|
| 39 |
resultsList.appendChild(li)
|
| 40 |
})
|
| 41 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
</script>
|
| 43 |
{% endblock %}
|
|
|
|
| 9 |
<input type="text" id="search-input" placeholder="Type something..." autocomplete="off" />
|
| 10 |
<ul id="results-list"></ul>
|
| 11 |
|
| 12 |
+
<h2>Search Authors</h2>
|
| 13 |
+
<input type="text" id="author-search-input" placeholder="Type an author's name..." autocomplete="off" />
|
| 14 |
+
<ul id="author-results-list"></ul>
|
| 15 |
+
|
| 16 |
{% endblock %}
|
| 17 |
|
| 18 |
{% block js %}
|
|
|
|
| 43 |
resultsList.appendChild(li)
|
| 44 |
})
|
| 45 |
})
|
| 46 |
+
|
| 47 |
+
const authorInput = document.getElementById('author-search-input')
|
| 48 |
+
const authorResultsList = document.getElementById('author-results-list')
|
| 49 |
+
|
| 50 |
+
authorInput.addEventListener('input', async () => {
|
| 51 |
+
const query = authorInput.value.trim()
|
| 52 |
+
if (!query) {
|
| 53 |
+
authorResultsList.innerHTML = ''
|
| 54 |
+
return
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
const res = await fetch(`/search_author/?q=${encodeURIComponent(query)}`)
|
| 58 |
+
const data = await res.json()
|
| 59 |
+
|
| 60 |
+
authorResultsList.innerHTML = ''
|
| 61 |
+
data.results.forEach((item) => {
|
| 62 |
+
const li = document.createElement('li')
|
| 63 |
+
|
| 64 |
+
const link = document.createElement('a')
|
| 65 |
+
link.href = `/author/${item.id}/`
|
| 66 |
+
link.textContent = item.text
|
| 67 |
+
link.style.textDecoration = 'none'
|
| 68 |
+
link.style.color = 'black'
|
| 69 |
+
li.appendChild(link)
|
| 70 |
+
authorResultsList.appendChild(li)
|
| 71 |
+
})
|
| 72 |
+
})
|
| 73 |
</script>
|
| 74 |
{% endblock %}
|
core/urls.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
from django.urls import path
|
| 2 |
from .views import home_page, search_hierarchy, refresh_author_db_view, domain_list, domain_detail
|
| 3 |
from .views import field_list, field_detail, subfield_list, subfield_detail
|
| 4 |
-
from .views import topic_list, topic_detail, author_detail
|
| 5 |
|
| 6 |
|
| 7 |
urlpatterns = [
|
|
@@ -22,4 +22,6 @@ urlpatterns = [
|
|
| 22 |
path('topic/<str:pk>/', topic_detail, name='topic_detail'),
|
| 23 |
|
| 24 |
path('author/<str:pk>/', author_detail, name='author_detail'),
|
|
|
|
|
|
|
| 25 |
]
|
|
|
|
| 1 |
from django.urls import path
|
| 2 |
from .views import home_page, search_hierarchy, refresh_author_db_view, domain_list, domain_detail
|
| 3 |
from .views import field_list, field_detail, subfield_list, subfield_detail
|
| 4 |
+
from .views import topic_list, topic_detail, author_detail, search_author
|
| 5 |
|
| 6 |
|
| 7 |
urlpatterns = [
|
|
|
|
| 22 |
path('topic/<str:pk>/', topic_detail, name='topic_detail'),
|
| 23 |
|
| 24 |
path('author/<str:pk>/', author_detail, name='author_detail'),
|
| 25 |
+
|
| 26 |
+
path('search_author/', search_author, name='search_author'),
|
| 27 |
]
|
core/views.py
CHANGED
|
@@ -2,6 +2,7 @@ from django.shortcuts import render, get_object_or_404
|
|
| 2 |
# Import Author model
|
| 3 |
from .models import Domain, Field, Subfield, Topic, AuthorTopic, Author
|
| 4 |
from django.http import JsonResponse, HttpResponse
|
|
|
|
| 5 |
|
| 6 |
from BridgeMentor.utils import refresh_author_db
|
| 7 |
|
|
@@ -40,6 +41,29 @@ def search_hierarchy(request):
|
|
| 40 |
return JsonResponse({"results": sorted(results, key=lambda x: x["text"].lower())[:10]})
|
| 41 |
|
| 42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
# Domain views
|
| 44 |
|
| 45 |
|
|
@@ -102,4 +126,9 @@ def topic_detail(request, pk):
|
|
| 102 |
def author_detail(request, pk):
|
| 103 |
author = get_object_or_404(Author, pk=pk)
|
| 104 |
topics = AuthorTopic.objects.filter(author=author).select_related('topic')
|
| 105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
# Import Author model
|
| 3 |
from .models import Domain, Field, Subfield, Topic, AuthorTopic, Author
|
| 4 |
from django.http import JsonResponse, HttpResponse
|
| 5 |
+
from django.db.models import Q
|
| 6 |
|
| 7 |
from BridgeMentor.utils import refresh_author_db
|
| 8 |
|
|
|
|
| 41 |
return JsonResponse({"results": sorted(results, key=lambda x: x["text"].lower())[:10]})
|
| 42 |
|
| 43 |
|
| 44 |
+
def search_author(request):
|
| 45 |
+
q = request.GET.get("q", "").strip()
|
| 46 |
+
if not q:
|
| 47 |
+
return JsonResponse({"results": []})
|
| 48 |
+
|
| 49 |
+
results = []
|
| 50 |
+
|
| 51 |
+
authors = Author.objects.filter(
|
| 52 |
+
name__icontains=q
|
| 53 |
+
) | Author.objects.filter(
|
| 54 |
+
name__regex=rf'\b{q}\b'
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
for author in authors:
|
| 58 |
+
last_affiliation = author.affiliations.filter(
|
| 59 |
+
is_last_known=True).select_related('institution').first()
|
| 60 |
+
affiliation = last_affiliation.institution.name if last_affiliation else "No affiliation"
|
| 61 |
+
results.append(
|
| 62 |
+
{"id": author.id, "text": f"{author.name} ({affiliation})"})
|
| 63 |
+
|
| 64 |
+
return JsonResponse({"results": sorted(results, key=lambda x: x["text"].lower())[:10]})
|
| 65 |
+
|
| 66 |
+
|
| 67 |
# Domain views
|
| 68 |
|
| 69 |
|
|
|
|
| 126 |
def author_detail(request, pk):
|
| 127 |
author = get_object_or_404(Author, pk=pk)
|
| 128 |
topics = AuthorTopic.objects.filter(author=author).select_related('topic')
|
| 129 |
+
last_affiliation = author.affiliations.filter(
|
| 130 |
+
is_last_known=True).select_related('institution').first()
|
| 131 |
+
affiliation = last_affiliation.institution.name if last_affiliation else "No affiliation"
|
| 132 |
+
return render(request, 'author/detail.html', {'item': author,
|
| 133 |
+
'affiliation': affiliation,
|
| 134 |
+
'topics': topics})
|