diff --git a/src/core/admin.py b/src/core/admin.py index 82d3e5db31..ba2fc85bc5 100644 --- a/src/core/admin.py +++ b/src/core/admin.py @@ -80,6 +80,7 @@ class FileAdmin(admin.ModelAdmin): (models.Country, CountryAdmin), (models.WorkflowElement,), (models.HomepageElement, HomepageElementAdmin), + (models.LoginAttempt,), ] [admin.site.register(*t) for t in admin_list] diff --git a/src/core/example_settings.py b/src/core/example_settings.py index c33eaae62f..e752262cee 100644 --- a/src/core/example_settings.py +++ b/src/core/example_settings.py @@ -165,7 +165,7 @@ 'PASSWORD': '', 'HOST': 'localhost', 'PORT': '3306', - 'OPTIONS': {'init_command': 'SET storage_engine=INNODB'}, + 'OPTIONS': {'init_command': 'SET default_storage_engine=INNODB'}, } } @@ -310,6 +310,12 @@ def filter(self, record): EMAIL_HOST_PASSWORD = '' EMAIL_USE_TLS = True +# Settings for use with Mailgun +MAILGUN_ACCESS_KEY = '' +MAILGUN_SERVER_NAME = '' +MAILGUN_REQUIRE_TLS = False +ENABLE_ENHANCED_MAILGUN_FEATURES = False # Enables email tracking + DATE_FORMT = "Y-m-d" DATETIME_FORMAT = "Y-m-d H:i" diff --git a/src/core/logic.py b/src/core/logic.py index b5797b97ae..f5a50ef3cb 100644 --- a/src/core/logic.py +++ b/src/core/logic.py @@ -28,12 +28,17 @@ def send_reset_token(request, reset_token): context = {'reset_token': reset_token} + log_dict = {'level': 'Info', 'types': 'Reset Token', 'target': None} if not request.journal: message = render_template.get_message_content(request, context, request.press.password_reset_text, template_is_setting=True) + subject = 'Password Reset' else: message = render_template.get_message_content(request, context, 'password_reset') - notify_helpers.send_email_with_body_from_user(request, 'subject_password_reset', reset_token.account.email, message) + subject = 'subject_password_reset' + + notify_helpers.send_email_with_body_from_user(request, subject, reset_token.account.email, message, + log_dict=log_dict) def send_confirmation_link(request, new_user): @@ -41,11 +46,14 @@ def send_confirmation_link(request, new_user): if not request.journal: message = render_template.get_message_content(request, context, request.press.registration_text, template_is_setting=True) + subject = 'Registration Confirmation' else: message = render_template.get_message_content(request, context, 'new_user_registration') + subject = 'subject_new_user_registration' notify_helpers.send_slack(request, 'New registration: {0}'.format(new_user.full_name()), ['slack_admins']) - notify_helpers.send_email_with_body_from_user(request, 'subject_new_user_registration', new_user.email, message) + log_dict = {'level': 'Info', 'types': 'Account Confirmation', 'target': None} + notify_helpers.send_email_with_body_from_user(request, subject, new_user.email, message, log_dict=log_dict) def resize_and_crop(img_path, size, crop_type='middle'): diff --git a/src/core/urls.py b/src/core/urls.py index a2d3b7f2d1..2eb9579bc1 100644 --- a/src/core/urls.py +++ b/src/core/urls.py @@ -65,7 +65,7 @@ url(r'^logout/$', core_views.user_logout, name='core_logout'), url(r'^dashboard/$', core_views.dashboard, name='core_dashboard'), url(r'^dashboard/article/(?P\d+)/$', core_views.dashboard_article, name='core_dashboard_article'), - url(r'^cover/$', press_views.serve_press_cover, name='press_cover_download'), + url(r'^press/cover/$', press_views.serve_press_cover, name='press_cover_download'), # Notes url(r'^article/(?P\d+)/note/(?P\d+)/delete/$', core_views.delete_note, @@ -294,7 +294,7 @@ url(r'^(?P[-\w.]+)/dashboard/$', core_views.dashboard, name='core_dashboard'), url(r'^(?P[-\w.]+)/dashboard/article/(?P\d+)/$', core_views.dashboard_article, name='core_dashboard_article'), - url(r'^(?P[-\w.]+)/cover/$', press_views.serve_press_cover, name='press_cover_download'), + url(r'^(?P[-\w.]+)/press/cover/$', press_views.serve_press_cover, name='press_cover_download'), # Notes url(r'^(?P[-\w.]+)/article/(?P\d+)/note/(?P\d+)/delete/$', diff --git a/src/core/views.py b/src/core/views.py index fb88c841d7..5a991e3ee3 100644 --- a/src/core/views.py +++ b/src/core/views.py @@ -67,29 +67,27 @@ def user_login(request): user = authenticate(username=user, password=pawd) if user is not None: - if user.is_active: - login(request, user) - messages.info(request, 'Login successful.') - logic.clear_bad_login_attempts(request) - - orcid_token = request.POST.get('orcid_token', None) - if orcid_token: - try: - token_obj = models.OrcidToken.objects.get(token=orcid_token, expiry__gt=timezone.now()) - user.orcid = token_obj.orcid - user.save() - token_obj.delete() - except models.OrcidToken.DoesNotExist: - pass - - if request.GET.get('next'): - return redirect(request.GET.get('next')) - else: - return redirect(reverse('website_index')) + login(request, user) + messages.info(request, 'Login successful.') + logic.clear_bad_login_attempts(request) + + orcid_token = request.POST.get('orcid_token', None) + if orcid_token: + try: + token_obj = models.OrcidToken.objects.get(token=orcid_token, expiry__gt=timezone.now()) + user.orcid = token_obj.orcid + user.save() + token_obj.delete() + except models.OrcidToken.DoesNotExist: + pass + + if request.GET.get('next'): + return redirect(request.GET.get('next')) else: - messages.add_message(request, messages.ERROR, 'User account is not active.') + return redirect(reverse('website_index')) else: - messages.add_message(request, messages.ERROR, 'Account not found with those details.') + messages.add_message(request, messages.ERROR, 'Account not found or account not active. Please ensure' + 'you have activated your account.') util_models.LogEntry.add_entry(types='Authentication', description='Failed login attempt for user {0}'.format( request.POST.get('user_name')), diff --git a/src/journal/migrations/0006_auto_20171115_1216.py b/src/journal/migrations/0006_auto_20171115_1216.py new file mode 100644 index 0000000000..ede5693d43 --- /dev/null +++ b/src/journal/migrations/0006_auto_20171115_1216.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-11-15 12:16 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('journal', '0005_auto_20171002_1503'), + ] + + operations = [ + migrations.AlterField( + model_name='journal', + name='code', + field=models.CharField(max_length=10), + ), + migrations.AlterField( + model_name='journal', + name='domain', + field=models.CharField(default='www.example.com', max_length=255, unique=True), + ), + ] diff --git a/src/journal/models.py b/src/journal/models.py index af0c1ceb76..46db5daf8a 100644 --- a/src/journal/models.py +++ b/src/journal/models.py @@ -55,8 +55,8 @@ def issue_large_image_path(instance, filename): class Journal(models.Model): - code = models.CharField(max_length=4) - domain = models.CharField(max_length=255, default='localhost', unique=True) + code = models.CharField(max_length=10) + domain = models.CharField(max_length=255, default='www.example.com', unique=True) current_issue = models.ForeignKey('Issue', related_name='current_issue', null=True, blank=True) carousel = models.OneToOneField('carousel.Carousel', related_name='journal', null=True, blank=True) thumbnail_image = models.ForeignKey('core.File', null=True, blank=True, related_name='thumbnail_image', @@ -513,3 +513,9 @@ def create_sites_folder(sender, instance, created, **kwargs): if created: if not os.path.exists(path): os.makedirs(path) + + from submission.models import Section + Section.objects.language('en').get_or_create(journal=instance, + number_of_reviewers=2, + name='Article', + plural='Articles') diff --git a/src/journal/views.py b/src/journal/views.py index 42ff25a4db..3a2c72a13e 100644 --- a/src/journal/views.py +++ b/src/journal/views.py @@ -23,6 +23,7 @@ from django.utils.translation import ugettext_lazy as _ from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST +from django.core.management import call_command from cms import models as cms_models from core import files, models as core_models, plugin_loader @@ -1187,6 +1188,10 @@ def manage_article_log(request, article_id): content_type = ContentType.objects.get_for_model(article) log_entries = utils_models.LogEntry.objects.filter(content_type=content_type, object_id=article.pk) + if request.POST and settings.ENABLE_ENHANCED_MAILGUN_FEATURES: + call_command('check_mailgun_stat') + return redirect(reverse('manage_article_log', kwargs={'article_id': article.pk})) + template = 'journal/article_log.html' context = { 'article': article, diff --git a/src/preprint/forms.py b/src/preprint/forms.py index 9b19c50c76..37afd801f0 100644 --- a/src/preprint/forms.py +++ b/src/preprint/forms.py @@ -5,6 +5,7 @@ from submission import models as submission_models from preprint import models from press import models as press_models +from review.forms import render_choices class PreprintInfo(forms.ModelForm): @@ -22,6 +23,7 @@ class Meta: } def __init__(self, *args, **kwargs): + elements = kwargs.pop('additional_fields', None) super(PreprintInfo, self).__init__(*args, **kwargs) self.fields['license'].queryset = submission_models.Licence.objects.filter(press__isnull=False, @@ -34,6 +36,45 @@ def __init__(self, *args, **kwargs): if article: self.fields['subject'].initial = article.get_subject_area() + if elements: + for element in elements: + if element.kind == 'text': + self.fields[element.name] = forms.CharField( + widget=forms.TextInput(attrs={'div_class': element.width}), + required=element.required) + elif element.kind == 'textarea': + self.fields[element.name] = forms.CharField(widget=forms.Textarea, + required=element.required) + elif element.kind == 'date': + self.fields[element.name] = forms.CharField( + widget=forms.DateInput(attrs={'class': 'datepicker', 'div_class': element.width}), + required=element.required) + + elif element.kind == 'select': + choices = render_choices(element.choices) + self.fields[element.name] = forms.ChoiceField( + widget=forms.Select(attrs={'div_class': element.width}), choices=choices, + required=element.required) + + elif element.kind == 'email': + self.fields[element.name] = forms.EmailField( + widget=forms.TextInput(attrs={'div_class': element.width}), + required=element.required) + elif element.kind == 'check': + self.fields[element.name] = forms.BooleanField( + widget=forms.CheckboxInput(attrs={'is_checkbox': True}), + required=element.required) + + self.fields[element.name].help_text = element.help_text + self.fields[element.name].label = element.name + + if article: + try: + check_for_answer = submission_models.FieldAnswer.objects.get(field=element, article=article) + self.fields[element.name].initial = check_for_answer.answer + except submission_models.FieldAnswer.DoesNotExist: + pass + def save(self, commit=True, request=None): article = super(PreprintInfo, self).save() @@ -49,6 +90,22 @@ def save(self, commit=True, request=None): if self.cleaned_data.get('subject', None): article.set_preprint_subject(self.cleaned_data['subject']) + if request: + additional_fields = submission_models.Field.objects.filter(press=request.press) + + for field in additional_fields: + answer = request.POST.get(field.name, None) + print(answer) + if answer: + try: + field_answer = submission_models.FieldAnswer.objects.get(article=article, field=field) + field_answer.answer = answer + field_answer.save() + except submission_models.FieldAnswer.DoesNotExist: + field_answer = submission_models.FieldAnswer.objects.create(article=article, + field=field, + answer=answer) + return article diff --git a/src/preprint/logic.py b/src/preprint/logic.py index 4f85aa70f2..1991bbe640 100644 --- a/src/preprint/logic.py +++ b/src/preprint/logic.py @@ -281,4 +281,30 @@ def unpublish_preprint(request, preprint): preprint.preprint_decision_notification = False preprint.stage = submission_models.STAGE_PREPRINT_REVIEW preprint.save() - messages.add_message(request, messages.INFO, 'This preprint has been unpublished') \ No newline at end of file + messages.add_message(request, messages.INFO, 'This preprint has been unpublished') + + +def get_preprint_article_if_id(request, article_id): + if article_id: + article = get_object_or_404(submission_models.Article.preprints, + pk=article_id, + date_submitted__isnull=True) + else: + article = None + + return article + + +def save_preprint_submit_form(request, form, article, additional_fields): + article = form.save(request=request) + article.owner = request.user + article.is_preprint = True + article.current_step = 1 + article.authors.add(request.user) + article.correspondence_author = request.user + article.save() + + submission_models.ArticleAuthorOrder.objects.get_or_create(article=article, + author=request.user, + defaults={'order': article.next_author_sort()}) + return article \ No newline at end of file diff --git a/src/preprint/views.py b/src/preprint/views.py index 1df55ca3f4..bb4c2f6c85 100644 --- a/src/preprint/views.py +++ b/src/preprint/views.py @@ -242,37 +242,22 @@ def preprints_submit(request, article_id=None): :param request: HttpRequest :return: HttpResponse or HttpRedirect """ - if article_id: - article = get_object_or_404(submission_models.Article.preprints, - pk=article_id, - date_submitted__isnull=True) - else: - article = None - - form = forms.PreprintInfo(instance=article) + article = preprint_logic.get_preprint_article_if_id(request, article_id) + additional_fields = submission_models.Field.objects.filter(press=request.press) + form = forms.PreprintInfo(instance=article, additional_fields=additional_fields) if request.POST: - form = forms.PreprintInfo(request.POST, instance=article) + form = forms.PreprintInfo(request.POST, instance=article, additional_fields=additional_fields) if form.is_valid(): - article = form.save() - article.owner = request.user - article.is_preprint = True - article.current_step = 1 - article.authors.add(request.user) - article.correspondence_author = request.user - article.save() - - submission_models.ArticleAuthorOrder.objects.get_or_create(article=article, - author=request.user, - defaults={'order': article.next_author_sort()}) - + article = preprint_logic.save_preprint_submit_form(request, form, article, additional_fields) return redirect(reverse('preprints_authors', kwargs={'article_id': article.pk})) template = 'preprints/submit_start.html' context = { 'form': form, 'article': article, + 'additional_fields': additional_fields, } return render(request, template, context) @@ -546,7 +531,7 @@ def preprints_manager_article(request, article_id): if 'decline' in request.POST: preprint.decline_article() - return redirect(reverse('preprints_notifictation', kwargs={'article_id': preprint.pk})) + return redirect(reverse('preprints_notification', kwargs={'article_id': preprint.pk})) if 'upload' in request.POST: preprint_logic.handle_file_upload(request, preprint) diff --git a/src/press/templatetags/press_url.py b/src/press/templatetags/press_url.py index 9c14dc1d70..3863f1ec3f 100644 --- a/src/press/templatetags/press_url.py +++ b/src/press/templatetags/press_url.py @@ -2,9 +2,10 @@ from django import template from django.utils.safestring import mark_safe +from django.urls import reverse +from django.http import Http404 from press import models as press_models - register = template.Library() @@ -18,11 +19,11 @@ def svg(filename): path = filename if not path: - return None + raise Http404 mimetype = mimetypes.guess_type(path, strict=True) if not mimetype or mimetype[0] != 'image/svg+xml': - return None + return mark_safe(''.format(url=reverse('press_cover_download'))) if isinstance(path, (list, tuple)): path = path[0] @@ -31,4 +32,4 @@ def svg(filename): with open(path) as svg_file: return mark_safe(svg_file.read()) except FileNotFoundError: - return None + raise Http404 diff --git a/src/press/views.py b/src/press/views.py index 6fc4704666..485e64cd79 100644 --- a/src/press/views.py +++ b/src/press/views.py @@ -143,7 +143,7 @@ def serve_press_cover(request): """ p = press_models.Press.get_press(request) - response = files.serve_press_cover(request, p) + response = files.serve_press_cover(request, p.thumbnail_image) return response diff --git a/src/production/logic.py b/src/production/logic.py index ec28361d5e..a09cb23a55 100644 --- a/src/production/logic.py +++ b/src/production/logic.py @@ -89,6 +89,23 @@ def save_galley_image(galley, request, uploaded_file, label="Galley Image", fixe return new_file +def use_data_file_as_galley_image(galley, request, label): + file_id = request.POST.get('datafile') + + if file_id: + try: + file = core_models.File.objects.get(pk=file_id) + file.original_filename = request.POST.get('file_name') + file.save() + galley.images.add(file) + messages.add_message(request, messages.SUCCESS, 'File added.') + except core_models.File.DoesNotExist: + messages.add_message(request, messages.WARNING, 'No file with given ID found.') + + + + + def save_galley_css(galley, request, uploaded_file, filename, label="Galley Image"): new_file = files.save_file_to_article(uploaded_file, galley.article, request.user) new_file.is_galley = False @@ -215,7 +232,12 @@ def handle_delete_request(request, galley, typeset_task=None, article=None, page file_to_delete = core_models.File.objects.get(pk=file_id) if file_to_delete.pk in galley.article.all_galley_file_pks(): messages.add_message(request, messages.INFO, 'File deleted') - file_to_delete.delete() + + # Check if this is a data file, and if it is remove it, dont delete it. + if file_to_delete in galley.article.data_figure_files.all(): + galley.images.remove(file_to_delete) + else: + file_to_delete.delete() except core_models.File.DoesNotExist: messages.add_message(request, messages.WARNING, 'File not found') diff --git a/src/production/views.py b/src/production/views.py index 6715b478ec..59e9e397c8 100644 --- a/src/production/views.py +++ b/src/production/views.py @@ -446,6 +446,8 @@ def edit_galley(request, galley_id, typeset_id=None, article_id=None): label = request.POST.get('label') if 'fixed-image-upload' in request.POST: + if request.POST.get('datafile') != None: + logic.use_data_file_as_galley_image(galley, request, label) for uploaded_file in request.FILES.getlist('image'): logic.save_galley_image(galley, request, uploaded_file, label, fixed=True) if 'image-upload' in request.POST: @@ -474,7 +476,9 @@ def edit_galley(request, galley_id, typeset_id=None, article_id=None): 'galley': galley, 'article': galley.article, 'image_names': logic.get_image_names(galley), - 'return_url': return_url + 'return_url': return_url, + 'data_files': article.data_figure_files.all(), + 'galley_images': galley.images.all() } return render(request, template, context) diff --git a/src/review/models.py b/src/review/models.py index c5949da4c7..ef3f566fd0 100644 --- a/src/review/models.py +++ b/src/review/models.py @@ -37,7 +37,7 @@ def review_decision(): def review_type(): return ( ('traditional', 'Traditional'), - ('annotation', 'Annotation'), + #('annotation', 'Annotation'), ) @@ -82,8 +82,7 @@ class ReviewAssignment(models.Model): "have any competing interests please add them here. " "EG. 'This study was paid for by corp xyz.'.") review_type = models.CharField(max_length=20, choices=review_type(), default='traditional', - help_text='Traditional review uses a form set, annotation review ' - 'is freeform using hypothes.is') + help_text='Currently only traditional, form based, review is available.') visibility = models.CharField(max_length=20, choices=review_visibilty(), default='blind') form = models.ForeignKey('ReviewForm') access_code = models.CharField(max_length=100, blank=True, null=True) @@ -109,9 +108,9 @@ class ReviewAssignment(models.Model): def review_form_answers(self): return ReviewAssignmentAnswer.objects.filter(assignment=self).order_by('element__order') - def save_review_form(self, review_form): + def save_review_form(self, review_form, assignment): for k, v in review_form.cleaned_data.items(): - form_element = ReviewFormElement.objects.get(name=k) + form_element = ReviewFormElement.objects.get(reviewform=assignment.form, name=k) ReviewAssignmentAnswer.objects.create( assignment=self, element=form_element, diff --git a/src/review/views.py b/src/review/views.py index 9e2738220b..cd4119f961 100644 --- a/src/review/views.py +++ b/src/review/views.py @@ -591,7 +591,7 @@ def do_review(request, assignment_id): if form.is_valid() and decision_form.is_valid(): decision_form.save() - assignment.save_review_form(form) + assignment.save_review_form(form, assignment) assignment.date_complete = timezone.now() assignment.is_complete = True assignment.save() diff --git a/src/static/OLH/css/app.css b/src/static/OLH/css/app.css index a281fc8e57..9035fc475c 100644 --- a/src/static/OLH/css/app.css +++ b/src/static/OLH/css/app.css @@ -5215,3 +5215,6 @@ button.list-group-item-danger.active:focus { .subjectbutton { padding-top: 0 !important; padding-bottom: 0 !important; } + +.small-icon-text { + font-size: 17px; } diff --git a/src/static/admin/css/admin.css b/src/static/admin/css/admin.css index 3b92e154d8..8ef71fc3e7 100644 --- a/src/static/admin/css/admin.css +++ b/src/static/admin/css/admin.css @@ -366,4 +366,17 @@ th { .help-text { margin-bottom: 10px; +} + + +.green { + color: darkgreen; +} + +.red { + color: darkred; +} + +.amber { + color: darkorange; } \ No newline at end of file diff --git a/src/static/admin/js/resolution.js b/src/static/admin/js/resolution.js index a7f1c0696e..b7b3a4a818 100644 --- a/src/static/admin/js/resolution.js +++ b/src/static/admin/js/resolution.js @@ -1,3 +1,3 @@ function run_resolution() { - $('#run').html(' Report Running') + $('#run').html(' Refreshing') } \ No newline at end of file diff --git a/src/static/default/css/bootstrap.css b/src/static/default/css/bootstrap.css index 4040cf2ceb..cd7328dc24 100644 --- a/src/static/default/css/bootstrap.css +++ b/src/static/default/css/bootstrap.css @@ -9608,4 +9608,8 @@ footer svg { a.profilelink:link{ color: #FFFFFF; -} \ No newline at end of file +} + +.small-icon-text { + font-size: 17px !important; +} diff --git a/src/submission/forms.py b/src/submission/forms.py index 3ad4dc81f8..02984f4b2f 100644 --- a/src/submission/forms.py +++ b/src/submission/forms.py @@ -221,6 +221,7 @@ class Meta: model = models.Field exclude = ( 'journal', + 'press', ) diff --git a/src/submission/logic.py b/src/submission/logic.py index a37779f08e..ed1820eb55 100644 --- a/src/submission/logic.py +++ b/src/submission/logic.py @@ -7,6 +7,8 @@ from bs4 import BeautifulSoup from django.db.models import Q +from django.shortcuts import get_object_or_404 +from django.contrib import messages from core import files from core import models as core_models @@ -119,3 +121,85 @@ def import_from_jats_xml(path, journal): article.authors.add(author) return article + + +def get_current_field(request, field_id): + """ + Fetches a field based on whether there is a journal or press in the request object + :param request: HttpRequest + :param field_id: Field PK + :return: Field Object + """ + if field_id: + if request.journal: + field = get_object_or_404(models.Field, pk=field_id, journal=request.journal) + else: + field = get_object_or_404(models.Field, pk=field_id, press=request.press) + else: + field = None + + return field + + +def get_submission_fields(request): + """ + Gets a queryset of fields base on whether there is a journal or press object present in request + :param request: HttpRequest + :return: A queryset of Field objects + """ + + if request.journal: + fields = models.Field.objects.filter(journal=request.journal) + else: + fields = models.Field.objects.filter(press=request.press) + + return fields + + +def save_field(request, form): + """ + Saves a form field and sets the press or journal parameter. + :param request: + :param form: + :return: + """ + + new_field = form.save(commit=False) + + if request.journal: + new_field.journal = request.journal + else: + new_field.press = request.press + + new_field.save() + messages.add_message(request, messages.SUCCESS, 'Field saved.') + return new_field + + +def delete_field(request): + """ + Deletes a field object + :param request: HttpRequest + :return: None, adds a Message obejct to request + """ + + delete_id = request.POST.get('delete') + field_to_delete = get_current_field(request, delete_id) + field_to_delete.delete() + messages.add_message(request, messages.SUCCESS, 'Field deleted. Existing answers will remain intact.') + + +def order_fields(request, fields): + """ + Orders fields from a jquery sortable post. + :param request: HttpRequest + :param fields: Queryset of fields for this object + :return: None + """ + + ids = [int(_id) for _id in request.POST.getlist('order[]')] + + for field in fields: + order = ids.index(field.pk) + field.order = order + field.save() \ No newline at end of file diff --git a/src/submission/migrations/0017_auto_20171114_1502.py b/src/submission/migrations/0017_auto_20171114_1502.py new file mode 100644 index 0000000000..6b380e69e8 --- /dev/null +++ b/src/submission/migrations/0017_auto_20171114_1502.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-11-14 15:02 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('press', '0012_presssetting_is_boolean'), + ('submission', '0016_auto_20171106_0909'), + ] + + operations = [ + migrations.AddField( + model_name='field', + name='press', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='press.Press'), + ), + migrations.AlterField( + model_name='field', + name='journal', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='journal.Journal'), + ), + ] diff --git a/src/submission/models.py b/src/submission/models.py index 9d170186e9..939b76c8c8 100644 --- a/src/submission/models.py +++ b/src/submission/models.py @@ -1043,7 +1043,8 @@ def width_choices(): class Field(models.Model): - journal = models.ForeignKey('journal.Journal', default=1) + journal = models.ForeignKey('journal.Journal', blank=True, null=True) + press = models.ForeignKey('press.Press', blank=True, null=True) name = models.CharField(max_length=200) kind = models.CharField(max_length=50, choices=field_kind_choices()) width = models.CharField(max_length=50, choices=width_choices(), default='full') @@ -1059,6 +1060,13 @@ class Meta: def __str__(self): return "Field: {0} ({1})".format(self.name, self.kind) + @property + def object(self): + if not self.journal: + return self.press + + return self.journal + class FieldAnswer(models.Model): field = models.ForeignKey(Field, null=True, blank=True, on_delete=models.SET_NULL) diff --git a/src/submission/views.py b/src/submission/views.py index 1c3337209e..0e2ad9c551 100644 --- a/src/submission/views.py +++ b/src/submission/views.py @@ -498,13 +498,10 @@ def fields(request, field_id=None): :param field_id: Field object PK, optional :return: HttpResponse or HttpRedirect """ - if field_id: - field = get_object_or_404(models.Field, pk=field_id, journal=request.journal) - else: - field = None - fields = models.Field.objects.filter(journal=request.journal) + field = logic.get_current_field(request, field_id) + fields = logic.get_submission_fields(request) form = forms.FieldForm(instance=field) if request.POST: @@ -513,27 +510,15 @@ def fields(request, field_id=None): form = forms.FieldForm(request.POST, instance=field) if form.is_valid(): - new_field = form.save(commit=False) - new_field.journal = request.journal - new_field.save() - messages.add_message(request, messages.SUCCESS, 'Field saved.') + logic.save_field(request, form) return redirect(reverse('submission_fields')) elif 'delete' in request.POST: - delete_id = request.POST.get('delete') - field_to_delete = get_object_or_404(models.Field, pk=delete_id, journal=request.journal) - field_to_delete.delete() - messages.add_message(request, messages.SUCCESS, 'Field deleted. Existing answers will remain intact.') + logic.delete_field(request) return redirect(reverse('submission_fields')) elif 'order[]' in request.POST: - ids = [int(_id) for _id in request.POST.getlist('order[]')] - - for field in fields: - order = ids.index(field.pk) - field.order = order - field.save() - + logic.order_fields(request, fields) return HttpResponse('Thanks') template = 'admin/submission/manager/fields.html' diff --git a/src/templates/admin/elements/journal/log_description.html b/src/templates/admin/elements/journal/log_description.html index e80b29145a..eda9f20c13 100644 --- a/src/templates/admin/elements/journal/log_description.html +++ b/src/templates/admin/elements/journal/log_description.html @@ -9,6 +9,15 @@

 {{ entry.pk }} - {{ entry.types }}

