From f7719a3a9ec113be7aaa5b12c08bfafd4ebb8443 Mon Sep 17 00:00:00 2001 From: Joseph Muller Date: Mon, 28 Oct 2024 18:46:09 +0000 Subject: [PATCH 1/3] Default recommendation emails #74 --- install/settings.json | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/install/settings.json b/install/settings.json index b3a2ad8..dcb9ebb 100644 --- a/install/settings.json +++ b/install/settings.json @@ -148,5 +148,65 @@ "value": { "default": "

Note: We don't have data for the country selected, so we could not adjust the GNI per capita accordingly, but you can still sign up! Please contact us for a custom quote.

" } + }, + { + "group": { + "name": "plugin:consortial_billing" + }, + "setting": { + "description": "General email for recommending the OLH", + "is_translatable": true, + "name": "recommend_us_general_email", + "pretty_name": "Recommend Us General Email", + "type": "rich-text" + }, + "value": { + "default": "

Dear Librarian,

I am writing to ask if the library would be able to join the Open Library of Humanities please? I am very impressed with their excellent cause as a diamond open-access publisher. Many thanks.

" + } + }, + { + "group": { + "name": "plugin:consortial_billing" + }, + "setting": { + "description": "Author email for recommending the OLH", + "is_translatable": true, + "name": "recommend_us_author_email", + "pretty_name": "Recommend Us Author Email", + "type": "rich-text" + }, + "value": { + "default": "

Dear Librarian,

I am writing to ask if the library would be able to join the Open Library of Humanities please? I recently published my paper ‘{{ article.title|safe }}’ in {{ article.journal.name }} with the Open Library of Humanities, and I was very impressed with their publication process and excellent cause as a diamond open-access publisher. Many thanks.

" + } + }, + { + "group": { + "name": "plugin:consortial_billing" + }, + "setting": { + "description": "Reader email for recommending the OLH", + "is_translatable": true, + "name": "recommend_us_reader_email", + "pretty_name": "Recommend Us Reader Email", + "type": "rich-text" + }, + "value": { + "default": "

Dear Librarian,

I am writing to ask if the library would be able to join the Open Library of Humanities please? I recently read ‘{{ article.title|safe }}’ in {{ article.journal.name }}, and I was very impressed with their publication process and excellent cause as a diamond open-access publisher. Many thanks.

" + } + }, + { + "group": { + "name": "plugin:consortial_billing" + }, + "setting": { + "description": "Editor email for recommending the OLH", + "is_translatable": true, + "name": "recommend_us_editor_email", + "pretty_name": "Recommend Us Editor Email", + "type": "rich-text" + }, + "value": { + "default": "

Dear Librarian,

I am writing to ask if the library would be able to join the Open Library of Humanities please? I am an editor for {{ journal.name }}, and I am in strong support of their excellent cause as a diamond open-access publisher. Many thanks.

" + } } ] From d22b7fe84f08ffdc17c2dd445efb12810caad928 Mon Sep 17 00:00:00 2001 From: Joseph Muller Date: Mon, 28 Oct 2024 18:51:58 +0000 Subject: [PATCH 2/3] Views and URLs for Recommend Us page #74 --- .../requires_hourglass.html | 12 ++ urls.py | 40 ++++ views.py | 176 ++++++++++++++++++ 3 files changed, 228 insertions(+) create mode 100644 templates/consortial_billing/requires_hourglass.html diff --git a/templates/consortial_billing/requires_hourglass.html b/templates/consortial_billing/requires_hourglass.html new file mode 100644 index 0000000..f1a6538 --- /dev/null +++ b/templates/consortial_billing/requires_hourglass.html @@ -0,0 +1,12 @@ +{% extends "core/base.html" %} + +{% load static %} + +{% block title %} + Requires Hourglass theme +{% endblock title %} + +{% block body %} +

Requires Hourglass theme

+

To use this page, you need the Hourglass theme installed.

