From e0b54672e1ea9385a8a31008b9c86d5cdbe7f47d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jean-S=C3=A9bastien=20Caux?= <git@jscaux.org>
Date: Tue, 26 Oct 2021 18:54:11 +0200
Subject: [PATCH] Enable AcademicField choice for user session

---
 scipost_django/SciPost_v1/settings/base.py    |  1 +
 scipost_django/ontology/context_processors.py | 13 ++++++----
 scipost_django/ontology/forms.py              | 21 +++++++++++++++-
 .../ontology/session_acad_field_form.html     |  8 +++++++
 scipost_django/ontology/urls.py               |  5 ++++
 scipost_django/ontology/views.py              | 24 ++++++++++++++++++-
 .../static/scipost/assets/css/_navbar.scss    | 15 ++++++++++++
 .../scipost/_index_publications.html          |  4 ++++
 .../templates/scipost/_index_submissions.html |  4 ++++
 .../scipost/templates/scipost/header.html     | 12 ++++++++++
 .../scipost/templates/scipost/index.html      |  4 ++--
 scipost_django/scipost/views.py               | 19 ++++++++++++---
 12 files changed, 119 insertions(+), 11 deletions(-)
 create mode 100644 scipost_django/ontology/templates/ontology/session_acad_field_form.html

diff --git a/scipost_django/SciPost_v1/settings/base.py b/scipost_django/SciPost_v1/settings/base.py
index f9a0c84dd..01174ec23 100644
--- a/scipost_django/SciPost_v1/settings/base.py
+++ b/scipost_django/SciPost_v1/settings/base.py
@@ -278,6 +278,7 @@ TEMPLATES = [
                 'django.contrib.auth.context_processors.auth',
                 'django.contrib.messages.context_processors.messages',
                 'journals.context_processors.journals_processor',
+                'ontology.context_processors.ontology_processor',
             ],
         },
     },
diff --git a/scipost_django/ontology/context_processors.py b/scipost_django/ontology/context_processors.py
index 99a1a6dfb..bf92c16b2 100644
--- a/scipost_django/ontology/context_processors.py
+++ b/scipost_django/ontology/context_processors.py
@@ -1,7 +1,9 @@
 __copyright__ = "Copyright 2016-2018, Stichting SciPost (SciPost Foundation)"
 __license__ = "AGPL v3"
 
+
 from .models import Branch, AcademicField, Specialty
+from .forms import SessionAcademicFieldForm
 
 
 def ontology_processor(request):
@@ -13,10 +15,13 @@ def ontology_processor(request):
         'branches': Branch.objects.all(),
         'acad_fields': AcademicField.objects.all(),
     }
-    if request.session.get('acad_field_slug', None):
+    initial = {}
+    if request.session.get('session_acad_field_slug', None):
         context['session_acad_field'] = AcademicField.objects.get(
-            slug=request.session.get('acad_field_slug'))
-    if request.session.get('specialty_slug', None):
+            slug=request.session.get('session_acad_field_slug'))
+        initial['acad_field'] = context['session_acad_field']
+    if request.session.get('session_specialty_slug', None):
         context['session_specialty'] = Specialty.objects.get(
-            slug=request.session.get('specialty_slug'))
+            slug=request.session.get('session_specialty_slug'))
+    context['session_acad_field_form'] = SessionAcademicFieldForm(initial=initial)
     return context
diff --git a/scipost_django/ontology/forms.py b/scipost_django/ontology/forms.py
index 55d690ff5..37a69732d 100644
--- a/scipost_django/ontology/forms.py
+++ b/scipost_django/ontology/forms.py
@@ -4,10 +4,29 @@ __license__ = "AGPL v3"
 
 from django import forms
 
+from crispy_forms.helper import FormHelper
+from crispy_forms.layout import Layout, Div
+from crispy_bootstrap5.bootstrap5 import FloatingField
 from dal import autocomplete
 
 from .constants import TOPIC_RELATIONS_ASYM
-from .models import Tag, Topic
+from .models import AcademicField, Tag, Topic
+
+
+class SessionAcademicFieldForm(forms.Form):
+    acad_field = forms.ModelChoiceField(
+        queryset=AcademicField.objects.all(),
+        label='Academic Field'
+    )
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.helper = FormHelper(self)
+        self.helper.disable_csrf = True
+        self.helper.show_errors = True
+        self.helper.layout = Layout(
+            Div(FloatingField('acad_field'))
+        )
 
 
 class SelectTagsForm(forms.Form):