+ {% if settings.ENABLE_ENHANCED_MAILGUN_FEATURES and entry.is_email %} +
+

Headers

+
+
+

To: {{ entry.to }}

+

Status: {{ entry.get_message_status_display }}

+
+ {% endif %}

Content

diff --git a/src/templates/admin/install/index.html b/src/templates/admin/install/index.html index 766e433327..c1025d6756 100644 --- a/src/templates/admin/install/index.html +++ b/src/templates/admin/install/index.html @@ -21,7 +21,7 @@

Press

- {% svg request.press_cover %} +
Move to Next Step diff --git a/src/templates/admin/install/next.html b/src/templates/admin/install/next.html index 35383c7d5b..ab4f1a7737 100644 --- a/src/templates/admin/install/next.html +++ b/src/templates/admin/install/next.html @@ -13,48 +13,54 @@

Next Steps

diff --git a/src/templates/admin/journal/article_log.html b/src/templates/admin/journal/article_log.html index cd3d2777dc..fe8d9509fb 100644 --- a/src/templates/admin/journal/article_log.html +++ b/src/templates/admin/journal/article_log.html @@ -1,4 +1,5 @@ {% extends "admin/core/base.html" %} +{% load static from staticfiles %} {% block title %}Article Log{% endblock %} {% block title-section %}Article Log{% endblock %} @@ -7,6 +8,7 @@

