diff --git a/petitions/forms.py b/petitions/forms.py index 8ce10ab92e4cb0b333aa3e6256de8d2a66db7d33..7321a5178d4cf265d135995e3bc15234147d439c 100644 --- a/petitions/forms.py +++ b/petitions/forms.py @@ -1,10 +1,43 @@ from django import forms +from captcha.fields import ReCaptchaField + from .models import PetitionSignatory +from scipost.models import Contributor + class SignPetitionForm(forms.ModelForm): + captcha = ReCaptchaField(attrs={'theme': 'clean'}, label='*Please verify to continue:') + class Meta: model = PetitionSignatory fields = ['title', 'first_name', 'last_name', 'email', 'country_of_employment', 'affiliation'] + + def __init__(self, *args, **kwargs): + self.petition = kwargs.pop('petition', False) + self.current_user = kwargs.pop('current_user', False) + super().__init__(*args, **kwargs) + + def clean_email(self): + email = self.cleaned_data['email'] + petition = self.petition + if not petition: + return email + + if self.instance.id: + return email + + if self.current_user.is_authenticated(): + if self.current_user.email != email: + self.add_error('email', 'This email address is not associated to your account') + else: + if Contributor.objects.filter(user__email=email).exists(): + self.add_error('email', ('This email address is associated to a Contributor; please ' + 'login to sign the petition')) + if PetitionSignatory.objects.filter(petition=petition, email=email).exists(): + self.add_error('email', ('This email address is already associated to a ' + 'signature for this petition')) + + return email diff --git a/petitions/utils.py b/petitions/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..8adeca9b6e618a13bbdb5943a0ef9bb4801e152a --- /dev/null +++ b/petitions/utils.py @@ -0,0 +1,12 @@ +from common.utils import BaseMailUtil + + +class PetitionUtils(BaseMailUtil): + mail_sender = 'petitions@scipost.org' + mail_sender_title = 'SciPost petitions' + + @classmethod + def send_SPB_petition_signature_thanks(cls, email_address): + cls._send_mail(cls, 'SPB_petition_signature_thanks', + [email_address], + 'Thanks for signing') diff --git a/petitions/views.py b/petitions/views.py index 8a7a9c7026f058617eeae1f072abbf47104d8cdf..b702d80784f700c223fe6be5da4f6228a3955790 100644 --- a/petitions/views.py +++ b/petitions/views.py @@ -9,6 +9,7 @@ from django.template import Context, Template from .models import Petition, PetitionSignatory from .forms import SignPetitionForm +from .utils import PetitionUtils def petition(request, slug): @@ -20,6 +21,7 @@ def petition(request, slug): is_signed = petition.petition_signatories.verified().filter( signatory=request.user.contributor).exists() initial = { + 'petition': petition, 'title': request.user.contributor.title, 'first_name': request.user.first_name, 'last_name': request.user.last_name, @@ -28,7 +30,8 @@ def petition(request, slug): 'affiliation': request.user.contributor.affiliation, } - form = SignPetitionForm(request.POST or None, initial=initial) + form = SignPetitionForm(request.POST or None, initial=initial, petition=petition, + current_user=request.user) if form.is_valid(): signature = form.save(commit=False) signature.petition = petition @@ -37,6 +40,8 @@ def petition(request, slug): if request.user.is_authenticated: signature.signatory = request.user.contributor signature.verified = True + PetitionUtils.load({'petition': petition}) + PetitionUtils.send_SPB_petition_signature_thanks(request.user.email) else: # Generate verification key and link salt = "" @@ -94,4 +99,6 @@ def verify_signature(request, slug, key): signature.save() messages.success(request, ('<h3>Many thanks for confirming your signature.</h3>' '<p>Please invite your colleagues to also sign.</p>')) + PetitionUtils.load({'petition': petition}) + PetitionUtils.send_SPB_petition_signature_thanks(signature.email) return redirect(petition.get_absolute_url()) diff --git a/scipost/forms.py b/scipost/forms.py index 50e6a5557616ce4364db520a96e53de2719a7679..614c14f44fad3314c1e6333c434e8ad634e56d21 100644 --- a/scipost/forms.py +++ b/scipost/forms.py @@ -6,6 +6,7 @@ from django.contrib.auth.models import User, Group from django.contrib.auth.password_validation import validate_password from django.core.exceptions import ValidationError from django.core.urlresolvers import reverse_lazy +from django.db.models import Q from django.utils import timezone from django.utils.dates import MONTHS from django.utils.http import is_safe_url @@ -327,6 +328,22 @@ class AuthenticationForm(forms.Form): password = forms.CharField(label='Password', widget=forms.PasswordInput()) next = forms.CharField(widget=forms.HiddenInput(), required=False) + def user_is_inactive(self): + """ + Check if the User is active but only if the password is valid, to prevent any + possible clue (?) of the password. + """ + username = self.cleaned_data['username'] + password = self.cleaned_data['password'] + try: + _user = User.objects.get(Q(email=username) | Q(username=username)) + return _user.check_password(password) and not _user.is_active + except: + return False + + def can_resend_activation_mail(self): + return True + def authenticate(self): """ Authenticate will return an valid User if credentials are correct. @@ -338,6 +355,7 @@ class AuthenticationForm(forms.Form): if user: return user + # Try to use the email address for convenience try: _user = User.objects.get(email=username) return authenticate(username=_user.username, password=password) diff --git a/scipost/templatetags/user_groups.py b/scipost/templatetags/user_groups.py index eac1a8b142a94351ee09751cae447afec31aa901..408837b3610ed36499ad4a021c0c8124ccecf6c2 100644 --- a/scipost/templatetags/user_groups.py +++ b/scipost/templatetags/user_groups.py @@ -9,4 +9,4 @@ def is_edcol_admin(user): Assign template variable (boolean) to check if user is Editorial Administator. This assignment is limited to a certain context block! """ - return user.groups.filter(name='Editorial Administrators').exists() or user.is_superuser() + return user.groups.filter(name='Editorial Administrators').exists() or user.is_superuser diff --git a/scipost/views.py b/scipost/views.py index c142244dc7789f3c738d31341bfc9b0aaa3148ee..fb5ff5b6cf000087a8bf638593772d59fea71478 100644 --- a/scipost/views.py +++ b/scipost/views.py @@ -210,7 +210,7 @@ def request_new_activation_link(request, contributor_id, key): context = { 'ack_header': 'We have emailed you a new activation link.', 'ack_message': ('Please acknowledge it within its 48 hours validity ' - 'window if you want us to proceed with vetting your registraion.'), + 'window if you want us to proceed with vetting your registration.'), } return render(request, 'scipost/acknowledgement.html', context) context = {'contributor': contributor} @@ -643,16 +643,15 @@ def login_view(request): user = form.authenticate() if user is not None: if is_registered(user): - # This check seems redundant, however do not remove. - if user.is_active: - login(request, user) - redirect_to = form.get_redirect_url(request) - return redirect(redirect_to) - else: - form.add_error(None, 'Your account is disabled.') + login(request, user) + redirect_to = form.get_redirect_url(request) + return redirect(redirect_to) else: form.add_error(None, ('Your account has not yet been vetted. ' '(our admins will verify your credentials very soon)')) + elif form.user_is_inactive(): + form.add_error(None, ('Your account is not yet activated. ' + 'Please first activate your account.')) else: form.add_error(None, 'Invalid username/password.') context = {'form': form} diff --git a/submissions/templates/submissions/submission_detail.html b/submissions/templates/submissions/submission_detail.html index 1a0b85913247e8d3cc940466be9541f3b1893a4a..891f73799991e18c7faf3bf55ae2ceee6a6f5d53 100644 --- a/submissions/templates/submissions/submission_detail.html +++ b/submissions/templates/submissions/submission_detail.html @@ -51,7 +51,7 @@ <h3 class="mt-0">- <span class="circle text-danger border-danger">!</span> You have an unfinished report for this submission, <a href="{% url 'submissions:submit_report' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr %}">finish your report here.</a></h3> {% endif %} - {% if submission.other_versions and not submission.is_current %} + {% if submission.other_versions or not submission.is_current %} <ul class="mt-3 mb-1 list-unstyled pl-4"> {% if not submission.is_current %} <li><h3 class="text-danger">This is not the current version.</h3></li> diff --git a/templates/email/SPB_petition_signature_thanks.html b/templates/email/SPB_petition_signature_thanks.html new file mode 100644 index 0000000000000000000000000000000000000000..d528bf7666449f25a968acb281be50b2ae138f78 --- /dev/null +++ b/templates/email/SPB_petition_signature_thanks.html @@ -0,0 +1,15 @@ +<p>Many thanks for signing the petition!</p> +<p> + If you have not done so already, you can really further help SciPost convince + your institution, library and/or funding agency to become Supporting Partners + by sending a personalized email to one of their representatives; you can use our + <a href="mailto:?subject=Petition to support SciPost&body=[PLEASE FILL IN THE TO FIELD ABOVE (keeping partners@scipost.org in cc)]%0D%0A%0D%0ADear ...%0D%0A%0D%0A[PLEASE WRITE A PERSONALIZED MESSAGE]%0D%0A%0D%0AHere under, you will find basic information about SciPost and how you can support it.%0D%0A%0D%0ASincerely,%0D%0A[YOUR SIGNATURE]%0D%0A%0D%0A%0D%0A%0D%0ASciPost (https://scipost.org) is a top-quality next-generation Open Access publication portal managed by professional scientists. Its principles, ideals and implementation can be found at https://scipost.org/about and https://scipost.org/FAQ.%0D%0A%0D%0ASciPost follows a different funding model than most traditional publishers. It operates on an entirely not-for-profit basis, and charges neither subscription fees nor article processing charges; instead, its activities are financed through a cost-slashing consortial model.%0D%0A%0D%0ABy making a small financial commitment, the institutions and organizations that benefit from SciPost’s activities can become Supporting Partners. This enables SciPost to perform all of its publication-related activities, maintain its online portal and implement its long-term development plan. Details of the consortial funding scheme and how to join can be found at https://scipost.org/partners or by emailing partners@scipost.org.%0D%0A&cc=partners@scipost.org">template</a> as a start.</p> +<p> + You can also point them towards details of our consortial funding scheme on our <a href="https://scipost.org/partners">Partners page</a>, and our <a href="https://scipost.org/static/scipost/SPB/SciPost_Supporting_Partners_Board_Prospectus.pdf">one-page Prospectus</a> summarizing the scheme, which is expounded in detail in the draft <a href="https://scipost.org/static/scipost/SPB/SciPost_Supporting_Partner_Agreement.pdf">Partner Agreement</a>. +</p> +<p> + We are very grateful for your help. +</p> +<p> + The SciPost Team +</p> diff --git a/templates/email/SPB_petition_signature_thanks.txt b/templates/email/SPB_petition_signature_thanks.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad8c0002e889cf3031538cbc1f9f1494e80a41ab --- /dev/null +++ b/templates/email/SPB_petition_signature_thanks.txt @@ -0,0 +1,7 @@ +Many thanks for signing the petition!\n\n +If you have not done so already, you can really further help SciPost convince +your institution, library and/or funding agency to become Supporting Partners +by sending a personalized email to one of their representatives; we have a +handy email template for you to use at https://scipost.org/partners/.\n\n +You can also point them to our prospectus and draft agreement on that same +page.\n\nWe are very grateful for your help.\n\nThe SciPost Team