diff --git a/scipost_django/ontology/templates/ontology/session_acad_field_form.html b/scipost_django/ontology/templates/ontology/session_acad_field_form.html
new file mode 100644
index 000000000..edd146ff6
--- /dev/null
+++ b/scipost_django/ontology/templates/ontology/session_acad_field_form.html
@@ -0,0 +1,8 @@
+{% load crispy_forms_tags %}
+<form id="session_acad_field_form"
+      hx-get="{% url 'ontology:set_session_acad_field' %}"
+      hx-trigger="change"
+      hx-swap="outerHTML"
+>
+  {% crispy session_acad_field_form %}
+</form>
diff --git a/scipost_django/ontology/urls.py b/scipost_django/ontology/urls.py
index f9b9bef54..1f504a004 100644
--- a/scipost_django/ontology/urls.py
+++ b/scipost_django/ontology/urls.py
@@ -34,6 +34,11 @@ urlpatterns = [
         views.TopicLinkedAutocompleteView.as_view(),
         name='topic-linked-autocomplete',
     ),
+    path(
+        'set_session_acad_field',
+        views.set_session_acad_field,
+        name='set_session_acad_field'
+    ),
     path(
         '',
         views.ontology,
diff --git a/scipost_django/ontology/views.py b/scipost_django/ontology/views.py
index 24924b82d..1cb8e698b 100644
--- a/scipost_django/ontology/views.py
+++ b/scipost_django/ontology/views.py
@@ -3,6 +3,7 @@ __license__ = "AGPL v3"
 
 
 from django.contrib import messages
+from django.http import HttpResponse
 from django.urls import reverse, reverse_lazy
 from django.db.models import Q
 from django.shortcuts import get_object_or_404, redirect, render
@@ -15,12 +16,33 @@ from dal import autocomplete
 from guardian.decorators import permission_required
 
 from .models import AcademicField, Specialty, Tag, Topic, RelationAsym
-from .forms import SelectTagsForm, SelectLinkedTopicForm, AddRelationAsymForm
+from .forms import (
+    SessionAcademicFieldForm,
+    SelectTagsForm, SelectLinkedTopicForm,
+    AddRelationAsymForm
+)
 
 from scipost.forms import SearchTextForm
 from scipost.mixins import PaginationMixin, PermissionsMixin
 
 
+def set_session_acad_field(request):
+    """Set the Academic Field to be viewed in the current user session."""
+    form = SessionAcademicFieldForm(request.GET or None)
+    if form.is_valid():
+        request.session['session_acad_field_slug'] = form.cleaned_data['acad_field'].slug
+    form = SessionAcademicFieldForm(initial={
+        'acad_field': AcademicField.objects.get(slug=request.session['session_acad_field_slug'])
+    })
+    response = render(
+        request,
+        'ontology/session_acad_field_form.html',
+        context={ 'session_acad_field_form': form}
+    )
+    response['HX-Trigger'] = 'session-acad-field-set'
+    return response
+
+
 def ontology(request):
     context = {
         'select_linked_topic_form': SelectLinkedTopicForm(),
diff --git a/scipost_django/scipost/static/scipost/assets/css/_navbar.scss b/scipost_django/scipost/static/scipost/assets/css/_navbar.scss
index d1973870c..199a79f4f 100644
--- a/scipost_django/scipost/static/scipost/assets/css/_navbar.scss
+++ b/scipost_django/scipost/static/scipost/assets/css/_navbar.scss
@@ -284,3 +284,18 @@ header .nav-item {
         }
     }
 }
+
+#session_acad_field_form {
+
+    div #div_id_acad_field {
+	margin: 0rem !important;
+
+	#id_acad_field {
+	    border: 2px solid $scipost-lightblue;
+	    border-radius: 2px;
+	    background-color: $scipost-darkblue;
+	    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
+	    color: $white;
+	}
+    }
+}
diff --git a/scipost_django/scipost/templates/scipost/_index_publications.html b/scipost_django/scipost/templates/scipost/_index_publications.html
index 4e65e24c2..6d297de0d 100644
--- a/scipost_django/scipost/templates/scipost/_index_publications.html
+++ b/scipost_django/scipost/templates/scipost/_index_publications.html
@@ -3,5 +3,9 @@
     <li class="list-group-item py-2">
       {% include 'journals/_publication_li_content.html' with publication=publication %}
     </li>
+  {% empty %}
+    <li class="list-group-item py-2">
+      No publications yet
+    </li>
   {% endfor %}
 </ul>
diff --git a/scipost_django/scipost/templates/scipost/_index_submissions.html b/scipost_django/scipost/templates/scipost/_index_submissions.html
index 3bd5f7aee..3462e01cf 100644
--- a/scipost_django/scipost/templates/scipost/_index_submissions.html
+++ b/scipost_django/scipost/templates/scipost/_index_submissions.html
@@ -3,5 +3,9 @@
     <li class="list-group-item py-2">
       {% include 'submissions/_submission_card_content_homepage.html' with submission=submission %}
     </li>