+{% endblock body %} diff --git a/urls.py b/urls.py index 139d714..8f9989b 100755 --- a/urls.py +++ b/urls.py @@ -38,4 +38,44 @@ views.edit_supporter_band, name='edit_supporter_band', ), + re_path( + r'^recommend-us/$', + views.recommend_us, + name='recommend_us', + ), + re_path( + r'^recommend-us/see-matching-supporters/$', + views.recommend_us_see_matching_supporters, + name='recommend_us_see_matching_supporters', + ), + re_path( + r'^recommend-us/choose-role/$', + views.recommend_us_choose_role, + name='recommend_us_choose_role', + ), + re_path( + r'^recommend-us/search-article/$', + views.recommend_us_search_article, + name='recommend_us_search_article', + ), + re_path( + r'^recommend-us/search-journal/$', + views.recommend_us_search_journal, + name='recommend_us_search_journal', + ), + re_path( + r'^recommend-us/choose-article/$', + views.recommend_us_choose_article, + name='recommend_us_choose_article', + ), + re_path( + r'^recommend-us/choose-journal/$', + views.recommend_us_choose_journal, + name='recommend_us_choose_journal', + ), + re_path( + r'^recommend-us/generate-email/$', + views.recommend_us_generate_email, + name='recommend_us_generate_email', + ), ] diff --git a/views.py b/views.py index d916dff..4f7d1a2 100755 --- a/views.py +++ b/views.py @@ -6,7 +6,9 @@ from django.contrib.admin.views.decorators import staff_member_required from django.contrib import messages from django.db.models import OuterRef, Subquery +from django.views.decorators.http import require_POST from django.utils.decorators import method_decorator +from django.template import Template, RequestContext, Context from plugins.consortial_billing import utils, \ logic, models as supporter_models, plugin_settings, forms @@ -14,14 +16,31 @@ from core.views import GenericFacetedListView from core.models import Account +from journal.models import Journal from core.model_utils import search_model_admin from cms import models as cms_models +from core.models import SettingValue from utils.logger import get_logger +from utils.logic import get_current_request from security.decorators import base_check_required +from submission import models as submission_models + logger = get_logger(__name__) +def hourglass(template): + """ + A helper for accessing templates that only exist in Hourglass, + with a fallback template to explain this if needed. + """ + request = get_current_request() + if request.press.theme == 'hourglass': + return template + else: + return 'consortial_billing/requires_hourglass.html' + + @staff_member_required def manager(request): @@ -425,3 +444,160 @@ def edit_supporter_band(request, supporter_id=None): return render(request, template, context) +def recommend_us(request): + """ + A view for authors, editors, readers, and others + to generate an email for recommending us to their librarian. + Depends on the subsequent views via HTMX. + """ + template = hourglass('custom/recommend-us.html') + context = { + 'step': '1', + } + return render(request, template, context) + + +@require_POST +def recommend_us_see_matching_supporters(request): + query = request.POST.get('supporter_query', '') + if query: + supporters = supporter_models.Supporter.objects.filter(name__icontains=query) + else: + supporters = supporter_models.Supporter.objects.none() + template = hourglass('custom/recommend-us-see-matching-supporters.html') + context = { + 'supporters': supporters, + 'step': '2', + 'query': query, + } + return render(request, template, context) + + +@require_POST +def recommend_us_choose_role(request): + template = hourglass('custom/recommend-us-choose-role.html') + context = { + 'step': '3', + } + return render(request, template, context) + + +@require_POST +def recommend_us_search_article(request): + context = { + 'step': '4', + } + if 'author' in request.POST: + context['role'] = 'author' + elif 'reader' in request.POST: + context['role'] = 'reader' + template = hourglass('custom/recommend-us-search-article.html') + return render(request, template, context) + + +@require_POST +def recommend_us_search_journal(request): + context = { + 'role': 'editor', + 'step': '4', + } + template = hourglass('custom/recommend-us-search-journal.html') + return render(request, template, context) + + +@require_POST +def recommend_us_choose_article(request): + query = request.POST.get('article_query', '') + if query: + articles = request.press.published_articles.filter(title__icontains=query) + else: + articles = submission_models.Article.objects.none() + role = request.POST.get('role', '') + template = hourglass('custom/recommend-us-choose-article.html') + context = { + 'articles': articles, + 'step': '5', + 'role': role, + 'query': query, + } + return render(request, template, context) + + +@require_POST +def recommend_us_choose_journal(request): + query = request.POST.get('journal_query', '') + if query: + journal_names = SettingValue.objects.filter( + setting__name='journal_name', + value__icontains=query, + journal__in=request.press.public_journals, + ) + else: + journal_names = SettingValue.objects.none() + role = request.POST.get('role', '') + template = hourglass('custom/recommend-us-choose-journal.html') + context = { + 'journal_names': journal_names, + 'step': '5', + 'role': role, + 'query': query, + } + return render(request, template, context) + + +@require_POST +def recommend_us_generate_email(request): + role = request.POST.get('role', '') + step = '6' + setting_name = 'recommend_us_general_email' + + if role == 'author': + setting_name = 'recommend_us_author_email' + elif role == 'reader': + setting_name = 'recommend_us_reader_email' + elif role == 'editor': + setting_name = 'recommend_us_editor_email' + else: + # We assume this is "other" because no role input is available + # in the request data. + setting_name = 'recommend_us_general_email' + step = '4' + + # An author, reader, or editor could not find the article or journal so + # selects general + if 'general' in request.POST: + setting_name = 'recommend_us_general_email' + + template = Template(utils.setting(setting_name)) + setting_context = RequestContext(request) + + article_pk = request.POST.get('article_pk', '') + if article_pk: + setting_context.push( + { + 'article': get_object_or_404( + submission_models.Article, + pk=article_pk, + ) + } + ) + + journal_pk = request.POST.get('journal_pk', '') + if journal_pk: + setting_context.push( + { + 'journal': get_object_or_404( + Journal, + pk=journal_pk, + ) + } + ) + + email = template.render(setting_context) + context = { + 'email': email, + 'step': step, + } + + template = hourglass('custom/recommend-us-generate-email.html') + return render(request, template, context) From ff71046c02cfaa99320cb3cf124ae92423f28dc5 Mon Sep 17 00:00:00 2001 From: Joseph Muller Date: Wed, 30 Oct 2024 14:46:13 +0000 Subject: [PATCH 3/3] View changes for security, clarity, and better search #74 --- views.py | 51 ++++++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/views.py b/views.py index 4f7d1a2..826da5b 100755 --- a/views.py +++ b/views.py @@ -8,7 +8,7 @@ from django.db.models import OuterRef, Subquery from django.views.decorators.http import require_POST from django.utils.decorators import method_decorator -from django.template import Template, RequestContext, Context +from django.template import Template, RequestContext from plugins.consortial_billing import utils, \ logic, models as supporter_models, plugin_settings, forms @@ -29,7 +29,7 @@ logger = get_logger(__name__) -def hourglass(template): +def requires_hourglass(template): """ A helper for accessing templates that only exist in Hourglass, with a fallback template to explain this if needed. @@ -450,7 +450,7 @@ def recommend_us(request): to generate an email for recommending us to their librarian. Depends on the subsequent views via HTMX. """ - template = hourglass('custom/recommend-us.html') + template = requires_hourglass('custom/recommend-us.html') context = { 'step': '1', } @@ -464,7 +464,9 @@ def recommend_us_see_matching_supporters(request): supporters = supporter_models.Supporter.objects.filter(name__icontains=query) else: supporters = supporter_models.Supporter.objects.none() - template = hourglass('custom/recommend-us-see-matching-supporters.html') + template = requires_hourglass( + 'custom/recommend-us-see-matching-supporters.html' + ) context = { 'supporters': supporters, 'step': '2', @@ -475,7 +477,7 @@ def recommend_us_see_matching_supporters(request): @require_POST def recommend_us_choose_role(request): - template = hourglass('custom/recommend-us-choose-role.html') + template = requires_hourglass('custom/recommend-us-choose-role.html') context = { 'step': '3', } @@ -491,7 +493,7 @@ def recommend_us_search_article(request): context['role'] = 'author' elif 'reader' in request.POST: context['role'] = 'reader' - template = hourglass('custom/recommend-us-search-article.html') + template = requires_hourglass('custom/recommend-us-search-article.html') return render(request, template, context) @@ -501,7 +503,7 @@ def recommend_us_search_journal(request): 'role': 'editor', 'step': '4', } - template = hourglass('custom/recommend-us-search-journal.html') + template = requires_hourglass('custom/recommend-us-search-journal.html') return render(request, template, context) @@ -509,11 +511,12 @@ def recommend_us_search_journal(request): def recommend_us_choose_article(request): query = request.POST.get('article_query', '') if query: - articles = request.press.published_articles.filter(title__icontains=query) + search_filters = {"title": True} + articles = submission_models.Article.objects.search(query, search_filters) else: articles = submission_models.Article.objects.none() role = request.POST.get('role', '') - template = hourglass('custom/recommend-us-choose-article.html') + template = requires_hourglass('custom/recommend-us-choose-article.html') context = { 'articles': articles, 'step': '5', @@ -535,7 +538,7 @@ def recommend_us_choose_journal(request): else: journal_names = SettingValue.objects.none() role = request.POST.get('role', '') - template = hourglass('custom/recommend-us-choose-journal.html') + template = requires_hourglass('custom/recommend-us-choose-journal.html') context = { 'journal_names': journal_names, 'step': '5', @@ -573,25 +576,19 @@ def recommend_us_generate_email(request): article_pk = request.POST.get('article_pk', '') if article_pk: - setting_context.push( - { - 'article': get_object_or_404( - submission_models.Article, - pk=article_pk, - ) - } - ) + try: + article = request.press.published_articles.get(pk=article_pk) + setting_context['article'] = article + except submission_models.Article.DoesNotExist: + article = None journal_pk = request.POST.get('journal_pk', '') if journal_pk: - setting_context.push( - { - 'journal': get_object_or_404( - Journal, - pk=journal_pk, - ) - } - ) + try: + journal = request.press.public_journals.get(pk=journal_pk) + setting_context['journal'] = journal + except Journal.DoesNotExist: + journal = None email = template.render(setting_context) context = { @@ -599,5 +596,5 @@ def recommend_us_generate_email(request): 'step': step, } - template = hourglass('custom/recommend-us-generate-email.html') + template = requires_hourglass('custom/recommend-us-generate-email.html') return render(request, template, context)