Log Entries

+ {% if settings.ENABLE_ENHANCED_MAILGUN_FEATURES %}
{% csrf_token %}
{% endif %}
@@ -16,17 +18,22 @@

Log Entries

+ {% if settings.ENABLE_ENHANCED_MAILGUN_FEATURES %}{% endif %} {% for entry in log_entries %} - - - - - + + + + + {% if settings.ENABLE_ENHANCED_MAILGUN_FEATURES %}{% endif %} + {% endfor %} @@ -64,5 +71,6 @@

Article Stage log

{% endblock %} {% block js %} -{% include "elements/datatables.html" with target="#log" sort=1 %} + + {% include "elements/datatables.html" with target="#log" sort=1 %} {% endblock %} \ No newline at end of file diff --git a/src/templates/admin/press/press_manager_index.html b/src/templates/admin/press/press_manager_index.html index e3418d1ad6..cc7ab6af85 100644 --- a/src/templates/admin/press/press_manager_index.html +++ b/src/templates/admin/press/press_manager_index.html @@ -28,6 +28,7 @@

Settings

{% if request.press.enable_preprints %} Preprint SettingsPreprint Licence Manager + Preprint Additional Fields Manager {% endif %} diff --git a/src/templates/admin/production/edit_galley.html b/src/templates/admin/production/edit_galley.html index 06507afd04..0e10886fb7 100644 --- a/src/templates/admin/production/edit_galley.html +++ b/src/templates/admin/production/edit_galley.html @@ -126,7 +126,7 @@