+  {% empty %}
+    <li class="list-group-item py-2">
+      No submissions yet
+    </li>
   {% endfor %}
 </ul>
diff --git a/scipost_django/scipost/templates/scipost/header.html b/scipost_django/scipost/templates/scipost/header.html
index 9f27397d0..211846490 100644
--- a/scipost_django/scipost/templates/scipost/header.html
+++ b/scipost_django/scipost/templates/scipost/header.html
@@ -1,4 +1,5 @@
 {% load static %}
+{% load crispy_forms_tags %}
 
 <header>
   <div class="container">
@@ -7,6 +8,17 @@
         <a href="{% url 'scipost:index' %}"><img src="{% static 'scipost/images/logo_scipost_RGB_HTML_groot.png' %}" alt="SciPost logo" width="180" /></a>
       </div>
 
+      <ul class="navbar-nav">
+	<li class="nav-item">
+	  <form id="session_acad_field_form"
+		hx-get="{% url 'ontology:set_session_acad_field' %}"
+		hx-trigger="change"
+		hx-swap="outerHTML"
+	  >
+	    {% crispy session_acad_field_form %}
+	  </form>
+	</li>
+      </ul>
       <ul class="navbar-nav">
         <li class="nav-item">
           <a class="nav-link" id="header-search-button" href="{% url 'scipost:search' %}">
diff --git a/scipost_django/scipost/templates/scipost/index.html b/scipost_django/scipost/templates/scipost/index.html
index 61f159517..012ab3db9 100644
--- a/scipost_django/scipost/templates/scipost/index.html
+++ b/scipost_django/scipost/templates/scipost/index.html
@@ -34,7 +34,7 @@
           <hr class="sm mb-0 mt-2">
         </div>
 	<div hx-get="{% url 'scipost:_index_publications' %}"
-	     hx-trigger="load"
+	     hx-trigger="load, session-acad-field-set from:body"
 	>
 	</div>
         <p class="mb-3 px-3"><a href="{% url 'journals:publications' %}">View all Publications</a></p>
@@ -49,7 +49,7 @@
           <hr class="sm mb-0 mt-2">
         </div>
 	<div hx-get="{% url 'scipost:_index_submissions' %}"
-	     hx-trigger="load"
+	     hx-trigger="load, session-acad-field-set from:body"
 	>
 	</div>
         <p class="mb-3 px-3"><a href="{% url 'submissions:submissions' %}">View all Submissions</a></p>
diff --git a/scipost_django/scipost/views.py b/scipost_django/scipost/views.py
index a0479e0a9..5e7c9f8c0 100644
--- a/scipost_django/scipost/views.py
+++ b/scipost_django/scipost/views.py
@@ -171,16 +171,23 @@ def index(request):
 
 
 def _index_submissions(request):
+    submissions = Submission.objects.public()
+    session_acad_field_slug = request.session.get('session_acad_field_slug', None)
+    if session_acad_field_slug and session_acad_field_slug != 'multidisciplinary':
+        submissions = submissions.filter(acad_field__slug=session_acad_field_slug)
     context = {
-        'submissions': Submission.objects.public().order_by('-submission_date')[:3],
+        'submissions': submissions.order_by('-submission_date')[:3],
     }
     return render(request, 'scipost/_index_submissions.html', context)
 
 
 def _index_publications(request):
+    publications = Publication.objects.published()
+    session_acad_field_slug = request.session.get('session_acad_field_slug', None)
+    if session_acad_field_slug and session_acad_field_slug != 'multidisciplinary':
+        publications = publications.filter(acad_field__slug=session_acad_field_slug)
     context = {
-        'publications': Publication.objects.published().order_by('-publication_date',
-                                                                 '-paper_nr')[:3],
+        'publications': publications.order_by('-publication_date', '-paper_nr')[:3],
     }
     return render(request, 'scipost/_index_publications.html', context)
 
@@ -495,6 +502,12 @@ class SciPostLoginView(LoginView):
     def get_initial(self):
         return self.request.GET
 
+    def get_success_url(self):
+        """Add the `acad_field_view` item to session."""
+        self.request.session['session_acad_field_slug'] = \
+            self.request.user.contributor.profile.acad_field.slug
+        return super().get_success_url()
+
     def get_redirect_url(self):
         """Redirect to the requested url if safe, otherwise to personal page or org dashboard."""
         redirect_to = self.request.POST.get(
-- 
GitLab