From f77c8f9e0f407062e1d47a99ef0ef50d72843854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Caux?= <git@jscaux.org> Date: Sat, 12 Feb 2022 20:55:50 +0100 Subject: [PATCH] htmx-driven version of personal page --- scipost_django/SciPost_v1/settings/base.py | 1 + scipost_django/scipost/context_processors.py | 62 +++++ .../static/scipost/assets/css/_tablist.scss | 13 + .../static/scipost/assets/css/style.scss | 1 + .../scipost/personal_page/_hx_account.html | 219 +++++++++++++++++ .../scipost/personal_page/_hx_admin.html | 95 ++++++++ .../personal_page/_hx_author_replies.html | 25 ++ .../personal_page/_hx_commentaries.html | 35 +++ .../scipost/personal_page/_hx_comments.html | 25 ++ .../scipost/personal_page/_hx_edadmin.html | 125 ++++++++++ .../personal_page/_hx_publications.html | 41 ++++ .../scipost/personal_page/_hx_refereeing.html | 144 +++++++++++ .../personal_page/_hx_submissions.html | 62 +++++ .../scipost/personal_page/_hx_tablist.html | 71 ++++++ .../scipost/personal_page/_hx_theses.html | 34 +++ .../personal_page/personal_page_htmx.html | 34 +++ scipost_django/scipost/urls.py | 169 +++++++++++-- scipost_django/scipost/views.py | 228 ++++++++++++++++++ 18 files changed, 1367 insertions(+), 17 deletions(-) create mode 100644 scipost_django/scipost/context_processors.py create mode 100644 scipost_django/scipost/static/scipost/assets/css/_tablist.scss create mode 100644 scipost_django/scipost/templates/scipost/personal_page/_hx_account.html create mode 100644 scipost_django/scipost/templates/scipost/personal_page/_hx_admin.html create mode 100644 scipost_django/scipost/templates/scipost/personal_page/_hx_author_replies.html create mode 100644 scipost_django/scipost/templates/scipost/personal_page/_hx_commentaries.html create mode 100644 scipost_django/scipost/templates/scipost/personal_page/_hx_comments.html create mode 100644 scipost_django/scipost/templates/scipost/personal_page/_hx_edadmin.html create mode 100644 scipost_django/scipost/templates/scipost/personal_page/_hx_publications.html create mode 100644 scipost_django/scipost/templates/scipost/personal_page/_hx_refereeing.html create mode 100644 scipost_django/scipost/templates/scipost/personal_page/_hx_submissions.html create mode 100644 scipost_django/scipost/templates/scipost/personal_page/_hx_tablist.html create mode 100644 scipost_django/scipost/templates/scipost/personal_page/_hx_theses.html create mode 100644 scipost_django/scipost/templates/scipost/personal_page/personal_page_htmx.html diff --git a/scipost_django/SciPost_v1/settings/base.py b/scipost_django/SciPost_v1/settings/base.py index b84f985ca..310bd20ff 100644 --- a/scipost_django/SciPost_v1/settings/base.py +++ b/scipost_django/SciPost_v1/settings/base.py @@ -318,6 +318,7 @@ TEMPLATES = [ "django.template.context_processors.media", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", + "scipost.context_processors.roles_processor", "journals.context_processors.journals_processor", "ontology.context_processors.ontology_processor", ], diff --git a/scipost_django/scipost/context_processors.py b/scipost_django/scipost/context_processors.py new file mode 100644 index 000000000..cf6f2ed8d --- /dev/null +++ b/scipost_django/scipost/context_processors.py @@ -0,0 +1,62 @@ +__copyright__ = "Copyright 2016-2018, Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from django.contrib.auth.models import Group + + +def roles_processor(request): + """ + Add list of roles a User has to the context. + """ + context = { + "user_roles": [] + } + group_names = [g.name for g in Group.objects.filter(user__pk=request.user.id)] + # Groups-based roles + # if groups.filter(name="Registered Contributors").exists(): + # context["user_roles"].append("registered_contributor") + # if groups.filter(name="SciPost Administrators").exists(): + # context["user_roles"].append("scipost_admin") + # if groups.filter(name="Editorial Administrators").exists(): + # context["user_roles"].append("edadmin") + # if groups.filter(name="Financial Administrators").exists(): + # context["user_roles"].append("finadmin") + # if groups.filter(name="Advisory Board").exists(): + # context["user_roles"].append("advisory_board") + # if groups.filter(name="Vetting Editors").exists(): + # context["user_roles"].append("vetting_editor") + # if groups.filter(name="Ambassadors").exists(): + # context["user_roles"].append("ambassador") + # if groups.filter(name="Junior Ambassadors").exists(): + # context["user_roles"].append("junior_ambassador") + # if groups.filter(name="Production Officers").exists(): + # context["user_roles"].append("production_officer") + if "Registered Contributors" in group_names: + context["user_roles"].append("registered_contributor") + if "SciPost Administrators" in group_names: + context["user_roles"].append("scipost_admin") + if "Editorial Administrators" in group_names: + context["user_roles"].append("edadmin") + if "Financial Administrators" in group_names: + context["user_roles"].append("finadmin") + if "Advisory Board" in group_names: + context["user_roles"].append("advisory_board") + if "Vetting Editors" in group_names: + context["user_roles"].append("vetting_editor") + if "Ambassadors" in group_names: + context["user_roles"].append("ambassador") + if "Junior Ambassadors" in group_names: + context["user_roles"].append("junior_ambassador") + if "Production Officers" in group_names: + context["user_roles"].append("production_officer") + # Contributor-based roles + try: + active_fellowships = request.user.contributor.fellowships.active() + if active_fellowships.exists(): + context["user_roles"].append("active_fellow") + if active_fellowships.senior().exists(): + context["user_roles"].append("active_senior_fellow") + except AttributeError: + pass + return context diff --git a/scipost_django/scipost/static/scipost/assets/css/_tablist.scss b/scipost_django/scipost/static/scipost/assets/css/_tablist.scss new file mode 100644 index 000000000..a444fbae6 --- /dev/null +++ b/scipost_django/scipost/static/scipost/assets/css/_tablist.scss @@ -0,0 +1,13 @@ +.tablist { + border-bottom: 3px solid #eee; + margin-bottom: 1rem; +} +.tablist a { + display: inline-block; + padding: 0.5rem 1rem; + cursor: pointer; +} +.tablist a.selected { + background-color: #eee; + font-weight: bold; +} diff --git a/scipost_django/scipost/static/scipost/assets/css/style.scss b/scipost_django/scipost/static/scipost/assets/css/style.scss index 604b806a4..0d2964b21 100644 --- a/scipost_django/scipost/static/scipost/assets/css/style.scss +++ b/scipost_django/scipost/static/scipost/assets/css/style.scss @@ -54,6 +54,7 @@ @import "personal_page"; @import "reports"; @import "submissions"; +@import "tablist"; /** diff --git a/scipost_django/scipost/templates/scipost/personal_page/_hx_account.html b/scipost_django/scipost/templates/scipost/personal_page/_hx_account.html new file mode 100644 index 000000000..2d3eb1721 --- /dev/null +++ b/scipost_django/scipost/templates/scipost/personal_page/_hx_account.html @@ -0,0 +1,219 @@ +{% include 'scipost/personal_page/_hx_tablist.html' with selected='account' %} + + +{% load bootstrap %} +{% load user_groups %} + +{% recommend_new_totp_device request.user as recommend_totp %} + +<div class="row"> + <div class="col-12"> + <div class="card bg-light"> + <div class="card-body"> + <h2 class="card-title mb-0">Your Account</h2> + </div> + </div> + </div> +</div> + +<div class="row"> + <div class="col-md-6"> + <h3>Your personal details:</h3> + {% include "scipost/_private_info_as_table.html" with contributor=contributor %} + + {% if contributor %} + {# Scientist fields #} + <h3 class="mt-3">Your main academic field:</h3> + <ul><li>{{ contributor.profile.acad_field }}</li></ul> + + <h3 class="mt-3">Your specialties:</h3> + <ul> + {% for specialty in contributor.profile.specialties.all %} + <li>{{ specialty }}</li> + {% empty %} + <li>You haven't listed your specialties yet.</li> + {% endfor %} + </ul> + <p>You can add/remove specialties by <a href="{% url 'scipost:update_personal_data' %}">updating your personal data</a>.</p> + {% endif %} + </div> + + <div class="col-md-6"> + {% if contributor %} + {# Scientist fields #} + {% if not contributor.is_currently_available %} + <h3 class="text-warning">You are currently unavailable</h3> + <p>Check your availability underneath if this should not be the case.</p> + <hr> + {% endif %} + {# END: Scientist fields #} + {% endif %} + + {% if recommend_totp %} + <div class="border border-danger p-2 mb-3"> + <h3> + <span class="text-danger">{% include 'bi/exclamation-triangle-fill.html' %}</span> + Please increase your account's security</h3> + <div> + Your account grants access to sensitive, confidential information. + Therefore we strongly recommend to use two factor authentication, which adds + an extra layer of protection to your SciPost account. + <br><br> + <a href="{% url 'scipost:totp_create' %}">Set up two factor authentication here</a>. + </div> + </div> + {% endif %} + + <div class="border border-danger p-2"> + <h3 class="text-danger">Scientists, please help us out!</h3> + <p class="mb-1">If it is not listed on our + <a href="{% url 'sponsors:sponsors' %}" target="_blank">Sponsors page</a>, + please encourage your institution (through a librarian, director, ...) to join. + You can use this email <a href="mailto:?subject=Petition to support SciPost&body={% autoescape on %}{% include 'sponsors/sponsor_petition_email.html' %}{% endautoescape %}&cc=sponsors@{{ request.get_host }}">template</a>.</p> + </div> + <hr> + + {% if "scipost_admin" in user_roles %} + <h3>You are a SciPost Administrator.</h3> + {% endif %} + + {% if "edadmin" in user_roles %} + <h3>You are a SciPost Editorial Administrator.</h3> + {% endif %} + + {% if "advisory_board" in user_roles %} + <h3>You are a member of the Advisory Board.</h3> + {% endif %} + + {% if "vetting_editor" in user_roles %} + <h3>You are a SciPost Vetting Editor.</h3> + {% endif %} + + {% if "registered_contributor" in user_roles %} + <h3>You are a Registered Contributor.</h3> + {% endif %} + + {% if "tester" in user_roles %} + <h3>You are a SciPost Tester.</h3> + {% endif %} + + {% if "ambassador" in user_roles %} + <h3>You are a SciPost Ambassador.</h3> + {% endif %} + + {% if "junior_ambassador" in user_roles %} + <h3>You are a SciPost Junior Ambassador.</h3> + {% endif %} + + {% if "production_officer" in user_roles %} + <h3>You are a SciPost Production Officer.</h3> + {% endif %} + + {% if contributor.fellowships.all %} + <h3>Your Fellowships:</h3> + <ul class="mb-2"> + {% for fellowship in contributor.fellowships.all %} + <li class="pt-1"> + {{ fellowship.college }} + + {% if fellowship.guest %} + (Guest Fellowship) + <br> + Your Proceedings: + <ul> + {% for proc in fellowship.proceedings.all %} + <li>{{ proc }}</li> + {% empty %} + <li><em>No proceedings assigned yet.</em></li> + {% endfor %} + </ul> + {% elif fellowship.senior %} + (Senior Fellowship) + {% else %} + (Regular Fellowship) + {% endif %} + + {% if not fellowship.is_active %} + <span class="label label-outline-warning label-sm">Inactive</span> + {% endif %} + + {% if fellowship.start_date or fellowship.until_date %} + <div class="text-muted"> + {% if fellowship.start_date %} + from {{ fellowship.start_date }} + {% endif %} + {% if fellowship.until_date %} + until {{ fellowship.until_date }} + {% endif %} + </div> + {% endif %} + </li> + {% endfor %} + </ul> + <a href="{% url 'submissions:pool' %}" class="h3 text-primary ms-4 px-3 d-block-inline">Go to the Submissions Pool</a> + {% endif %} + + <h3 class="mt-3">Update your personal data or password</h3> + <ul> + <li><a href="{% url 'scipost:update_personal_data' %}">Update your personal data</a></li> + <li><a href="{% url 'scipost:password_change' %}">Change your password</a></li> + <li><a href="{% url 'scipost:totp' %}">Two factor authentication</a></li> + </ul> + </div> +</div> + +<div class="row"> + <div class="col-12"> + <h3>Your Affiliations:</h3> + <ul> + <li><a href="{% url 'profiles:affiliation_create' profile_id=contributor.profile.id %}">Add a new Affiliation</a></li> + </ul> + {% include 'profiles/_affiliations_table.html' with profile=contributor.profile actions=True %} + </div> +</div> + +{% if unavailability_form %} + <hr> + <div class="row"> + <div class="col"> + <h2 class="highlight">Your Availability</h2> + </div> + </div> + <div class="row justify-content-center"> + <div class="col-md-4 me-md-5"> + <p>To help with the editorial workflow, you can inform us of any periods during which you are unavailable. We will do our best to respect these.</p> + <h3 class="mb-3">Mark a period as unavailable:</h3> + <form action="{% url 'scipost:mark_unavailable_period' %}" method="post"> + {% csrf_token %} + {{ unavailability_form|bootstrap }} + <input class="btn btn-outline-secondary" type="submit" value="Submit" /> + </form> + </div> + <div class="col-md-4 ms-md-5"> + {% if unavailabilities %} + <h3>Your unavailability periods in our records</h3> + <p class="text-muted">(YYYY-MM-DD)</p> + <table class="table"> + <tr> + <th>Start</th> + <th colspan="2">End</th> + </tr> + {% for unav in unavailabilities %} + <tr> + <td>{{ unav.start }}</td> + <td>{{ unav.end }}</td> + <td> + <form action="{% url 'scipost:delete_unavailable_period' unav.id %}" method="post"> + {% csrf_token %} + <input class="btn btn-danger" type="submit" value="Delete" /> + </form> + </td> + </tr> + {% endfor %} + </table> + {% else %} + <p>You don't have any upcoming unavailability periods on record.</p> + {% endif %} + </div> + </div> +{% endif %} diff --git a/scipost_django/scipost/templates/scipost/personal_page/_hx_admin.html b/scipost_django/scipost/templates/scipost/personal_page/_hx_admin.html new file mode 100644 index 000000000..621e43872 --- /dev/null +++ b/scipost_django/scipost/templates/scipost/personal_page/_hx_admin.html @@ -0,0 +1,95 @@ +{% include 'scipost/personal_page/_hx_tablist.html' with selected='admin' %} + +<div class="row"> + <div class="col-12"> + <div class="card bg-light"> + <div class="card-body"> + <h2 class="card-title mb-0">Admin Actions</h2> + </div> + </div> + </div> +</div> + +<div class="row"> + {% if perms.scipost.can_vet_registration_requests or perms.scipost.can_create_registration_invitations or perms.scipost.can_resend_registration_requests or perms.scipost.can_manage_news %} + <div class="col-md-4"> + <h3>Registration actions</h3> + <ul> + {% if perms.scipost.can_vet_registration_requests %} + <li><a href="{% url 'scipost:vet_registration_requests' %}">Vet Registration requests</a> ({{ nr_reg_to_vet }})</li> + {% endif %} + {% if perms.scipost.can_resend_registration_requests %} + <li><a href="{% url 'scipost:registration_requests' %}">Awaiting validation</a> ({{ nr_reg_awaiting_validation }})</li> + {% endif %} + {% if perms.scipost.can_create_registration_invitations %} + <li><a href="{% url 'invitations:list' %}">Manage Registration Invitations</a></li> + {% endif %} + </ul> + + {% if perms.scipost.can_manage_news %} + <h3>News management</h3> + <ul> + <li><a href="{% url 'news:manage' %}">Manage News Items and Newsletters</a></li> + </ul> + {% endif %} + + {% if perms.scipost.can_manage_registration_invitations %} + <h3>Notifications</h3> + <ul> + <li><a href="{% url 'invitations:citation_notification_list' %}">Manage citation notifications</a></li> + </ul> + {% endif %} + + {% if "scipost_admin" in user_roles %} + <h3>Email communications</h3> + <ul> + {% if perms.scipost.can_email_group_members %} + <li><a href="{% url 'scipost:email_group_members' %}">Email Group Members</a></li> + {% endif %} + {% if perms.scipost.can_email_particulars %} + <li><a href="{% url 'scipost:send_precooked_email' %}">Send a precooked email</a></li> + <li><a href="{% url 'scipost:email_particular' %}">Email a particular individual/address</a></li> + {% endif %} + {% if perms.scipost.can_manage_mailchimp %} + <li><a href="{% url 'mailing_lists:overview' %}">Manage mailing lists</a></li> + {% endif %} + </ul> + {% endif %} + + </div> + {% endif %} + + <div class="col-md-4"> + {% if perms.scipost.can_view_profiles %} + <h3>Profiles</h3> + <ul> + <li><a href="{% url 'profiles:profiles' %}">List/Manage Profiles</a></li> + </ul> + {% endif %} + + <h3>Ontology</h3> + <ul> + <li><a href="{% url 'ontology:ontology' %}">View/Manage the Ontology</a></li> + </ul> + + {% if perms.scipost.can_manage_organizations %} + <h3>Organizations</h3> + <ul> + <li><a href="{% url 'organizations:organizations' %}">Manage Organizations</a></li> + </ul> + {% endif %} + </div> + + <div class="col-md-4"> + <h3>Finances</h3> + <ul> + {% if perms.scipost.can_manage_subsidies %} + <li><a href="{% url 'finances:subsidies' %}">Manage Subsidies</a></li> + {% endif %} + {% if perms.scipost.can_view_timesheets %} + <li><a href="{% url 'finances:timesheets' %}">Production Team Timesheets</a></li> + {% endif %} + </ul> + </div> + +</div> diff --git a/scipost_django/scipost/templates/scipost/personal_page/_hx_author_replies.html b/scipost_django/scipost/templates/scipost/personal_page/_hx_author_replies.html new file mode 100644 index 000000000..6e33291de --- /dev/null +++ b/scipost_django/scipost/templates/scipost/personal_page/_hx_author_replies.html @@ -0,0 +1,25 @@ +{% include 'scipost/personal_page/_hx_tablist.html' with selected='author_replies' %} + +<div class="row"> + <div class="col-12"> + <div class="card bg-light"> + <div class="card-body"> + <h2 class="card-title mb-0">Your Author Replies</h2> + </div> + </div> + </div> +</div> + +<div class="row" id="myauthorreplieslist"> + <div class="col-12"> + <ul class="list-group list-group-flush"> + {% for own_reply in own_authorreplies %} + <li class="list-group-item"> + {% include 'comments/_comment_card_extended_for_author.html' with comment=own_reply %} + </li> + {% empty %} + <li class="list-group-item"><em>You do not have Author Replies yet.</em></li> + {% endfor %} + </ul> + </div> +</div> diff --git a/scipost_django/scipost/templates/scipost/personal_page/_hx_commentaries.html b/scipost_django/scipost/templates/scipost/personal_page/_hx_commentaries.html new file mode 100644 index 000000000..73b20b63f --- /dev/null +++ b/scipost_django/scipost/templates/scipost/personal_page/_hx_commentaries.html @@ -0,0 +1,35 @@ +{% include 'scipost/personal_page/_hx_tablist.html' with selected='commentaries' %} + + +<div class="row"> + <div class="col-12"> + <div class="card bg-light"> + <div class="card-body"> + <h2 class="card-title">Commentaries</h2> + <ul class="mb-0"> + {% if nr_commentary_authorships_to_claim > 0 %} + <li><a href="{% url 'scipost:claim_authorships' %}">Potential authorships to claim (auto-detected: {{ nr_commentary_authorships_to_claim}})</a></li> + {% endif %} + <li><a href="{% url 'commentaries:request_commentary' %}">Request opening a SciPost Commentary Page</a></li> + </ul> + </div> + </div> + </div> +</div> + +<div class="row" id="mycommentarieslist"> + <div class="col-12"> + <h3>Commentaries for which you are identified as an author:</h3> + </div> + <div class="col-12"> + <ul class="list-group list-group-flush"> + {% for com in own_commentaries %} + <li class="list-group-item"> + {% include 'commentaries/_commentary_card_content.html' with commentary=com %} + </li> + {% empty %} + <li class="list-group-item"><em>No Commentaries found</em></li> + {% endfor %} + </ul> + </div> +</div> diff --git a/scipost_django/scipost/templates/scipost/personal_page/_hx_comments.html b/scipost_django/scipost/templates/scipost/personal_page/_hx_comments.html new file mode 100644 index 000000000..e4fb89a40 --- /dev/null +++ b/scipost_django/scipost/templates/scipost/personal_page/_hx_comments.html @@ -0,0 +1,25 @@ +{% include 'scipost/personal_page/_hx_tablist.html' with selected='comments' %} + +<div class="row"> + <div class="col-12"> + <div class="card bg-light"> + <div class="card-body"> + <h2 class="card-title mb-0">Your Comments</h2> + </div> + </div> + </div> +</div> + +<div class="row" id="mycommentslist"> + <div class="col-12"> + <ul class="list-group list-group-flush"> + {% for own_comment in own_comments %} + <li class="list-group-item"> + {% include 'comments/_comment_card_extended_for_author.html' with comment=own_comment %} + </li> + {% empty %} + <li class="list-group-item"><em>You have not commented yet.</em></li> + {% endfor %} + </ul> + </div> +</div> diff --git a/scipost_django/scipost/templates/scipost/personal_page/_hx_edadmin.html b/scipost_django/scipost/templates/scipost/personal_page/_hx_edadmin.html new file mode 100644 index 000000000..e26e61ba5 --- /dev/null +++ b/scipost_django/scipost/templates/scipost/personal_page/_hx_edadmin.html @@ -0,0 +1,125 @@ +{% include 'scipost/personal_page/_hx_tablist.html' with selected='edadmin' %} + + +<div class="row"> + <div class="col-12"> + <div class="card bg-light"> + <div class="card-body"> + <h2 class="card-title mb-0">Pending Editorial Actions</h2> + </div> + </div> + </div> +</div> + +<div class="row"> + + <div class="col-md-4"> + {% if perms.scipost.can_vet_comments or perms.scipost.can_vet_submitted_reports %} + <h3>Vetting actions</h3> + <ul> + {% if perms.scipost.can_vet_commentary_requests %} + <li><a href="{% url 'commentaries:vet_commentary_requests' %}">Vet Commentary Page requests</a> ({{ nr_commentary_page_requests_to_vet }})</li> + {% endif %} + {% if perms.scipost.can_vet_comments %} + <li><a href="{% url 'comments:vet_submitted_comments_list' %}">Vet submitted Comments</a> ({{ nr_comments_to_vet }})</li> + {% endif %} + {% if perms.scipost.can_vet_thesislink_requests %} + <li><a href="{% url 'theses:unvetted_thesislinks' %}">Vet Thesis Link Requests</a> ({{ nr_thesislink_requests_to_vet }})</li> + {% endif %} + {% if perms.scipost.can_vet_authorship_claims %} + <li><a href="{% url 'scipost:vet_authorship_claims' %}">Vet Authorship Claims</a> ({{ nr_authorship_claims_to_vet }})</li> + {% endif %} + {% if perms.scipost.can_vet_submitted_reports %} + <li><a href="{% url 'submissions:vet_submitted_reports_list' %}">Vet submitted Reports</a> ({{ nr_reports_to_vet }})</li> + {% endif %} + </ul> + {% endif %} + + {% if perms.scipost.can_oversee_refereeing %} + <h3>Editorial Admin actions</h3> + <ul> + <li><a href="{% url 'submissions:reports_accepted_list' %}">Accepted Reports</a>{% if nr_reports_without_pdf %} ({{nr_reports_without_pdf}} unfinished){% endif %}</li> + <li><a href="{% url 'submissions:pool' %}">Submissions Pool</a></li> + <li><a href="{% url 'submissions:treated_submissions_list' %}">Fully treated Submissions</a>{% if nr_treated_submissions_without_pdf %} ({{nr_treated_submissions_without_pdf}} unfinished){% endif %}</li> + <li><a href="{% url 'journals:harvest_citedby_list' %}">Harvest citedby data</a></li> + <li><a href="{% url 'journals:manage_comment_metadata' %}">Manage Comment metadata</a></li> + <li><a href="{% url 'journals:admin_volumes_list' %}">Manage Volumes</a></li> + <li><a href="{% url 'journals:admin_issue_list' %}">Manage Issues</a></li> + <li><a href="{% url 'proceedings:proceedings' %}">Manage Proceedings Issues</a></li> + <li><a href="{% url 'journals:manage_metadata' %}">Manage Publication metadata</a></li> + <li><a href="{% url 'journals:manage_report_metadata' %}">Manage Report metadata</a></li> + <li><a href="{% url 'journals:manage_update_metadata' %}">Manage PublicationUpdate metadata</a></li> + </ul> + {% endif %} + + </div> + + {% if perms.scipost.can_oversee_refereeing or request.user.contributor.is_active_fellow %} + <div class="col-md-4"> + <h3>Info</h3> + <ul> + <li><a href="{% url 'submissions:editorial_workflow' %}">How-to guide: summary of the editorial workflow</a></li> + <li><a href="{% url 'submissions:monitor' %}">Submissions monitor (current workflow timescales)</a></li> + </ul> + + <h3>Submissions assignments</h3> + <ul> + <li><a href="{% url 'submissions:assignments' %}">Your assignments</a></li> + <li><a href="{% url 'colleges:fellowships' %}">Assignments overview</a></li> + + {% if perms.scipost.can_assign_submissions %} + <li>Assign Submissions via the <a href="{% url 'submissions:pool' %}">Submissions Pool</a> ({{ nr_submissions_to_assign }})</li> + {% endif %} + {% if request.user.contributor.is_active_fellow %} + <li>Accept or decline assignments via the <a href="{% url 'submissions:pool' %}">Submissions Pool</a> ({{ nr_assignments_to_consider }})</li> + {% endif %} + </ul> + + {% if perms.scipost.can_oversee_refereeing %} + <h3>Refereeing overview</h3> + <ul> + <li>View (and act on) outstanding refereeing invitations in the <a href="{% url 'submissions:refereeing_overview' %}">refereeing overview</a></li> + <li><a href="{% url 'stats:statistics' %}">View statistics</a> for submissions, refereeing, publishing</li> + </ul> + <h3>Voting</h3> + <ul> + <li>Prepare Editorial Recommendations for voting via the <a href="{% url 'submissions:pool' %}">Submissions Pool</a> ({{ nr_recommendations_to_prepare_for_voting }})</li> + </ul> + {% endif %} + </div> + {% endif %} + + <div class="col-md-4"> + {% if perms.scipost.can_manage_college_composition or perms.scipost.can_view_potentialfellowship_list %} + <h3>Colleges and Fellowships</h3> + <ul> + <li><a href="{% url 'colleges:colleges' %}">Editorial Colleges</a></li> + {% if perms.scipost.can_manage_college_composition %} + <li><a href="{% url 'colleges:fellowships' %}">Fellowships</a></li> + {% endif %} + <li><a href="{% url 'colleges:potential_fellowships' %}">Potential Fellowships: view{% if perms.scipost.can_manage_college_composition %} and manage{% endif %}</a></li> + </ul> + {% endif %} + </div> +</div> + +{% if active_assignments %} + <div class="row"> + <div class="col-12"> + <h3 class="highlight">Submissions for which you are Editor-in-charge</h3> + </div> + <div class="col-12"> + <ul class="list-group list-group-flush"> + {% for assignment in active_assignments %} + <li class="list-group-item"> + <div class="card-body px-0"> + {% include 'submissions/_submission_card_content.html' with submission=assignment.submission %} + {% include 'submissions/_submission_status.html' with submission=assignment.submission %} + <p class="card-text mt-2">Manage this Submission from its <a href="{% url 'submissions:editorial_page' assignment.submission.preprint.identifier_w_vn_nr %}">Editorial Page</a>.</p> + </div> + </li> + {% endfor %} + </ul> + </div> + </div> +{% endif %} diff --git a/scipost_django/scipost/templates/scipost/personal_page/_hx_publications.html b/scipost_django/scipost/templates/scipost/personal_page/_hx_publications.html new file mode 100644 index 000000000..e3af784dd --- /dev/null +++ b/scipost_django/scipost/templates/scipost/personal_page/_hx_publications.html @@ -0,0 +1,41 @@ +{% include 'scipost/personal_page/_hx_tablist.html' with selected='publications' %} + + +<div class="row"> + <div class="col-12"> + <div class="card bg-light"> + <div class="card-body"> + <h2 class="card-title">Publications</h2> + <ul class="mb-0"> + </ul> + </div> + </div> + </div> +</div> + + +<div class="row" id="mypublicationslist"> + <div class="col-12"> + <h3 class="mb-3">Publications for which you are identified as an author:</h3> + </div> + <div class="col-12"> + <ul class="list-unstyled"> + {% for pub in own_publications %} + <li> + <div class="card bg-light card-publication" id="{{pub.doi_label}}"> + {% include 'journals/_publication_card_content.html' with publication=pub current_user=request.user %} + {% if request.user == pub.accepted_submission.submitted_by.user %} + {% if not pub.pubfractions_confirmed_by_authors or not pub.pubfractions_sum_to_1 %} + <h4 class="m-2"><a href="{% url 'journals:allocate_orgpubfractions' doi_label=pub.doi_label %}"><span class="text-danger">Intervention needed:</span> review support fractions</a></h4> + {% endif %} + {% endif %} + </div> + </li> + {% empty %} + <li> + <em>No Publications found</em> + </li> + {% endfor %} + </ul> + </div> +</div> diff --git a/scipost_django/scipost/templates/scipost/personal_page/_hx_refereeing.html b/scipost_django/scipost/templates/scipost/personal_page/_hx_refereeing.html new file mode 100644 index 000000000..5de492e1a --- /dev/null +++ b/scipost_django/scipost/templates/scipost/personal_page/_hx_refereeing.html @@ -0,0 +1,144 @@ +{% include 'scipost/personal_page/_hx_tablist.html' with selected='refereeing' %} + + +<div class="row"> + <div class="col-12"> + <div class="card bg-light"> + <div class="card-body"> + <h2 class="card-title">Refereeing Tasks</h2> + <ul class="mb-0"> + <li><a href="{% url 'submissions:accept_or_decline_ref_invitations' %}">Accept/decline refereeing invitations</a> ({{ contributor.referee_invitations.open.count }})</li> + </ul> + </div> + </div> + </div> +</div> + +{% if contributor.reports.in_draft.all %} + <div class="row"> + <div class="col-12"> + <h3 class="highlight">Unfinished reports:</h3> + <ul class="list-group list-group-flush"> + {% for report in contributor.reports.in_draft.all %} + <li class="list-group-item"> + <div class="card-body px-0"> + {% include 'submissions/_submission_li.html' with submission=report.submission %} + <a class="btn btn-outline-primary my-2" href="{% url 'submissions:submit_report' report.submission.preprint.identifier_w_vn_nr %}">Finish report</a> + </div> + </li> + {% endfor %} + </ul> + </div> + </div> +{% endif %} + + +<div class="row"> + <div class="col-12"> + <h3 class="highlight">Refereeing Invitations</h3> + {% if contributor.referee_invitations.all %} + <h3 class="mt-4">Pending Refereeing Invitations</h3> + {% if contributor.referee_invitations.in_process.all %} + <ul class="list-group list-group-flush"> + {% for invitation in contributor.referee_invitations.in_process.all %} + <li class="list-group-item py-2"> + {% include 'submissions/_submission_li.html' with submission=invitation.submission %} + <table> + <tr> + <th style='min-width: 100px;'>Due:</th> + <td>{{ invitation.submission.reporting_deadline|date:'d F Y' }}{% if invitation.submission.reporting_deadline_has_passed %} <span class="label label-sm label-danger ms-2 px-3">overdue</span> {% endif %}<td> + </tr> + <tr> + <th>Status:</th> + <td>{{ invitation.get_status_display }}</td> + </tr> + {% if invitation.accepted is not None %} + <tr> + <th>{{ invitation.accepted|yesno:'Accepted,Declined' }}:</th> + <td>{{ invitation.date_responded }}</td> + </tr> + {% endif %} + <tr> + <td colspan="2"> + <a class="d-inline-block" href="{% url 'submissions:submit_report' identifier_w_vn_nr=invitation.submission.preprint.identifier_w_vn_nr %}">Submit your Report</a> <span class="text-blue">|</span> + <a class="d-inline-block" href="{% url 'submissions:communication' identifier_w_vn_nr=invitation.submission.preprint.identifier_w_vn_nr comtype='RtoE' referee_id=request.user.contributor.id %}">Write to the Editor-in-charge</a> + </td> + </tr> + </table> + </li> + {% endfor %} + </ul> + {% else %} + <p><em>You do not have any pending refereeing task</em></p> + {% endif %} + + <br> + <h3><button type="button" class="btn btn-link p-0" data-bs-toggle="toggle" data-bs-target="#all-invitations"><small>+ See all Refereeing Invitations ({{ contributor.referee_invitations.all|length }})</small></button></h3> + <ul class="list-group list-group-flush ms-md-4" id="all-invitations" style="display: none;"> + {% for invitation in contributor.referee_invitations.all %} + <li class="list-group-item py-2"> + {% include 'submissions/_submission_li.html' with submission=invitation.submission %} + <table> + <tr> + <th style='min-width: 100px;'>Status:</th> + <td>{{ invitation.get_status_display }}</td> + </tr> + {% if invitation.accepted is not None %} + <tr> + <th>{{ invitation.accepted|yesno:'Accepted,Declined' }}:</th> + <td>{{ invitation.date_responded }}</td> + </tr> + {% endif %} + {% if invitation.related_report %} + <tr> + <th>Report:</th> + <td><a href="{{ invitation.related_report.get_absolute_url }}">{{ invitation.related_report.citation|default:'Link' }}</a></td> + </tr> + {% endif %} + </table> + </li> + {% endfor %} + </ul> + {% else %} + <p><em>You do not have any refereeing invitation</em></p> + {% endif %} + </div> +</div> + +{% if contributor.reports.non_draft.all %} + <div class="row"> + <div class="col-12"> + <h3 class="highlight">Finished reports</h3> + + <ul class="list-group list-group-flush"> + {% for report in contributor.reports.non_draft.all %} + <li class="list-group-item"> + {% comment %} + Temporary: There is already a template for a "Report summary" in a parallel (unmerged) branch. Awaiting merge to use that template. + {% endcomment %} + <div class="card-body px-0 {% block cardblock_class_block %}{% endblock %}"> + <h3>Report on Submission <a href="{{ report.submission.get_absolute_url }}">{{ report.submission.title }}</a></h3> + <table> + <tr> + <th style='min-width: 100px;'>Received:</th><td>{{ report.date_submitted|date:'Y-n-j' }}<td> + </tr> + <tr> + <th>Status:</th><td {% if report.status == 'vetted' %}class="text-success"{% elif report.status == 'unvetted' %}class="text-danger"{% endif %}>{{report.get_status_display}}</td> + </tr> + {% if report.doi_label %} + <tr> + <th>DOI:</th> + <td>{{ report.doi_string }}</td> + </tr> + {% endif %} + <tr> + <th>Anonymous:</th><td>{{report.anonymous|yesno:'Yes,No'}}</td>{% if report.anonymous %}<td>You can <a href="{% url 'journals:sign_existing_report' report_id=report.id %}">click here to sign this Report</a> (leads to confirmation page){% endif %}</td> + </tr> + </table> + </div> + </li> + {% endfor %} + </ul> + </div> + </div> +{% endif %} diff --git a/scipost_django/scipost/templates/scipost/personal_page/_hx_submissions.html b/scipost_django/scipost/templates/scipost/personal_page/_hx_submissions.html new file mode 100644 index 000000000..40351b2ff --- /dev/null +++ b/scipost_django/scipost/templates/scipost/personal_page/_hx_submissions.html @@ -0,0 +1,62 @@ +{% include 'scipost/personal_page/_hx_tablist.html' with selected='submissions' %} + + +<div class="row"> + <div class="col-12"> + <div class="card bg-light"> + <div class="card-body"> + <h2 class="card-title">Submissions</h2> + <ul class="mb-0"> + {% if nr_submission_authorships_to_claim > 0 %} + <li><a href="{% url 'scipost:claim_authorships' %}">Potential authorships to claim (auto-detected: {{ nr_submission_authorships_to_claim }})</a></li> + {% endif %} + <li><a href="{% url 'submissions:submit_manuscript' %}">Submit to a SciPost Journal</a></li> + </ul> + </div> + </div> + </div> +</div> + + +<div class="row" id="mysubmissionslist"> + <div class="col-12"> + <h3>Submissions for which you are identified as an author:</h3> + </div> + <div class="col-12"> + <ul class="list-group list-group-flush"> + {% for sub in own_submissions %} + <li class="list-group-item"> + <div class="card-body px-0"> + {% include 'submissions/_submission_card_content.html' with submission=sub %} + {% include 'submissions/_submission_status.html' with submission=sub %} + + {% if request.user.contributor == sub.submitted_by %} + <p class="card-text mt-1"> + <ul> + {% if sub.open_for_resubmission %} + <li><a href="{% url 'submissions:submit_choose_journal' acad_field=sub.acad_field.slug %}?thread_hash={{ sub.thread_hash }}">{% include 'bi/arrow-right.html' %} resubmit</a></li> + {% endif %} + {% if sub.under_consideration %} + {% if sub.editor_in_charge %} + <li><a href="{% url 'submissions:communication' sub.preprint.identifier_w_vn_nr 'AtoE' %}">Write to the Editor-in-charge</a></li> + {% endif %} + {% if sub.editorial_decision %} + {% if sub.editorial_decision.status == sub.editorial_decision.AWAITING_PUBOFFER_ACCEPTANCE %} + <li><a class="btn btn-primary my-1 px-1 py-0" href="{% url 'submissions:accept_puboffer' sub.preprint.identifier_w_vn_nr %}">Accept offer for publication in {{ sub.editorial_decision.for_journal }} (one-click action)</a></li> + {% endif %} + {% endif %} + <li><a href="{% url 'submissions:withdraw_manuscript' sub.preprint.identifier_w_vn_nr %}"><span class="text-danger">Withdraw</span> (leads to confirmation page)</a></li> + {% endif %} + </ul> + </p> + {% endif %} + </div> + </li> + {% empty %} + <li class="list-group-item"> + <em>No Submissions found</em> + </li> + {% endfor %} + </ul> + </div> +</div> diff --git a/scipost_django/scipost/templates/scipost/personal_page/_hx_tablist.html b/scipost_django/scipost/templates/scipost/personal_page/_hx_tablist.html new file mode 100644 index 000000000..64904378e --- /dev/null +++ b/scipost_django/scipost/templates/scipost/personal_page/_hx_tablist.html @@ -0,0 +1,71 @@ +<div class="tablist"> + <a hx-get="{% url 'scipost:personal_page_hx_account' %}" + {% if selected == 'account' %}class="selected"{% endif %} + > + Account + </a> + {% if "scipost_admin" in user_roles or "finadmin" in user_roles or perms.scipost.can_vet_registration_requests %} + <a hx-get="{% url 'scipost:personal_page_hx_admin' %}" + {% if selected == 'admin' %}class="selected"{% endif %} + > + Admin + </a> + {% endif %} + {% if "scipost_admin" in user_roles or "edadmin" in user_roles or "active_fellow" in user_roles or "advisory_board" in user_roles or "vetting_editor" in user_roles or "ambassador" in user_roles or "junior_ambassador" in user_roles %} + <a hx-get="{% url 'scipost:personal_page_hx_edadmin' %}" + {% if selected == 'edadmin' %}class="selected"{% endif %} + > + EdAdmin + </a> + {% endif %} + {% if perms.scipost.can_referee %} + <a hx-get="{% url 'scipost:personal_page_hx_refereeing' %}" + {% if selected == 'refereeing' %}class="selected"{% endif %} + > + Refereeing + </a> + {% endif %} + <a hx-get="{% url 'scipost:personal_page_hx_publications' %}" + {% if selected == 'publications' %}class="selected"{% endif %} + > + Publications + </a> + <a hx-get="{% url 'scipost:personal_page_hx_submissions' %}" + {% if selected == 'submissions' %}class="selected"{% endif %} + > + Submissions + </a> + <a hx-get="{% url 'scipost:personal_page_hx_commentaries' %}" + {% if selected == 'commentaries' %}class="selected"{% endif %} + > + Commentaries + </a> + <a hx-get="{% url 'scipost:personal_page_hx_theses' %}" + {% if selected == 'theses' %}class="selected"{% endif %} + > + Theses + </a> + {% with contributor.comments.regular_comments as regular_comments %} + {% if regular_comments %} + {% with regular_comments.awaiting_vetting.count as count %} + <a hx-get="{% url 'scipost:personal_page_hx_comments' %}" + {% if selected == 'comments' %}class="selected"{% endif %} + > + Comments{% if count %} ({{count}} unvetted){% endif %} + </a> + {% endwith %} + {% endif %} + {% endwith %} + {% with contributor.comments.author_replies as replies %} + {% if replies %} + {% with replies.awaiting_vetting.count as count %} + <a hx-get="{% url 'scipost:personal_page_hx_author_replies' %}" + {% if selected == 'author_replies' %}class="selected"{% endif %} + > + Author Replies{% if count %} ({{count}} unvetted){% endif %} + </a> + {% endwith %} + {% endif %} + {% endwith %} + +</div> diff --git a/scipost_django/scipost/templates/scipost/personal_page/_hx_theses.html b/scipost_django/scipost/templates/scipost/personal_page/_hx_theses.html new file mode 100644 index 000000000..8e5fb6586 --- /dev/null +++ b/scipost_django/scipost/templates/scipost/personal_page/_hx_theses.html @@ -0,0 +1,34 @@ +{% include 'scipost/personal_page/_hx_tablist.html' with selected='theses' %} + +<div class="row"> + <div class="col-12"> + <div class="card bg-light"> + <div class="card-body"> + <h2 class="card-title">Theses</h2> + <ul class="mb-0"> + {% if nr_thesis_authorships_to_claim > 0 %} + <li><a href="{% url 'scipost:claim_authorships' %}">Potential authorships to claim (auto-detected: {{ nr_thesis_authorships_to_claim}})</a></li> + {% endif %} + <li><a href="{% url 'theses:request_thesislink' %}">Request a SciPost ThesisLink</a></li> + </ul> + </div> + </div> + </div> +</div> + +<div class="row" id="mytheseslist"> + <div class="col-12"> + <h3>Theses for which you are identified as an author:</h3> + </div> + <div class="col-12"> + <ul class="list-group list-group-flush"> + {% for thesis in own_thesislinks %} + <li class="list-group-item"> + {% include 'theses/_thesislink_card_content.html' with thesislink=thesis %} + </li> + {% empty %} + <li class="list-group-item"><em>No Theses found</em></li> + {% endfor %} + </ul> + </div> +</div> diff --git a/scipost_django/scipost/templates/scipost/personal_page/personal_page_htmx.html b/scipost_django/scipost/templates/scipost/personal_page/personal_page_htmx.html new file mode 100644 index 000000000..a74383e2b --- /dev/null +++ b/scipost_django/scipost/templates/scipost/personal_page/personal_page_htmx.html @@ -0,0 +1,34 @@ +{% extends 'scipost/base.html' %} + +{% block pagetitle %}: personal page{% endblock pagetitle %} + +{% block navbar %} + {% include 'scipost/navbar.html' %} +{% endblock navbar %} + +{% block content %} + + <h1 class="highlight">Welcome to your SciPost Personal Page, {{ appellation }}</h1> + + {% if needs_validation %} + <div class="row"> + <div class="col-12"> + <hr> + <h3>Your credentials will soon be verified by an Editor.</h3> + <p>If accepted, you will become a registered Contributor, enabling you to submit, comment and vote.</p> + </div> + </div> + + {% else %} + + <div id="tablist" + hx-get="{% url 'scipost:personal_page_hx_account' %}" + hx-trigger="load after:100ms" + hx-target="this" + hx-swap="innerHTML" + > + </div> + + {% endif %} + +{% endblock content %} diff --git a/scipost_django/scipost/urls.py b/scipost_django/scipost/urls.py index ef7715836..419ff30db 100644 --- a/scipost_django/scipost/urls.py +++ b/scipost_django/scipost/urls.py @@ -39,12 +39,24 @@ app_name = "scipost" urlpatterns = [ + # + ####################### # redirect for favicon + ####################### path("favicon\.ico", favicon_view), + # + ############# # Utilities: + ############# + # + ########################### # Test Sentry installation + ########################### path("sentry-debug/", views.trigger_error, name="trigger_error"), + # + ############### # Autocomplete + ############### path( "group-autocomplete", views.GroupAutocompleteView.as_view(), @@ -55,20 +67,29 @@ urlpatterns = [ views.UserAutocompleteView.as_view(), name="user-autocomplete", ), + # + ######### # Search + ######### path( "search", TemplateView.as_view(template_name="search/search.html"), name="search", ), + # + ########### # Homepage + ########### path( "", #'index_pre202202', views.index_pre202202, name="index", # name='index_pre202202' ), path("portal", views.portal, name="portal"), - # HTMX-delivered fragments + # + #################################### + # HTMX-delivered homepage fragments + #################################### path("portal/_hx_home", views.portal_hx_home, name="portal_hx_home"), path("portal/_hx_journals", views.portal_hx_journals, name="portal_hx_journals"), path( @@ -110,8 +131,11 @@ urlpatterns = [ name="_hx_participates_in", ), path("_hx_sponsors", views._hx_sponsors, name="_hx_sponsors"), - path("files/secure/<path:path>", views.protected_serve, name="secure_file"), + # + #################### # General use pages + #################### + path("files/secure/<path:path>", views.protected_serve, name="secure_file"), path( "error", TemplateView.as_view(template_name="scipost/error.html"), name="error" ), @@ -120,7 +144,10 @@ urlpatterns = [ TemplateView.as_view(template_name="scipost/acknowledgement.html"), name="acknowledgement", ), + # + ####### # Info + ####### path( "about", TemplateView.as_view(template_name="scipost/about.html"), name="about" ), @@ -166,7 +193,10 @@ urlpatterns = [ TemplateView.as_view(template_name="scipost/privacy_policy.html"), name="privacy_policy", ), + # + ######## # Feeds + ######## path("feeds", views.feeds, name="feeds"), path("rss/news/", LatestNewsFeedRSS(), name="feeds_rss_news"), path("atom/news/", LatestNewsFeedAtom(), name="feeds_atom_news"), @@ -209,16 +239,23 @@ urlpatterns = [ LatestPublicationsFeedAtom(), name="pub_feed_spec_atom", ), + # ################ # Contributors: ################ + # + ################################# # Contributor info (public view) + ################################# path( "contributor/<int:contributor_id>", views.contributor_info, name="contributor_info", ), + # + ############### # Registration + ############### path("register", views.register, name="register"), path( "thanks_for_registering", @@ -260,9 +297,15 @@ urlpatterns = [ views.registration_requests_reset, name="registration_requests_reset", ), + # + ################################################################# # Registration invitations (Never change this route! Thank you.) + ################################################################# path("invitation/<str:key>", views.invitation, name="invitation"), + # + ################# # Authentication + ################# path("login/", views.SciPostLoginView.as_view(), name="login"), path("login/info/", views.raw_user_auth_info, name="login_info"), path("logout/", views.SciPostLogoutView.as_view(), name="logout"), @@ -291,9 +334,66 @@ urlpatterns = [ views.TOTPDeviceDeleteView.as_view(), name="totp_delete", ), + # + ############################################ # Single sign-on [for GitLab: see api/urls] + ############################################ path("sso_discourse", sso.discourse, name="sso_discourse"), + # + ################ # Personal Page + ################ + path("personal_page_htmx", views.personal_page_htmx, name="personal_page_htmx"), + path( + "personal_page_htmx/_hx_account", + views.personal_page_hx_account, + name="personal_page_hx_account", + ), + path( + "personal_page_htmx/_hx_admin", + views.personal_page_hx_admin, + name="personal_page_hx_admin", + ), + path( + "personal_page_htmx/_hx_edadmin", + views.personal_page_hx_edadmin, + name="personal_page_hx_edadmin", + ), + path( + "personal_page_htmx/_hx_refereeing", + views.personal_page_hx_refereeing, + name="personal_page_hx_refereeing", + ), + path( + "personal_page_htmx/_hx_publications", + views.personal_page_hx_publications, + name="personal_page_hx_publications", + ), + path( + "personal_page_htmx/_hx_submissions", + views.personal_page_hx_submissions, + name="personal_page_hx_submissions", + ), + path( + "personal_page_htmx/_hx_commentaries", + views.personal_page_hx_commentaries, + name="personal_page_hx_commentaries", + ), + path( + "personal_page_htmx/_hx_theses", + views.personal_page_hx_theses, + name="personal_page_hx_theses", + ), + path( + "personal_page_htmx/_hx_comments", + views.personal_page_hx_comments, + name="personal_page_hx_comments", + ), + path( + "personal_page_htmx/_hx_author_replies", + views.personal_page_hx_author_replies, + name="personal_page_hx_author_replies", + ), path("personal_page/", views.personal_page, name="personal_page"), path( "personal_page/account", @@ -355,7 +455,10 @@ urlpatterns = [ name="personal_page_author_replies", kwargs={"tab": "author_replies"}, ), + # + ################### # Unavailabilities + ################### path( "unavailable_period", views.mark_unavailable_period, @@ -366,7 +469,10 @@ urlpatterns = [ views.delete_unavailable_period, name="delete_unavailable_period", ), + # + #################### # Authorship claims + #################### path("claim_authorships", views.claim_authorships, name="claim_authorships"), path( "claim_sub_authorship/<int:submission_id>/<int:claim>", @@ -393,52 +499,70 @@ urlpatterns = [ views.vet_authorship_claim, name="vet_authorship_claim", ), + # + ####################### # Potential duplicates + ####################### path( "contributor_duplicates/", views.ContributorDuplicateListView.as_view(), name="contributor_duplicates", ), path("contributor_merge/", views.contributor_merge, name="contributor_merge"), - #################### - # Email facilities # - #################### + # + ################### + # Email facilities + ################### path("email_group_members", views.email_group_members, name="email_group_members"), path("email_particular", views.email_particular, name="email_particular"), path( "send_precooked_email", views.send_precooked_email, name="send_precooked_email" ), - ##################### - # Editorial College # - ##################### + # + #################### + # Editorial College + #################### path("EdCol_by-laws", views.EdCol_bylaws, name="EdCol_by-laws"), path( "EdCol_by-laws_Changes_2021_04", views.EdCol_bylaws_Changes_2021_04, name="EdCol_by-laws_Changes_2021_04", ), - ################ - # Publications # - ################ + # + ############### + # Publications + ############### + # + ########## # Reports + ########## path( "<report_doi_label:doi_label>", journals_views.report_detail, name="report_detail", ), + # + ########### # Comments + ########### path( "<comment_doi_label:doi_label>", journals_views.comment_detail, name="comment_detail", ), + # + ################# # Author Replies + ################# path( "<author_reply_doi_label:doi_label>", journals_views.author_reply_detail, name="author_reply_detail", ), + # + ############################ # Publication detail (+pdf) + ############################ re_path( "^10.21468/{pattern}$".format(pattern=DOI_DISPATCH_PATTERN), journals_views.doi_dispatch, @@ -469,7 +593,10 @@ urlpatterns = [ journals_views.publication_detail_pdf, name="publication_pdf", ), + # + ###################### # Publication updates + ###################### path( "<publication_doi_label:doi_label>-update-<int:update_nr>", journals_views.publication_update_detail, @@ -480,7 +607,10 @@ urlpatterns = [ journals_views.publication_update_detail, name="publication_update_detail", ), + # + ################ # Journal issue + ################ path( "10.21468/<issue_doi_label:doi_label>", journals_views.issue_detail, @@ -489,7 +619,10 @@ urlpatterns = [ path( "<issue_doi_label:doi_label>", journals_views.issue_detail, name="issue_detail" ), + # + ####################### # Journal landing page + ####################### path( "10.21468/<journal_doi_label:doi_label>", journals_views.landing_page, @@ -505,9 +638,10 @@ urlpatterns = [ journals_views.arxiv_doi_feed, name="arxiv_doi_feed", ), - ################ - # Howto guides # - ################ + # + ############### + # Howto guides + ############### path( "howto", TemplateView.as_view(template_name="scipost/howto.html"), name="howto" ), @@ -516,9 +650,10 @@ urlpatterns = [ TemplateView.as_view(template_name="scipost/howto_production.html"), name="howto_production", ), - ######################## - # Pwning verification # - ######################## + # + ###################### + # Pwning verification + ###################### path( "have-i-been-pwned-verification.txt", views.have_i_been_pwned, diff --git a/scipost_django/scipost/views.py b/scipost_django/scipost/views.py index 71ff52b39..6a9f82732 100644 --- a/scipost_django/scipost/views.py +++ b/scipost_django/scipost/views.py @@ -1192,6 +1192,234 @@ def _personal_page_author_replies(request): return render(request, "scipost/_personal_page_author_replies.html", context) +@is_contributor_user() +def personal_page_htmx(request): + context = { + "appellation": str(request.user), + "needs_validation": False, + } + try: + contributor = request.user.contributor + context["needs_validation"] = contributor.status != NORMAL_CONTRIBUTOR + except (Contributor.DoesNotExist, AttributeError): + if has_contact(request.user): + return redirect(reverse("organizations:dashboard")) + contributor = None + + if contributor: + context["appellation"] = ( + contributor.profile.get_title_display() + " " + contributor.user.last_name + ) + return render(request, "scipost/personal_page/personal_page_htmx.html", context) + + +@login_required +def personal_page_hx_account(request): + """Personal Page tab: Account.""" + contributor = request.user.contributor + context = { + "contributor": contributor, + "unavailability_form": UnavailabilityPeriodForm(), + "unavailabilities": contributor.unavailability_periods.future().order_by( + "start" + ), + } + return render(request, "scipost/personal_page/_hx_account.html", context) + + +@login_required +def personal_page_hx_admin(request): + """Personal Page tab: Admin Actions.""" + permission = ( + request.user.groups.filter( + name__in=["SciPost Administrators", "Financial Administrators"] + ).exists() + or request.user.is_superuser + ) + if not permission: + raise PermissionDenied + context = {} + contributor = request.user.contributor + if contributor.is_scipost_admin: + # count the number of pending registration requests + context["nr_reg_to_vet"] = Contributor.objects.awaiting_vetting().count() + context[ + "nr_reg_awaiting_validation" + ] = Contributor.objects.awaiting_validation().count() + return render(request, "scipost/personal_page/_hx_admin.html", context) + + +@login_required +def personal_page_hx_edadmin(request): + """ + Personal Page tab: Editorial Actions. + """ + permission = ( + request.user.groups.filter( + name__in=[ + "Ambassadors", + "Advisory Board", + "Editorial Administrators", + "Editorial College", + "Vetting Editors", + "Junior Ambassadors", + ] + ).exists() + or request.user.is_superuser + ) + permission = permission or request.user.contributor.is_active_fellow() + if not permission: + raise PermissionDenied + context = {} + contributor = request.user.contributor + if contributor.is_scipost_admin: + context["nr_submissions_to_assign"] = Submission.objects.prescreening().count() + context[ + "nr_recommendations_to_prepare_for_voting" + ] = EICRecommendation.objects.voting_in_preparation().count() + if contributor.is_vetting_editor: + context["nr_commentary_page_requests_to_vet"] = ( + Commentary.objects.awaiting_vetting() + .exclude(requested_by=contributor) + .count() + ) + context["nr_comments_to_vet"] = Comment.objects.awaiting_vetting().count() + context[ + "nr_thesislink_requests_to_vet" + ] = ThesisLink.objects.awaiting_vetting().count() + context[ + "nr_authorship_claims_to_vet" + ] = AuthorshipClaim.objects.awaiting_vetting().count() + if contributor.is_active_fellow: + context[ + "nr_assignments_to_consider" + ] = contributor.editorial_assignments.invited().count() + context["active_assignments"] = contributor.editorial_assignments.ongoing() + context["nr_reports_to_vet"] = ( + Report.objects.awaiting_vetting() + .filter(submission__editor_in_charge=contributor) + .count() + ) + if contributor.is_ed_admin: + context["nr_reports_without_pdf"] = ( + Report.objects.accepted().filter(pdf_report="").count() + ) + context["nr_treated_submissions_without_pdf"] = ( + Submission.objects.treated().public().filter(pdf_refereeing_pack="").count() + ) + return render(request, "scipost/personal_page/_hx_edadmin.html", context) + + +@login_required +def personal_page_hx_refereeing(request): + context = {"contributor": request.user.contributor} + return render(request, "scipost/personal_page/_hx_refereeing.html", context) + + +@login_required +def personal_page_hx_publications(request): + """ + Personal Page tab: Publications. + """ + contributor = request.user.contributor + context = { + "contributor": contributor, + "own_publications": contributor.profile.publications() + .published() + .order_by("-publication_date"), + } + return render(request, "scipost/personal_page/_hx_publications.html", context) + + +@login_required +def personal_page_hx_submissions(request): + """ + Personal Page tab: Submissions. + """ + contributor = request.user.contributor + context = {"contributor": contributor} + + context["nr_submission_authorships_to_claim"] = ( + Submission.objects.filter(author_list__contains=request.user.last_name) + .exclude(authors=contributor) + .exclude(authors_claims=contributor) + .exclude(authors_false_claims=contributor) + .count() + ) + context["own_submissions"] = contributor.submissions.filter( + is_current=True + ).order_by("-submission_date") + return render(request, "scipost/personal_page/_hx_submissions.html", context) + + +@login_required +def personal_page_hx_commentaries(request): + """ + Personal Page tab: Commentaries. + """ + contributor = request.user.contributor + context = {"contributor": contributor} + + context["nr_commentary_authorships_to_claim"] = ( + Commentary.objects.filter(author_list__contains=request.user.last_name) + .exclude(authors=contributor) + .exclude(authors_claims=contributor) + .exclude(authors_false_claims=contributor) + .count() + ) + context["own_submissions"] = contributor.commentaries.order_by("-latest_activity") + return render(request, "scipost/personal_page/_hx_commentaries.html", context) + + +@login_required +def personal_page_hx_theses(request): + """ + Personal Page tab: Theses. + """ + contributor = request.user.contributor + context = {"contributor": contributor} + + context["nr_thesis_authorships_to_claim"] = ( + ThesisLink.objects.filter(author__contains=request.user.last_name) + .exclude(author_as_cont=contributor) + .exclude(author_claims=contributor) + .exclude(author_false_claims=contributor) + .count() + ) + context["own_thesislinks"] = contributor.theses.all() + return render(request, "scipost/personal_page/_hx_theses.html", context) + + +@login_required +def personal_page_hx_comments(request): + """ + Personal Page tab: Comments. + """ + contributor = request.user.contributor + context = { + "contributor": contributor, + "own_comments": contributor.comments.regular_comments().order_by( + "-date_submitted" + ), + } + return render(request, "scipost/personal_page/_hx_comments.html", context) + + +@login_required +def personal_page_hx_author_replies(request): + """ + Personal Page tab: Author Replies. + """ + contributor = request.user.contributor + context = { + "contributor": contributor, + "own_authorreplies": contributor.comments.author_replies().order_by( + "-date_submitted" + ), + } + return render(request, "scipost/personal_page/_hx_author_replies.html", context) + + @login_required def personal_page(request, tab="account"): """ -- GitLab