Image Files

- + {% csrf_token %} {% for image in galley.images.all %} {% can_view_file image as can_view_file_flag %} @@ -176,12 +176,21 @@
{{ element }}
+ {% if data_files %} +

Or, you can choose an existing figure file.

+ + {% endif %}
diff --git a/src/themes/OLH/assets/scss/app.scss b/src/themes/OLH/assets/scss/app.scss index 29f10a1f38..1d89c86eb4 100644 --- a/src/themes/OLH/assets/scss/app.scss +++ b/src/themes/OLH/assets/scss/app.scss @@ -1107,4 +1107,8 @@ button.list-group-item-danger.active:focus { .subjectbutton { padding-top: 0 !important; padding-bottom: 0 !important; +} + +.small-icon-text { + font-size: 17px; } \ No newline at end of file diff --git a/src/themes/OLH/templates/elements/journal/box_article.html b/src/themes/OLH/templates/elements/journal/box_article.html index 65904de074..81b34659c3 100644 --- a/src/themes/OLH/templates/elements/journal/box_article.html +++ b/src/themes/OLH/templates/elements/journal/box_article.html @@ -16,7 +16,7 @@ class="article-thumbnail"> {% endif %}
-

{{ article.title|safe }}

+

{{ article.title|safe }}{% if article.is_remote %} {% endif %}

{% include "elements/journal/authors_block.html" %}

{{ article.date_published|date:"Y-m-d" }} {{ issue.display_title }}

{% for category, articles in structure.items %} -

{{ category }}

- {% for article in articles %} -
-
- -
-
- {% if article.thumbnail_image_file %} - {{ article.title|striptags|escape }} - {% elif request.journal.thumbnail_image %} - - {% else %} - {{ article.title|striptags|escape }} {% endif %} -
-
-

{{ article.title|safe }}

- {% include "elements/journal/authors_block.html" %} -

{{ article.date_published|date:"Y-m-d" }} - {% trans "Volume" %} {{ article.issue.volume }}, - {% trans "Issue" %} {{ article.issue.issue }}

-
-
-
-
+ {% include "elements/journal/box_article.html" with article=article %} {% endfor %} {% endfor %}
diff --git a/src/themes/OLH/templates/journal/search.html b/src/themes/OLH/templates/journal/search.html index 64fb3ff040..44c4154a1c 100644 --- a/src/themes/OLH/templates/journal/search.html +++ b/src/themes/OLH/templates/journal/search.html @@ -15,35 +15,7 @@

{% trans "Articles" %}

{% for article in articles %} -
- -
-
- {% if article.thumbnail_image_file %} - {{ article.title|striptags|escape }} - {% elif request.journal.thumbnail_image %} - - {% else %} - {{ article.title|striptags|escape }} {% endif %} -
-
-

{{ article.title|safe }}

-

{% for author in article.authors.all %}{% if forloop.last %} - {% if article.authors.all|length > 1 %} and - {% endif %}{% endif %}{{ author.full_name }} - {% if not forloop.last %} - {% if not forloop.counter == article.authors.all|length|add:-1 %}, - {% endif %}{% endif %}{% endfor %}

-

{{ article.date_published|date:"Y-m-d" }} {% trans "Volume" %} {{ article.issue.volume }}, - {% trans "Issue" %} {{ article.issue.issue }}

-
-
-
+ {% include "elements/journal/box_article.html" with article=article %} {% endfor %}
diff --git a/src/themes/OLH/templates/preprints/submit_start.html b/src/themes/OLH/templates/preprints/submit_start.html index 1089c4ee46..f3747393f8 100644 --- a/src/themes/OLH/templates/preprints/submit_start.html +++ b/src/themes/OLH/templates/preprints/submit_start.html @@ -2,6 +2,7 @@ {% load static from staticfiles %} {% load i18n %} {% load foundation %} +{% load field %} {% block title %}{% trans "Submit a Preprint" %}{% endblock title %} @@ -72,7 +73,26 @@

{% trans "Submit a Preprint" %}

+
+ + + {% if additional_fields %} +
+

+

Additional Fields

+
+ {% for additional_field in additional_fields %} + {% get_form_field form additional_field.name as field %} +
+ {{ field|foundation }} +
+ {% endfor %} + {% endif %} + +
+
+
diff --git a/src/themes/OLH/templates/submission/submit_info.html b/src/themes/OLH/templates/submission/submit_info.html index 5cef7954e1..4a76682d50 100644 --- a/src/themes/OLH/templates/submission/submit_info.html +++ b/src/themes/OLH/templates/submission/submit_info.html @@ -57,7 +57,6 @@

Additional Fields

{{ field|foundation }}
{% endfor %} - {% endif %}
diff --git a/src/themes/default/assets/css/bootstrap.css b/src/themes/default/assets/css/bootstrap.css index 4040cf2ceb..cd7328dc24 100644 --- a/src/themes/default/assets/css/bootstrap.css +++ b/src/themes/default/assets/css/bootstrap.css @@ -9608,4 +9608,8 @@ footer svg { a.profilelink:link{ color: #FFFFFF; -} \ No newline at end of file +} + +.small-icon-text { + font-size: 17px !important; +} diff --git a/src/themes/default/templates/elements/article_listing.html b/src/themes/default/templates/elements/article_listing.html index 799ff5a525..1adf947938 100644 --- a/src/themes/default/templates/elements/article_listing.html +++ b/src/themes/default/templates/elements/article_listing.html @@ -17,7 +17,7 @@
-

{{ article.title|safe }}

+

{{ article.title|safe }}{% if article.is_remote %} {% endif %}

{% for author in article.authors.all %}{% if forloop.last %} {% if article.authors.all|length > 1 %} and diff --git a/src/transform/cassius/cassius-import/bin/saxon9.jar b/src/transform/cassius/cassius-import/bin/saxon9.jar old mode 100644 new mode 100755 diff --git a/src/utils/install/journal_defaults.json b/src/utils/install/journal_defaults.json index 6ec826d65a..a69426bce5 100644 --- a/src/utils/install/journal_defaults.json +++ b/src/utils/install/journal_defaults.json @@ -116,7 +116,7 @@ "type": "rich-text" }, "value": { - "default": "Dear {{ article.correspondence_author.full_name }},

Thank you for submitting \"{{ article }}\" to {{ article.journal }}.

Your work will now be reviewed by an editor and we will be in touch as the peer-review process progresses.

Regards,
{{ request.user.signature|safe }}" + "default": "Dear {{ article.correspondence_author.full_name }},

Thank you for submitting \"{{ article }}\" to {{ article.journal }}.

Your work will now be reviewed by an editor and we will be in touch as the peer-review process progresses.

Regards,
" } }, { diff --git a/src/utils/management/commands/check_mailgun_stat.py b/src/utils/management/commands/check_mailgun_stat.py new file mode 100644 index 0000000000..1c6c89ab08 --- /dev/null +++ b/src/utils/management/commands/check_mailgun_stat.py @@ -0,0 +1,64 @@ +import requests +from pprint import pprint + +from django.core.management.base import BaseCommand +from django.conf import settings + +from utils import models + +def get_logs(message_id): + return requests.get( + "https://api.mailgun.net/v3/{0}/events".format(settings.MAILGUN_SERVER_NAME), + auth=("api", settings.MAILGUN_ACCESS_KEY), + params={"message-id" : message_id}) + + +def check_for_perm_failure(event_dict, log): + + for event in event_dict.get('items'): + severity = event.get('severity', None) + if severity == 'permanent': + return True + + return False + + +class Command(BaseCommand): + """Attempts to update mailgun status for log entries""" + + help = "Attempts to update delivery status for mailgun emails." + + def handle(self, *args, **options): + + email_logs = models.LogEntry.objects.filter(is_email=True, + message_id__isnull=False, + status_checks_complete=False) + + for log in email_logs: + logs = get_logs(log.message_id.replace('<', '').replace('>', '')) + event_dict = logs.json() + print('Processing ', log.message_id, '...', end='') + + events = [] + for event in event_dict.get('items'): + events.append(event['event']) + + if 'delivered' in events: + log.message_status = 'delivered' + log.status_checks_complete = True + elif 'failed' in events: + if check_for_perm_failure(event_dict, log): + log.message_status = 'failed' + log.status_checks_complete = True + else: + log.message_status = 'accepted' + + elif 'accepted' in events: + log.message_status = 'accepted' + + log.number_status_checks += 1 + + print(' status {0}'.format(log.message_status)) + + log.save() + diff --git a/src/utils/management/commands/install_cron.py b/src/utils/management/commands/install_cron.py index 4b4e10d856..cc2e84bf4b 100644 --- a/src/utils/management/commands/install_cron.py +++ b/src/utils/management/commands/install_cron.py @@ -34,20 +34,28 @@ def handle(self, *args, **options): tab = CronTab(user=True) virtualenv = os.environ.get('VIRTUAL_ENV', None) - current_job = find_job(tab, "janeway_cron_job") + jobs = [ + {'name': 'janeway_cron_job', 'time': 10, 'task': 'execute_cron_tasks'}, + ] - if not current_job: - django_command = "{0}/manage.py execute_cron_tasks".format(settings.BASE_DIR) - if virtualenv: - command = '%s/bin/python3 %s' % (virtualenv, django_command) - else: - command = '%s' % (django_command) + if settings.ENABLE_ENHANCED_MAILGUN_FEATURES: + jobs.append({'name': 'janeway_mailgun_job', 'time': 60, 'task': 'check_mailgun_stat'}) - cron_job = tab.new(command, comment="janeway_cron_job") - cron_job.minute.every(10) + for job in jobs: + current_job = find_job(tab, job['name']) - else: - print("This cron job already exists.") + if not current_job: + django_command = "{0}/manage.py {1}".format(settings.BASE_DIR, job['task']) + if virtualenv: + command = '%s/bin/python3 %s' % (virtualenv, django_command) + else: + command = '%s' % (django_command) + + cron_job = tab.new(command, comment=job['name']) + cron_job.minute.every(job['time']) + + else: + print("{name} cron job already exists.".format(name=job['name'])) if action == 'test': print(tab.render()) diff --git a/src/utils/management/commands/install_janeway.py b/src/utils/management/commands/install_janeway.py index b1bea75a4d..9e1b44a680 100644 --- a/src/utils/management/commands/install_janeway.py +++ b/src/utils/management/commands/install_janeway.py @@ -4,7 +4,8 @@ from press import models as press_models from journal import models as journal_models -from utils import install +from utils.install import update_settings, update_license +from submission import models as submission_models class Command(BaseCommand): @@ -21,6 +22,7 @@ def handle(self, *args, **options): :param options: None :return: None """ + call_command('makemigrations', 'sites') call_command('migrate') print("Please answer the following questions.\n") translation.activate('en') @@ -38,8 +40,16 @@ def handle(self, *args, **options): journal.code = input('Journal #1 code: ') journal.domain = input('Journal #1 domain: ') journal.save() - install.update_settings(journal, management_command=True) - install.update_license(journal, management_command=True) + + print("Installing settings fixtures... ", end="") + update_settings(journal, management_command=False) + print("[okay]") + print("Installing license fixtures... ", end="") + update_license(journal, management_command=False) + print("[okay]") + print("Installing role fixtures") + call_command('loaddata', 'utils/install/roles.json') + journal.name = input('Journal #1 name: ') journal.description = input('Journal #1 description: ') journal.save() @@ -50,10 +60,11 @@ def handle(self, *args, **options): call_command('show_configured_journals') call_command('sync_journals_to_sites') call_command('build_assets') + print("Installing plugins.") call_command('install_plugins') + print("Installing Cron jobs") call_command('install_cron') - call_command('loaddata', 'utils/install/roles.json') print('Create a super user.') call_command('createsuperuser') - print('Open your browser to your domain /install/ to continue this setup process.') + print('Open your browser to your new journal domain {domain}/install/ to continue this setup process.'.format(domain=journal.domain)) diff --git a/src/utils/migrations/0003_auto_20171113_1251.py b/src/utils/migrations/0003_auto_20171113_1251.py new file mode 100644 index 0000000000..e03ec7ca99 --- /dev/null +++ b/src/utils/migrations/0003_auto_20171113_1251.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-11-13 12:51 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('utils', '0002_auto_20170813_1302'), + ] + + operations = [ + migrations.AddField( + model_name='logentry', + name='is_email', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='logentry', + name='message_id', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='logentry', + name='to', + field=models.EmailField(blank=True, max_length=254, null=True), + ), + migrations.AlterField( + model_name='logentry', + name='types', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AlterField( + model_name='pluginsetting', + name='types', + field=models.CharField(choices=[('rich-text', 'Rich Text'), ('text', 'Text'), ('char', 'Characters'), ('number', 'Number'), ('boolean', 'Boolean'), ('file', 'File'), ('select', 'Select'), ('json', 'JSON')], default='text', max_length=20), + ), + ] diff --git a/src/utils/migrations/0004_logentry_subject.py b/src/utils/migrations/0004_logentry_subject.py new file mode 100644 index 0000000000..57fdfb0ab8 --- /dev/null +++ b/src/utils/migrations/0004_logentry_subject.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-11-13 14:08 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('utils', '0003_auto_20171113_1251'), + ] + + operations = [ + migrations.AddField( + model_name='logentry', + name='subject', + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/src/utils/migrations/0005_logentry_message_status.py b/src/utils/migrations/0005_logentry_message_status.py new file mode 100644 index 0000000000..e083179c8b --- /dev/null +++ b/src/utils/migrations/0005_logentry_message_status.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-11-13 14:32 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('utils', '0004_logentry_subject'), + ] + + operations = [ + migrations.AddField( + model_name='logentry', + name='message_status', + field=models.CharField(choices=[('no_information', 'No Information'), ('accepted', 'Accepted'), ('delivered', 'Delivered'), ('failed', 'Failed')], default='no_information', max_length=255), + ), + ] diff --git a/src/utils/migrations/0006_auto_20171113_1444.py b/src/utils/migrations/0006_auto_20171113_1444.py new file mode 100644 index 0000000000..5cd0a2b52d --- /dev/null +++ b/src/utils/migrations/0006_auto_20171113_1444.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-11-13 14:44 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('utils', '0005_logentry_message_status'), + ] + + operations = [ + migrations.AddField( + model_name='logentry', + name='number_status_checks', + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name='logentry', + name='status_checks_complete', + field=models.BooleanField(default=False), + ), + ] diff --git a/src/utils/models.py b/src/utils/models.py index 9d9352b9ee..cec0d9411c 100644 --- a/src/utils/models.py +++ b/src/utils/models.py @@ -35,10 +35,18 @@ ('Info', 'Info'), ] +MESSAGE_STATUS = [ + ('no_information', 'No Information'), + ('accepted', 'Sending'), + ('delivered', 'Delivered'), + ('failed', 'Failed'), +] + class LogEntry(models.Model): - types = models.CharField(max_length=255, null=True, blank=True, choices=LOG_TYPES) + types = models.CharField(max_length=255, null=True, blank=True) date = models.DateTimeField(auto_now_add=True) + subject = models.TextField(null=True, blank=True) description = models.TextField(null=True, blank=True) level = models.CharField(max_length=20, null=True, blank=True, choices=LOG_LEVELS) actor = models.ForeignKey('core.Account', null=True, blank=True, related_name='actor', on_delete=models.SET_NULL) @@ -48,17 +56,33 @@ class LogEntry(models.Model): object_id = models.PositiveIntegerField(blank=True, null=True) target = GenericForeignKey('content_type', 'object_id') + is_email = models.BooleanField(default=False) + to = models.EmailField(blank=True, null=True) + message_id = models.TextField(blank=True, null=True) + message_status = models.CharField(max_length=255, choices=MESSAGE_STATUS, default='no_information') + number_status_checks = models.IntegerField(default=0) + status_checks_complete = models.BooleanField(default=False) + class Meta: verbose_name_plural = 'log entries' def __str__(self): - return u'[{0}] {1} - {2}'.format(self.types, self.date, self.description) + return u'[{0}] {1} - {2}'.format(self.types, self.date, self.subject) def __repr__(self): - return u'[{0}] {1} - {2}'.format(self.types, self.date, self.description) + return u'[{0}] {1} - {2}'.format(self.types, self.date, self.subject) + + def message_status_class(self): + if self.message_status == 'delivered': + return 'green' + elif self.message_status == 'failed': + return 'red' + else: + return 'amber' @staticmethod - def add_entry(types, description, level, actor=None, request=None, target=None): + def add_entry(types, description, level, actor=None, request=None, target=None, is_email=False, to=None, + message_id=None, subject=None): if actor is not None and callable(getattr(actor, "is_anonymous", None)): if actor.is_anonymous(): @@ -72,6 +96,10 @@ def add_entry(types, description, level, actor=None, request=None, target=None): 'actor': actor if actor else None, 'ip_address': get_ip_address(request), 'target': target, + 'is_email': is_email, + 'to': to, + 'message_id': message_id, + 'subject': subject, } new_entry = LogEntry.objects.create(**kwargs).save() diff --git a/src/utils/notify_helpers.py b/src/utils/notify_helpers.py index 5c91404dba..2176544de8 100644 --- a/src/utils/notify_helpers.py +++ b/src/utils/notify_helpers.py @@ -16,23 +16,25 @@ def send_slack(request, slack_message, slack_channels): notify.notification(**notify_contents) -def send_email_with_body_from_setting_template(request, template, subject, to, context): +def send_email_with_body_from_setting_template(request, template, subject, to, context, log_dict=None): notify_contents = { 'subject': subject, 'to': to, 'html': render_template.get_message_content(request, context, template), 'action': ['email'], 'request': request, + 'log_dict': log_dict } notify.notification(**notify_contents) -def send_email_with_body_from_user(request, subject, to, body): +def send_email_with_body_from_user(request, subject, to, body, log_dict=None): notify_contents = { 'subject': subject, 'to': to, 'html': body, 'action': ['email'], 'request': request, + 'log_dict': log_dict, } notify.notification(**notify_contents) diff --git a/src/utils/notify_plugins/email_log.py b/src/utils/notify_plugins/email_log.py new file mode 100644 index 0000000000..790d7161b0 --- /dev/null +++ b/src/utils/notify_plugins/email_log.py @@ -0,0 +1,41 @@ +from utils import models + + +def notify_hook(**kwargs): + # dummy mock-up of new notification hook defer + + # action is a list of notification targets + # if the "all" variable is passed, then some types of notification might act, like Slack. + # Email, though, should only send if it's specifically an email in action, not on "all". + action = kwargs.pop('action', []) + + if 'email_log' not in action: + # email is only sent if list of actions includes "email" + return + + # pop the args + + log_dict = kwargs.pop('log_dict') + + if log_dict: + types = log_dict.get('types') + action_text = log_dict.get('action_text') + level = log_dict.get('level') + request = kwargs.pop('request') + target = log_dict.get('target') + html = kwargs.pop('html') + + response = kwargs.pop('response') + + if isinstance(response, dict): + message_id = response['response'].get('id') + models.LogEntry.add_entry(types=types, description=html, level=level, + request=request, target=target, is_email=True, to=response.get('to')[0], + message_id=message_id, subject=action_text) + else: + models.LogEntry.add_entry(types=types, description=html, level=level, + request=request, target=target, subject=action_text) + + +def plugin_loaded(): + pass diff --git a/src/utils/notify_plugins/notify_email.py b/src/utils/notify_plugins/notify_email.py index ce5dfa17bb..3bf78e7808 100644 --- a/src/utils/notify_plugins/notify_email.py +++ b/src/utils/notify_plugins/notify_email.py @@ -2,6 +2,7 @@ from django.utils.html import strip_tags from utils import setting_handler +from utils import notify def send_email(subject, to, html, journal, request, bcc=None, cc=None, attachment=None, replyto=None): @@ -39,7 +40,8 @@ def send_email(subject, to, html, journal, request, bcc=None, cc=None, attachmen msg.attach(file.name, file.read(), file.content_type) file.close() - msg.send() + return msg.send() + def notify_hook(**kwargs): @@ -67,9 +69,19 @@ def notify_hook(**kwargs): # call the method if not task: - send_email(subject, to, html, request.journal, request, bcc, cc, attachment) + response = send_email(subject, to, html, request.journal, request, bcc, cc, attachment) else: - send_email(task.email_subject, task.email_to, task.email_html, task.email_journal, request, task.email_bcc, task.email_cc) + response = send_email(task.email_subject, task.email_to, task.email_html, task.email_journal, request, + task.email_bcc, task.email_cc) + + notify_contents = { + 'log_dict': kwargs.pop('log_dict'), + 'request': request, + 'response': response, + 'action': ['email_log'], + 'html': html, + } + notify.notification(**notify_contents) def plugin_loaded(): diff --git a/src/utils/transactional_emails.py b/src/utils/transactional_emails.py index 6247fa957f..f4032c7ded 100644 --- a/src/utils/transactional_emails.py +++ b/src/utils/transactional_emails.py @@ -24,13 +24,12 @@ def send_reviewer_withdrawl_notice(**kwargs): request.user.full_name()) if not skip: + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Review Withdrawl', + 'target': review_assignment.article} notify_helpers.send_email_with_body_from_user(request, 'subject_review_withdrawl', request.user.email, - user_message_content) + user_message_content, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Review Withdrawl Notification', description=description, level='Info', - request=request, target=review_assignment.article) - def send_editor_assigned_acknowledgements_mandatory(**kwargs): """ @@ -61,23 +60,24 @@ def send_editor_assigned_acknowledgements_mandatory(**kwargs): 'editor_assignment': editor_assignment } + log_dict = {'level': 'Info', + 'action_text': description, + 'types': 'Editor Assignment', + 'target': article} + # send to assigned editor if not skip: notify_helpers.send_email_with_body_from_user(request, 'subject_editor_assignment', editor_assignment.editor.email, - user_message_content) - util_models.LogEntry.add_entry(types='Editor Informed of Assignment', description=user_message_content, - level='Info', - request=request, target=article) + user_message_content, log_dict=log_dict) # send to editor if not acknowledgement: notify_helpers.send_slack(request, description, ['slack_editors']) notify_helpers.send_email_with_body_from_setting_template(request, 'editor_assignment', 'subject_editor_assignment', - request.user.email, context) - util_models.LogEntry.add_entry(types='Editor Assigned', description=description, level='Info', request=request, - target=article) + request.user.email, context, + log_dict=log_dict) def send_editor_assigned_acknowledgements(**kwargs): @@ -132,15 +132,16 @@ def send_reviewer_requested_acknowledgements_mandatory(**kwargs): 'review_assignment': review_assignment } + log_dict = {'level': 'Info', + 'action_text': description, + 'types': 'Review Request', + 'target': article} + # send to requested reviewer if not skip: notify_helpers.send_email_with_body_from_user(request, 'subject_review_request_sent', review_assignment.reviewer.email, - user_message_content) - util_models.LogEntry.add_entry(types='Reviewer Notified of Request', description=user_message_content, - level='Info', - request=request, target=article) - + user_message_content, log_dict=log_dict) if not acknowledgement: # send slack notify_helpers.send_slack(request, description, ['slack_editors']) @@ -148,10 +149,8 @@ def send_reviewer_requested_acknowledgements_mandatory(**kwargs): # send to editor notify_helpers.send_email_with_body_from_setting_template(request, 'review_request_sent', 'subject_review_request_sent', - review_assignment.editor.email, context) - - util_models.LogEntry.add_entry(types='Review Request', description=description, level='Info', request=request, - target=article) + review_assignment.editor.email, context, + log_dict=log_dict) def send_review_complete_acknowledgements(**kwargs): @@ -265,6 +264,11 @@ def send_submission_acknowledgement(**kwargs): 'request': request } + log_dict = {'level': 'Info', + 'action_text': 'A new article {0} was submitted'.format(article.title), + 'types': 'New Submission Acknowledgement', + 'target': article} + # send to slack notify_helpers.send_slack(request, 'New submission: {0} {1}'.format(article.title, article.get_remote_url(request)), @@ -275,7 +279,7 @@ def send_submission_acknowledgement(**kwargs): 'submission_acknowledgement', 'subject_submission_acknowledgement', article.correspondence_author.email, - context) + context, log_dict=log_dict) # send to all authors editors_to_email = setting_handler.get_setting( @@ -288,13 +292,11 @@ def send_submission_acknowledgement(**kwargs): else: editor_emails = request.journal.editor_emails - print(editor_emails) - notify_helpers.send_email_with_body_from_setting_template(request, 'editor_new_submission', 'subject_editor_new_submission', editor_emails, - context) + context, log_dict=log_dict) def send_article_decision(**kwargs): @@ -313,14 +315,16 @@ def send_article_decision(**kwargs): decision, request.user.full_name()) + log_dict = {'level': 'Info', + 'action_text': description, + 'types': 'Article Decision', + 'target': article} + if not skip: notify_helpers.send_email_with_body_from_user(request, 'Article Review Decision', request.user.email, - user_message_content) + user_message_content, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Article Decision', description=user_message_content, level='Info', - request=request, target=article) - def send_revisions_request(**kwargs): request = kwargs['request'] @@ -336,15 +340,17 @@ def send_revisions_request(**kwargs): revision.article.title, revision.date_due) + log_dict = {'level': 'Info', + 'action_text': description, + 'types': 'Revision Request', + 'target': revision.article} + if not skip: notify_helpers.send_email_with_body_from_user(request, 'subject_request_revisions', revision.article.correspondence_author.email, - user_message_content) + user_message_content, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Revision Request', description=user_message_content, level='Info', - request=request, target=revision.article) - def send_revisions_complete(**kwargs): request = kwargs['request'] @@ -377,14 +383,13 @@ def send_copyedit_assignment(**kwargs): copyedit_assignment.due) if not skip: - notify_helpers.send_email_with_body_from_user(request, 'subject_copyeditor_assignment_notification', + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Copyedit Assignment', + 'target': copyedit_assignment.article} + response = notify_helpers.send_email_with_body_from_user(request, 'subject_copyeditor_assignment_notification', copyedit_assignment.copyeditor.email, - user_message_content) + user_message_content, log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Revision Request', description=user_message_content, level='Info', - request=request, target=copyedit_assignment.article) - def send_copyedit_updated(**kwargs): request = kwargs['request'] @@ -397,13 +402,19 @@ def send_copyedit_updated(**kwargs): 'Copyedit assignment {0} updated'.format(copyedit_assignment.pk), ['slack_editors']) + log_dict = {'level': 'Info', + 'action_text': 'Copyedit assignment #{number} update.'.format(number=copyedit_assignment.pk), + 'types': 'Revision Request', + 'target': copyedit_assignment.article} + # send to author notify_helpers.send_email_with_body_from_setting_template(request, 'copyedit_updated', 'subject_copyedit_updated', copyedit_assignment.copyeditor.email, context={'request': request, - 'copyedit_assignment': copyedit_assignment}) + 'copyedit_assignment': copyedit_assignment}, + log_dict=log_dict) def send_copyedit_deleted(**kwargs): @@ -420,15 +431,16 @@ def send_copyedit_deleted(**kwargs): 'Copyedit assignment {0} updated'.format(copyedit_assignment.pk), ['slack_editors']) - # send to author + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Copyedit Assignment Deleted', + 'target': copyedit_assignment.article} + # send to copyeditor notify_helpers.send_email_with_body_from_setting_template(request, 'copyedit_deleted', 'subject_copyedit_deleted', copyedit_assignment.copyeditor.email, context={'request': request, - 'copyedit_assignment': copyedit_assignment}) - util_models.LogEntry.add_entry(types='Copyedit Task Deleted', description=description, level='Info', - request=request, target=copyedit_assignment.article) + 'copyedit_assignment': copyedit_assignment}, + log_dict=log_dict) def send_copyedit_decision(**kwargs): @@ -440,14 +452,14 @@ def send_copyedit_decision(**kwargs): copyedit_assignment.article.title, copyedit_assignment.due) + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Copyediting Decision', + 'target': copyedit_assignment.article} + notify_helpers.send_email_with_body_from_user(request, 'Article Copyediting Decision', copyedit_assignment.editor.email, - description) + description, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Copyeditor Decision', description=description, level='Info', - request=request, target=copyedit_assignment) - def send_copyedit_author_review(**kwargs): request = kwargs['request'] @@ -461,14 +473,14 @@ def send_copyedit_author_review(**kwargs): copyedit_assignment.article.correspondence_author.full_name()) if not skip: + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Copyedit Author Review', + 'target': copyedit_assignment.article} + notify_helpers.send_email_with_body_from_user(request, 'subject_copyeditor_notify_author', copyedit_assignment.article.correspondence_author.email, - user_message_content) + user_message_content, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Copyedit Author Review', description=user_message_content, level='Info', - request=request, target=copyedit_assignment.article) - def send_copyedit_complete(**kwargs): request = kwargs['request'] @@ -480,14 +492,14 @@ def send_copyedit_complete(**kwargs): copyedit_assignment.copyeditor.full_name(), article.title) + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Copyedit Complete', + 'target': copyedit_assignment.article} + notify_helpers.send_email_with_body_from_user(request, 'subject_copyeditor_notify_editor', copyedit_assignment.editor.email, - description) + description, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Initial Copyedit Complete', description=description, level='Info', - request=request, target=copyedit_assignment) - def send_copyedit_ack(**kwargs): request = kwargs['request'] @@ -499,14 +511,14 @@ def send_copyedit_ack(**kwargs): copyedit_assignment.article.title, ) if not skip: + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Copyedit Acknowledgement', + 'target': copyedit_assignment.article} + notify_helpers.send_email_with_body_from_user(request, 'subject_copyeditor_ack', copyedit_assignment.copyeditor.email, - user_message_content) + user_message_content, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Copyediting Complete', description=user_message_content, level='Info', - request=request, target=copyedit_assignment) - def send_copyedit_reopen(**kwargs): request = kwargs['request'] @@ -519,14 +531,14 @@ def send_copyedit_reopen(**kwargs): copyedit_assignment.copyeditor.full_name()) if not skip: + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Copyedit Complete', + 'target': copyedit_assignment.article} + notify_helpers.send_email_with_body_from_user(request, 'subject_copyeditor_reopen_task', copyedit_assignment.copyeditor.email, - user_message_content) + user_message_content, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Copyediting Reopened', description=user_message_content, level='Info', - request=request, target=copyedit_assignment.article) - def send_typeset_assignment(**kwargs): request = kwargs['request'] @@ -538,14 +550,14 @@ def send_typeset_assignment(**kwargs): typeset_task.assignment.article.title) if not skip: + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Typesetting Assignment', + 'target': typeset_task.assignment.article} + notify_helpers.send_email_with_body_from_user(request, 'subject_typesetter_notification', typeset_task.typesetter.email, - user_message_content) + user_message_content, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Typesetting Assignment', description=user_message_content, level='Info', - request=request, target=typeset_task.assignment.article) - def send_typeset_decision(**kwargs): request = kwargs['request'] @@ -556,14 +568,14 @@ def send_typeset_decision(**kwargs): decision, typeset_task.assignment.article.title) + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Typesetter Decision', + 'target': typeset_task.assignment.article} + notify_helpers.send_email_with_body_from_user(request, 'Article Typesetting Decision', typeset_task.assignment.production_manager.email, - description) + description, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Typesetting Assignment', description=description, level='Info', - request=request, target=typeset_task.assignment.article) - def send_typeset_task_deleted(**kwargs): request = kwargs['request'] @@ -575,16 +587,17 @@ def send_typeset_task_deleted(**kwargs): typeset_task.assignment.article.title, ) + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Typesetter Assignment Deleted', + 'target': typeset_task.assignment.article} + # send to author notify_helpers.send_email_with_body_from_setting_template(request, 'typeset_deleted', 'subject_typeset_deleted', typeset_task.typesetter.email, context={'request': request, - 'typeset_task': typeset_task}) + 'typeset_task': typeset_task}, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Typesetting Assignment Deleted', description=description, level='Info', - request=request, target=typeset_task.assignment.article) def send_typeset_complete(**kwargs): @@ -597,14 +610,14 @@ def send_typeset_complete(**kwargs): typeset_task.note_from_typesetter, ) + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Typesetting Assignment Complete', + 'target': typeset_task.assignment.article} + notify_helpers.send_email_with_body_from_user(request, 'subject_typesetter_complete_notification', typeset_task.assignment.production_manager.email, - description) + description, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Typesetting Assignment', description=description, level='Info', - request=request, target=typeset_task.assignment.article) - def send_production_complete(**kwargs): request = kwargs['request'] @@ -614,6 +627,9 @@ def send_production_complete(**kwargs): description = 'Production has been completed for article {0}.'.format(article.title) + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Production Complete', + 'target': article} + for task in assignment.typesettask_set.all(): notify_helpers.send_email_with_body_from_user(request, 'Article Production Complete', task.typesetter.email, user_content_message) @@ -622,12 +638,10 @@ def send_production_complete(**kwargs): 'production_complete', 'subject_production_complete', article.editor_emails(), - {'article': article, 'assignment': assignment}) + {'article': article, 'assignment': assignment}, + log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Production Complete', description=description, level='Info', - request=request, target=article) - def fire_proofing_manager_assignment(**kwargs): request = kwargs['request'] @@ -638,13 +652,15 @@ def fire_proofing_manager_assignment(**kwargs): proofing_assignment.proofing_manager.full_name(), article.title, ) - + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Proofing Manager Assigned', + 'target': article} context = {'request': request, 'proofing_assignment': proofing_assignment, 'article': article} notify_helpers.send_email_with_body_from_setting_template(request, 'notify_proofing_manager', 'subject_notify_proofing_manager', proofing_assignment.proofing_manager.email, - context) + context, + log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) @@ -659,6 +675,8 @@ def cancel_proofing_task(**kwargs): proofing_task.proofreader.full_name(), request.user.full_name() ) + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Proofing Task Cancelled', + 'target': article} context = {'request': request, 'proofing_task': proofing_task, 'user_content_message': user_content_message} notify_helpers.send_email_with_body_from_setting_template(request, 'notify_proofreader_cancelled', @@ -679,11 +697,13 @@ def edit_proofing_task(**kwargs): request.user.full_name() ) context = {'request': request, 'proofing_task': proofing_task} + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Proofing Task Edited', + 'target': article} notify_helpers.send_email_with_body_from_setting_template(request, 'notify_proofreader_edited', 'subject_notify_proofreader_edited', proofing_task.proofreader.email, - context) + context, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) @@ -698,15 +718,13 @@ def notify_proofreader(**kwargs): proofing_task.proofreader.full_name(), request.user.full_name() ) - + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Proofreading Requested', + 'target': article} notify_helpers.send_email_with_body_from_user(request, 'subject_notify_proofreader_assignment', proofing_task.proofreader.email, - user_content_message) + user_content_message, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - util_models.LogEntry.add_entry(types='Proofreading Requested', description=description, level='Info', - request=request, target=article) - def send_proofreader_decision(**kwargs): request = kwargs['request'] @@ -718,10 +736,11 @@ def send_proofreader_decision(**kwargs): proofing_task.round.assignment.article.title, decision ) - + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Proofreading Update', + 'target': proofing_task.round.assignment.article} notify_helpers.send_email_with_body_from_user(request, 'Article Proofreading Update', proofing_task.round.assignment.proofing_manager.email, - description) + description, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) @@ -754,13 +773,14 @@ def send_proofing_typeset_request(**kwargs): typeset_task.typesetter.full_name(), article.title, ) - + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Typesetting Updates Requested', + 'target': article} if not skip: notify_helpers.send_slack(request, description, ['slack_editors']) notify_helpers.send_email_with_body_from_user( request, 'subject_notify_typesetter_proofing_changes', typeset_task.proofing_task.round.assignment.proofing_manager.email, - user_content_message) + user_content_message, log_dict=log_dict) def send_proofing_typeset_decision(**kwargs): @@ -773,10 +793,11 @@ def send_proofing_typeset_decision(**kwargs): typeset_task.proofing_task.round.assignment.article.title, decision ) - + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Proofing Typesetting', + 'target': typeset_task.assignment.article} notify_helpers.send_email_with_body_from_user(request, 'Proofing Typesetting Changes', typeset_task.proofing_task.round.assignment.proofing_manager.email, - description) + description, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) @@ -790,9 +811,11 @@ def send_corrections_complete(**kwargs): article.title, typeset_task.pk, ) + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Proofing Typesetting Complete', + 'target': typeset_task.assignment.article} notify_helpers.send_email_with_body_from_user(request, 'subject_typesetter_corrections_complete', article.proofingassignment.proofing_manager.email, - description) + description, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) @@ -823,11 +846,12 @@ def send_proofing_complete(**kwargs): skip = kwargs['skip'] description = "Proofing is now complete for {0}".format(article.title) - + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Proofing Complete', + 'target': article} if not skip: notify_helpers.send_email_with_body_from_user(request, 'subject_notify_editor_proofing_complete', article.editor_emails(), - user_message) + user_message, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) @@ -842,14 +866,17 @@ def send_author_publication_notification(**kwargs): article.date_published, request.user.full_name()) + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Article Published', + 'target': article} + notify_helpers.send_email_with_body_from_user(request, '{0} Publication'.format(article.title), article.editor_emails(), - user_message) + user_message, log_dict=log_dict) notify_helpers.send_slack(request, description, ['slack_editors']) - # Check for SEs and PRs and notify them as well + # Check for SEs and PRs and notify them as well if section_editors: for editor in article.section_editors(): notify_helpers.send_email_with_body_from_setting_template(request, @@ -872,10 +899,12 @@ def review_sec_override_notification(**kwargs): override = kwargs['override'] description = "{0} overwrote their access to {1}".format(override.editor.full_name(), override.article.title) + log_dict = {'level': 'Warning', 'action_text': description, 'types': 'Security Override', + 'target': override.article} notify_helpers.send_slack(request, description, ['slack_editors']) notify_helpers.send_email_with_body_from_user(request, 'Review Security Override', request.journal.editor_emails, - description) + description, log_dict=log_dict) def send_draft_decison(**kwargs): @@ -889,12 +918,15 @@ def send_draft_decison(**kwargs): description = "Section Editor {0} has drafted a decision for Article {1}".format( draft.section_editor.full_name(), article.title) + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Draft Decision', + 'target': article} notify_helpers.send_slack(request, description, ['slack_editors']) notify_helpers.send_email_with_body_from_setting_template(request, 'draft_editor_message', 'subject_draft_editor_message', emails, - {'draft': draft, 'article': article}) + {'draft': draft, 'article': article}, + log_dict=log_dict) def send_author_copyedit_complete(**kwargs): @@ -925,15 +957,15 @@ def preprint_submission(**kwargs): description = '{author} has submitted a new preprint titled {title}.'.format(author=request.user.full_name(), title=article.title) - - util_models.LogEntry.add_entry('submission', description, 'info', request.user, request, article) + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Submission', + 'target': article} # Send an email to the user context = {'article': article} template = request.press.preprint_submission email_text = render_template.get_message_content(request, context, template, template_is_setting=True) - notify_helpers.send_email_with_body_from_user(request, 'Preprint Submission', request.user.email, email_text) - util_models.LogEntry.add_entry('email', email_text, 'info', request.user, request, article) + notify_helpers.send_email_with_body_from_user(request, 'Preprint Submission', request.user.email, email_text, + log_dict=log_dict) # Send an email to the preprint editor url = request.press_base_url + reverse('preprints_manager_article', kwargs={'article_id': article.pk}) @@ -945,7 +977,6 @@ def preprint_submission(**kwargs): for editor in request.press.preprint_editors(): notify_helpers.send_email_with_body_from_user(request, 'Preprint Submission', editor.email, editor_email_text) - util_models.LogEntry.add_entry('email', editor_email_text, 'info', request.user, request, article) def preprint_publication(**kwargs): @@ -987,7 +1018,8 @@ def preprint_comment(**kwargs): kwargs={'article_id': article.pk})) description = '{author} commented on {article}'.format(author=request.user.full_name(), article=article.title) + log_dict = {'level': 'Info', 'action_text': description, 'types': 'Preprint Comment', + 'target': article} - util_models.LogEntry.add_entry('comment', description, 'info', request.user, request, article) notify_helpers.send_email_with_body_from_user(request, ' Preprint Comment', article.owner.email, - email_text) + email_text, log_dict=log_dict)

Date Actor LevelEmail Status
{{ entry.types }}{{ entry.date }}{{ entry.actor.full_name }}{{ entry.get_level_display }}View Content {{ entry.types }}{{ entry.date }}{{ entry.actor.full_name }}{{ entry.get_level_display }} + + {{ entry.get_message_status_display }} + View Content
History Delete