SciPost Code Repository

Skip to content
Snippets Groups Projects
Commit 243e51c8 authored by Jorran de Wit's avatar Jorran de Wit
Browse files

Merge branch 'todos' into development

parents fc08930e 1adc70db
No related branches found
No related tags found
No related merge requests found
...@@ -124,6 +124,7 @@ subject_areas_dict = {} ...@@ -124,6 +124,7 @@ subject_areas_dict = {}
for k in subject_areas_raw_dict.keys(): for k in subject_areas_raw_dict.keys():
subject_areas_dict.update(dict(subject_areas_raw_dict[k])) subject_areas_dict.update(dict(subject_areas_raw_dict[k]))
CONTRIBUTOR_NEWLY_REGISTERED = 0
CONTRIBUTOR_NORMAL = 1 CONTRIBUTOR_NORMAL = 1
CONTRIBUTOR_STATUS = ( CONTRIBUTOR_STATUS = (
# status determine the type of Contributor: # status determine the type of Contributor:
...@@ -135,7 +136,7 @@ CONTRIBUTOR_STATUS = ( ...@@ -135,7 +136,7 @@ CONTRIBUTOR_STATUS = (
# -2: other account already exists for this person # -2: other account already exists for this person
# -3: barred from SciPost (abusive behaviour) # -3: barred from SciPost (abusive behaviour)
# -4: disabled account (deceased) # -4: disabled account (deceased)
(0, 'newly registered'), (CONTRIBUTOR_NEWLY_REGISTERED, 'newly registered'),
(CONTRIBUTOR_NORMAL, 'normal user'), (CONTRIBUTOR_NORMAL, 'normal user'),
(-1, 'not a professional scientist'), (-1, 'not a professional scientist'),
(-2, 'other account already exists'), (-2, 'other account already exists'),
......
...@@ -4,6 +4,7 @@ from django.contrib.auth.models import User, Group ...@@ -4,6 +4,7 @@ from django.contrib.auth.models import User, Group
from django.contrib.auth.password_validation import validate_password from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from django.utils import timezone
from django.utils.http import is_safe_url from django.utils.http import is_safe_url
from django_countries import countries from django_countries import countries
...@@ -133,6 +134,41 @@ class DraftInvitationForm(forms.ModelForm): ...@@ -133,6 +134,41 @@ class DraftInvitationForm(forms.ModelForm):
'cited_in_submission', 'cited_in_publication' 'cited_in_submission', 'cited_in_publication'
] ]
def __init__(self, *args, **kwargs):
'''
This form has a required keyword argument `current_user` which is used for validation of
the form fields.
'''
self.current_user = kwargs.pop('current_user')
super().__init__(*args, **kwargs)
def clean_email(self):
email = self.cleaned_data['email']
if self.instance.id:
return email
if RegistrationInvitation.objects.filter(email=email).exists():
self.add_error('email', 'This email address has already been used for an invitation')
elif DraftInvitation.objects.filter(email=email).exists():
self.add_error('email', ('This email address has already been'
' used for a draft invitation'))
elif User.objects.filter(email=email).exists():
self.add_error('email', 'This email address is already associated to a Contributor')
return email
def clean_invitation_type(self):
invitation_type = self.cleaned_data['invitation_type']
if invitation_type == 'F' and not self.current_user.has_perm('scipost.can_invite_Fellows'):
self.add_error('invitation_type', ('You do not have the authorization'
' to send a Fellow-type invitation.'
' Consider Contributor, or cited (sub/pub).'))
if invitation_type == 'R':
self.add_error('invitation_type', ('Referee-type invitations must be made'
'by the Editor-in-charge at the relevant'
' Submission\'s Editorial Page.'))
return invitation_type
class RegistrationInvitationForm(forms.ModelForm): class RegistrationInvitationForm(forms.ModelForm):
cited_in_submission = AutoCompleteSelectField('submissions_lookup', required=False) cited_in_submission = AutoCompleteSelectField('submissions_lookup', required=False)
...@@ -147,12 +183,17 @@ class RegistrationInvitationForm(forms.ModelForm): ...@@ -147,12 +183,17 @@ class RegistrationInvitationForm(forms.ModelForm):
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
'''
This form has a required keyword argument `current_user` which is used for validation of
the form fields.
'''
self.current_user = kwargs.pop('current_user')
if kwargs.get('initial', {}).get('cited_in_submission', False): if kwargs.get('initial', {}).get('cited_in_submission', False):
kwargs['initial']['cited_in_submission'] = kwargs['initial']['cited_in_submission'].id kwargs['initial']['cited_in_submission'] = kwargs['initial']['cited_in_submission'].id
if kwargs.get('initial', {}).get('cited_in_publication', False): if kwargs.get('initial', {}).get('cited_in_publication', False):
kwargs['initial']['cited_in_publication'] = kwargs['initial']['cited_in_publication'].id kwargs['initial']['cited_in_publication'] = kwargs['initial']['cited_in_publication'].id
super(RegistrationInvitationForm, self).__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['personal_message'].widget.attrs.update( self.fields['personal_message'].widget.attrs.update(
{'placeholder': ('NOTE: a personal phrase or two.' {'placeholder': ('NOTE: a personal phrase or two.'
' The bulk of the text will be auto-generated.')}) ' The bulk of the text will be auto-generated.')})
...@@ -161,6 +202,27 @@ class RegistrationInvitationForm(forms.ModelForm): ...@@ -161,6 +202,27 @@ class RegistrationInvitationForm(forms.ModelForm):
queryset=Publication.objects.all().order_by('-publication_date'), queryset=Publication.objects.all().order_by('-publication_date'),
required=False) required=False)
def clean_email(self):
email = self.cleaned_data['email']
if RegistrationInvitation.objects.filter(email=email).exists():
self.add_error('email', 'This email address has already been used for an invitation')
elif User.objects.filter(email=email).exists():
self.add_error('email', 'This email address is already associated to a Contributor')
return email
def clean_invitation_type(self):
invitation_type = self.cleaned_data['invitation_type']
if invitation_type == 'F' and not self.current_user.has_perm('scipost.can_invite_Fellows'):
self.add_error('invitation_type', ('You do not have the authorization'
' to send a Fellow-type invitation.'
' Consider Contributor, or cited (sub/pub).'))
if invitation_type == 'R':
self.add_error('invitation_type', ('Referee-type invitations must be made by the'
' Editor-in-charge at the relevant Submission'
'\'s Editorial Page. '))
return invitation_type
class ModifyPersonalMessageForm(forms.Form): class ModifyPersonalMessageForm(forms.Form):
personal_message = forms.CharField(widget=forms.Textarea()) personal_message = forms.CharField(widget=forms.Textarea())
...@@ -314,10 +376,21 @@ class UnavailabilityPeriodForm(forms.ModelForm): ...@@ -314,10 +376,21 @@ class UnavailabilityPeriodForm(forms.ModelForm):
fields = ['start', 'end'] fields = ['start', 'end']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(UnavailabilityPeriodForm, self).__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['start'].widget.attrs.update({'placeholder': 'YYYY-MM-DD'}) self.fields['start'].widget.attrs.update({'placeholder': 'YYYY-MM-DD'})
self.fields['end'].widget.attrs.update({'placeholder': 'YYYY-MM-DD'}) self.fields['end'].widget.attrs.update({'placeholder': 'YYYY-MM-DD'})
def clean_end(self):
now = timezone.now()
start = self.cleaned_data['start']
end = self.cleaned_data['end']
if start > end:
self.add_error('end', 'The start date you have entered is later than the end date.')
if end < now.date():
self.add_error('end', 'You have entered an end date in the past.')
return end
class RemarkForm(forms.Form): class RemarkForm(forms.Form):
remark = forms.CharField(widget=forms.Textarea(), label='') remark = forms.CharField(widget=forms.Textarea(), label='')
......
...@@ -61,6 +61,10 @@ class Command(BaseCommand): ...@@ -61,6 +61,10 @@ class Command(BaseCommand):
codename='can_invite_Fellows', codename='can_invite_Fellows',
name='Can invite Fellows', name='Can invite Fellows',
content_type=content_type) content_type=content_type)
can_resend_registration_requests, created = Permission.objects.get_or_create(
codename='can_resend_registration_requests',
name='Can resend registration activation emails',
content_type=content_type)
# Communications # Communications
can_email_group_members, created = Permission.objects.get_or_create( can_email_group_members, created = Permission.objects.get_or_create(
...@@ -189,6 +193,7 @@ class Command(BaseCommand): ...@@ -189,6 +193,7 @@ class Command(BaseCommand):
can_manage_registration_invitations, can_manage_registration_invitations,
can_email_group_members, can_email_group_members,
can_email_particulars, can_email_particulars,
can_resend_registration_requests,
can_vet_registration_requests, can_vet_registration_requests,
can_vet_commentary_requests, can_vet_commentary_requests,
can_vet_thesislink_requests, can_vet_thesislink_requests,
......
...@@ -3,7 +3,7 @@ import datetime ...@@ -3,7 +3,7 @@ import datetime
from django.db import models from django.db import models
from django.db.models import Q from django.db.models import Q
from .constants import CONTRIBUTOR_NORMAL from .constants import CONTRIBUTOR_NORMAL, CONTRIBUTOR_NEWLY_REGISTERED
class FellowManager(models.Manager): class FellowManager(models.Manager):
...@@ -20,3 +20,6 @@ class FellowManager(models.Manager): ...@@ -20,3 +20,6 @@ class FellowManager(models.Manager):
class ContributorManager(models.Manager): class ContributorManager(models.Manager):
def active(self): def active(self):
return self.filter(user__is_active=True, status=CONTRIBUTOR_NORMAL) return self.filter(user__is_active=True, status=CONTRIBUTOR_NORMAL)
def awaiting_validation(self):
return self.filter(user__is_active=False, status=CONTRIBUTOR_NEWLY_REGISTERED)
# -*- coding: utf-8 -*-
# Generated by Django 1.10.3 on 2017-06-19 18:49
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('scipost', '0055_auto_20170519_0937'),
]
operations = [
migrations.AlterField(
model_name='draftinvitation',
name='date_drafted',
field=models.DateTimeField(auto_now_add=True),
),
migrations.AlterField(
model_name='draftinvitation',
name='first_name',
field=models.CharField(max_length=30),
),
migrations.AlterField(
model_name='draftinvitation',
name='last_name',
field=models.CharField(max_length=30),
),
]
...@@ -103,7 +103,6 @@ class Contributor(models.Model): ...@@ -103,7 +103,6 @@ class Contributor(models.Model):
salt = self.user.username.encode('utf8') salt = self.user.username.encode('utf8')
self.activation_key = hashlib.sha1(salt+salt).hexdigest() self.activation_key = hashlib.sha1(salt+salt).hexdigest()
self.key_expires = datetime.datetime.now() + datetime.timedelta(days=2) self.key_expires = datetime.datetime.now() + datetime.timedelta(days=2)
self.save()
def discipline_as_string(self): def discipline_as_string(self):
# Redundant, to be removed in future # Redundant, to be removed in future
...@@ -161,7 +160,7 @@ class Contributor(models.Model): ...@@ -161,7 +160,7 @@ class Contributor(models.Model):
class UnavailabilityPeriod(models.Model): class UnavailabilityPeriod(models.Model):
contributor = models.ForeignKey(Contributor, on_delete=models.CASCADE) contributor = models.ForeignKey('scipost.Contributor', on_delete=models.CASCADE)
start = models.DateField() start = models.DateField()
end = models.DateField() end = models.DateField()
...@@ -205,8 +204,8 @@ class DraftInvitation(models.Model): ...@@ -205,8 +204,8 @@ class DraftInvitation(models.Model):
Draft of an invitation, filled in by an officer. Draft of an invitation, filled in by an officer.
""" """
title = models.CharField(max_length=4, choices=TITLE_CHOICES) title = models.CharField(max_length=4, choices=TITLE_CHOICES)
first_name = models.CharField(max_length=30, default='') first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30, default='') last_name = models.CharField(max_length=30)
email = models.EmailField() email = models.EmailField()
invitation_type = models.CharField(max_length=2, choices=INVITATION_TYPE, invitation_type = models.CharField(max_length=2, choices=INVITATION_TYPE,
default=INVITATION_CONTRIBUTOR) default=INVITATION_CONTRIBUTOR)
...@@ -216,10 +215,9 @@ class DraftInvitation(models.Model): ...@@ -216,10 +215,9 @@ class DraftInvitation(models.Model):
cited_in_publication = models.ForeignKey('journals.Publication', cited_in_publication = models.ForeignKey('journals.Publication',
on_delete=models.CASCADE, on_delete=models.CASCADE,
blank=True, null=True) blank=True, null=True)
drafted_by = models.ForeignKey(Contributor, drafted_by = models.ForeignKey('scipost.Contributor', on_delete=models.CASCADE,
on_delete=models.CASCADE,
blank=True, null=True) blank=True, null=True)
date_drafted = models.DateTimeField(default=timezone.now) date_drafted = models.DateTimeField(auto_now_add=True)
processed = models.BooleanField(default=False) processed = models.BooleanField(default=False)
def __str__(self): def __str__(self):
......
...@@ -36,10 +36,7 @@ $(document).ready(function(){ ...@@ -36,10 +36,7 @@ $(document).ready(function(){
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<h1 class="highlight">Edit a draft registration invitation</h1> <h1 class="highlight">Edit a draft registration invitation</h1>
{% if errormessage %} <form action="{% url 'scipost:edit_draft_reg_inv' draft_id=draft_inv_form.instance.id %}" method="post">
<h3 class="text-danger">{{ errormessage }}</h3>
{% endif %}
<form action="{% url 'scipost:edit_draft_reg_inv' draft_id=draft.id %}" method="post">
{% csrf_token %} {% csrf_token %}
{{draft_inv_form.media}} {{draft_inv_form.media}}
{{draft_inv_form|bootstrap}} {{draft_inv_form|bootstrap}}
......
...@@ -158,16 +158,23 @@ ...@@ -158,16 +158,23 @@
</div> </div>
<div class="col-md-4 offset-md-1"> <div class="col-md-4 offset-md-1">
{% if unavailabilities %} {% if unavailabilities %}
<h3>Your unavailability periods in our records (YYYY-DD-MM):</h3> <h3>Your unavailability periods in our records</h3>
<table class="availabilities"> <p class="text-muted">(YYYY-DD-MM)</p>
<table class="table">
<tr> <tr>
<th>Start</th> <th>Start</th>
<th>End</th> <th colspan="2">End</th>
</tr> </tr>
{% for unav in unavailabilities %} {% for unav in unavailabilities %}
<tr> <tr>
<td>{{ unav.start }}</td> <td>{{ unav.start }}</td>
<td>{{ unav.end }}</td> <td>{{ unav.end }}</td>
<td>
<form action="{% url 'scipost:delete_unavailable_period' unav.id %}" method="post">
{% csrf_token %}
<input class="btn btn-danger" type="submit" value="Delete" />
</form>
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
...@@ -198,7 +205,9 @@ ...@@ -198,7 +205,9 @@
<ul> <ul>
{% if perms.scipost.can_vet_registration_requests %} {% if perms.scipost.can_vet_registration_requests %}
<li><a href="{% url 'scipost:vet_registration_requests' %}">Vet Registration requests</a> ({{ nr_reg_to_vet }})</li> <li><a href="{% url 'scipost:vet_registration_requests' %}">Vet Registration requests</a> ({{ nr_reg_to_vet }})</li>
<li>Awaiting validation ({{ nr_reg_awaiting_validation }}) (no action necessary)</li> {% endif %}
{% if perms.scipost.can_resend_registration_requests %}
<li><a href="{% url 'scipost:registration_requests' %}">Awaiting validation</a> ({{ nr_reg_awaiting_validation }})</li>
{% endif %} {% endif %}
{% if perms.scipost.can_draft_registration_invitations %} {% if perms.scipost.can_draft_registration_invitations %}
<li><a href="{% url 'scipost:draft_registration_invitation' %}">Draft a Registration Invitation</a></li> <li><a href="{% url 'scipost:draft_registration_invitation' %}">Draft a Registration Invitation</a></li>
......
{% extends 'scipost/_personal_page_base.html' %}
{% block pagetitle %}: registration awaiting validation{% endblock pagetitle %}
{% load bootstrap %}
{% block breadcrumb_items %}
{{block.super}}
<span class="breadcrumb-item">Registration awaiting validation</span>
{% endblock %}
{% block content %}
<div class="row">
<div class="col-12">
<h1 class="highlight">Registration awaiting validation</h1>
<p>
These Contributors did not yet activate their account. Sometimes, this link is never clicked on (email is either lost to spam, or not received).<br>
As per this page, you are able to send a reminder email to the as-yet-unconfirmed contributor.
</p>
</div>
</div>
<div class="row">
<div class="col-12">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Date requested</th>
<th>Key expires</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for contributor in unactive_contributors %}
<tr>
<td>{{contributor.user.first_name}} {{contributor.user.last_name}}</td>
<td>{{contributor.user.email}}</td>
<td>{{contributor.user.date_joined|timesince}} ago</td>
<td>
{% if contributor.key_expires < now %}
<span class="text-danger">Expired {{contributor.key_expires|timesince}} ago</span>
{% else %}
Expires in {{contributor.key_expires|timeuntil}}
{% endif %}
</td>
<td>
<form action="{% url 'scipost:registration_requests_reset' contributor.id %}" method="post">
{% csrf_token %}
<input type="submit" class="btn btn-warning" value="Reset and resend" />
</form>
</td>
</tr>
{% empty %}
<tr>
<td colspan="5">All registrations have been activated.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock content %}
{% extends 'scipost/_personal_page_base.html' %}
{% block breadcrumb_items %}
{{block.super}}
<span class="breadcrumb-item">Mark a period as unavailable</span>
{% endblock %}
{% load bootstrap %}
{% block pagetitle %}: Mark a period as unavailable{% endblock pagetitle %}
{% block content %}
<div class="row">
<div class="col-lg-8 offset-lg-2">
<h1 class="highlight">Mark a period as unavailable</h1>
<form method="post">
{% csrf_token %}
{{form|bootstrap}}
<input type="submit" class="btn btn-secondary" value="Submit" />
</form>
</div>
</div>
{% endblock content %}
...@@ -84,6 +84,9 @@ urlpatterns = [ ...@@ -84,6 +84,9 @@ urlpatterns = [
views.vet_registration_requests, name='vet_registration_requests'), views.vet_registration_requests, name='vet_registration_requests'),
url(r'^vet_registration_request_ack/(?P<contributor_id>[0-9]+)$', url(r'^vet_registration_request_ack/(?P<contributor_id>[0-9]+)$',
views.vet_registration_request_ack, name='vet_registration_request_ack'), views.vet_registration_request_ack, name='vet_registration_request_ack'),
url(r'^registration_requests$', views.registration_requests, name="registration_requests"),
url(r'^registration_requests/(?P<contributor_id>[0-9]+)/reset$',
views.registration_requests_reset, name="registration_requests_reset"),
url(r'^registration_invitations/(?P<draft_id>[0-9]+)$', url(r'^registration_invitations/(?P<draft_id>[0-9]+)$',
views.registration_invitations, name="registration_invitations_from_draft"), views.registration_invitations, name="registration_invitations_from_draft"),
url(r'^registration_invitations$', url(r'^registration_invitations$',
...@@ -133,11 +136,13 @@ urlpatterns = [ ...@@ -133,11 +136,13 @@ urlpatterns = [
url(r'^update_personal_data$', views.update_personal_data, name='update_personal_data'), url(r'^update_personal_data$', views.update_personal_data, name='update_personal_data'),
# Unavailabilities # Unavailabilities
url(r'^mark_unavailable_period$', views.mark_unavailable_period, url(r'^unavailable_period$', views.mark_unavailable_period, name='mark_unavailable_period'),
name='mark_unavailable_period'), url(r'^unavailable_period/(?P<period_id>[0-9]+)/delete$', views.delete_unavailable_period,
name='delete_unavailable_period'),
# Contributor info # Contributor info
url(r'^contributor/(?P<contributor_id>[0-9]+)$', views.contributor_info, name="contributor_info"), url(r'^contributor/(?P<contributor_id>[0-9]+)$', views.contributor_info,
name="contributor_info"),
# Authorship claims # Authorship claims
url(r'^claim_authorships$', views.claim_authorships, name="claim_authorships"), url(r'^claim_authorships$', views.claim_authorships, name="claim_authorships"),
......
...@@ -7,7 +7,6 @@ from django.contrib.auth import login, logout, update_session_auth_hash ...@@ -7,7 +7,6 @@ from django.contrib.auth import login, logout, update_session_auth_hash
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.contrib.auth.views import password_reset, password_reset_confirm from django.contrib.auth.views import password_reset, password_reset_confirm
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.core import mail from django.core import mail
from django.core.mail import EmailMessage, EmailMultiAlternatives from django.core.mail import EmailMessage, EmailMultiAlternatives
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
...@@ -15,6 +14,7 @@ from django.core.urlresolvers import reverse ...@@ -15,6 +14,7 @@ from django.core.urlresolvers import reverse
from django.db.models import Q from django.db.models import Q
from django.shortcuts import redirect from django.shortcuts import redirect
from django.template import Context, Template from django.template import Context, Template
from django.views.decorators.http import require_POST
from django.views.generic.list import ListView from django.views.generic.list import ListView
from django.db.models import Prefetch from django.db.models import Prefetch
...@@ -278,6 +278,7 @@ def request_new_activation_link(request, contributor_id, key): ...@@ -278,6 +278,7 @@ def request_new_activation_link(request, contributor_id, key):
if request.GET.get('confirm', False): if request.GET.get('confirm', False):
# Generate a new email activation key and link # Generate a new email activation key and link
contributor.generate_key() contributor.generate_key()
contributor.save()
Utils.load({'contributor': contributor}, request) Utils.load({'contributor': contributor}, request)
Utils.send_new_activation_link_email() Utils.send_new_activation_link_email()
...@@ -385,6 +386,38 @@ def vet_registration_request_ack(request, contributor_id): ...@@ -385,6 +386,38 @@ def vet_registration_request_ack(request, contributor_id):
return redirect(reverse('scipost:vet_registration_requests')) return redirect(reverse('scipost:vet_registration_requests'))
@permission_required('scipost.can_resend_registration_requests', return_403=True)
def registration_requests(request):
'''
List all inactive users. These are users that have filled the registration form,
but did not yet activate their account using the validation email.
'''
unactive_contributors = (Contributor.objects.awaiting_validation()
.prefetch_related('user')
.order_by('-key_expires'))
context = {
'unactive_contributors': unactive_contributors,
'now': timezone.now()
}
return render(request, 'scipost/registration_requests.html', context)
@require_POST
@permission_required('scipost.can_resend_registration_requests', return_403=True)
def registration_requests_reset(request, contributor_id):
'''
Reset specific activation_key for Contributor and resend activation mail.
'''
contributor = get_object_or_404(Contributor.objects.awaiting_validation(), id=contributor_id)
contributor.generate_key()
contributor.save()
Utils.load({'contributor': contributor}, request)
Utils.send_new_activation_link_email()
messages.success(request, ('New key successfully generated and sent to <i>%s</i>'
% contributor.user.email))
return redirect(reverse('scipost:registration_requests'))
@permission_required('scipost.can_draft_registration_invitations', return_403=True) @permission_required('scipost.can_draft_registration_invitations', return_403=True)
def draft_registration_invitation(request): def draft_registration_invitation(request):
""" """
...@@ -392,36 +425,13 @@ def draft_registration_invitation(request): ...@@ -392,36 +425,13 @@ def draft_registration_invitation(request):
This is similar to the registration_invitations method, This is similar to the registration_invitations method,
which is used to complete the invitation process. which is used to complete the invitation process.
""" """
errormessage = '' draft_inv_form = DraftInvitationForm(request.POST or None, current_user=request.user)
if request.method == 'POST': if draft_inv_form.is_valid():
draft_inv_form = DraftInvitationForm(request.POST) invitation = draft_inv_form.save(commit=False)
Utils.load({'contributor': request.user.contributor, 'form': draft_inv_form}) invitation.drafted_by = request.user.contributor
if draft_inv_form.is_valid(): invitation.save()
if Utils.email_already_invited(): messages.success(request, 'Draft invitation saved.')
errormessage = ('DUPLICATE ERROR: ' return redirect(reverse('scipost:draft_registration_invitation'))
'This email address has already been used for an invitation')
elif Utils.email_already_drafted():
errormessage = ('DUPLICATE ERROR: '
'This email address has already been used for a draft invitation')
elif Utils.email_already_taken():
errormessage = ('DUPLICATE ERROR: '
'This email address is already associated to a Contributor')
elif (draft_inv_form.cleaned_data['invitation_type'] == 'F'
and not request.user.has_perm('scipost.can_invite_Fellows')):
errormessage = ('You do not have the authorization to send a Fellow-type '
'invitation. Consider Contributor, or cited (sub/pub). ')
elif (draft_inv_form.cleaned_data['invitation_type'] == 'R'):
errormessage = ('Referee-type invitations must be made by the Editor-in-charge '
'at the relevant Submission\'s Editorial Page. ')
else:
Utils.create_draft_invitation()
messages.success(request, 'Draft invitation saved.')
return redirect(reverse('scipost:draft_registration_invitation'))
else:
errormessage = 'The form was not filled validly.'
else:
draft_inv_form = DraftInvitationForm()
sent_reg_inv = RegistrationInvitation.objects.filter(responded=False, declined=False) sent_reg_inv = RegistrationInvitation.objects.filter(responded=False, declined=False)
sent_reg_inv_fellows = sent_reg_inv.filter(invitation_type='F').order_by('last_name') sent_reg_inv_fellows = sent_reg_inv.filter(invitation_type='F').order_by('last_name')
...@@ -445,7 +455,7 @@ def draft_registration_invitation(request): ...@@ -445,7 +455,7 @@ def draft_registration_invitation(request):
existing_drafts = DraftInvitation.objects.filter(processed=False).order_by('last_name') existing_drafts = DraftInvitation.objects.filter(processed=False).order_by('last_name')
context = { context = {
'draft_inv_form': draft_inv_form, 'errormessage': errormessage, 'draft_inv_form': draft_inv_form,
'sent_reg_inv_fellows': sent_reg_inv_fellows, 'sent_reg_inv_fellows': sent_reg_inv_fellows,
'sent_reg_inv_contrib': sent_reg_inv_contrib, 'sent_reg_inv_contrib': sent_reg_inv_contrib,
'sent_reg_inv_ref': sent_reg_inv_ref, 'sent_reg_inv_ref': sent_reg_inv_ref,
...@@ -466,23 +476,15 @@ def draft_registration_invitation(request): ...@@ -466,23 +476,15 @@ def draft_registration_invitation(request):
@permission_required('scipost.can_manage_registration_invitations', return_403=True) @permission_required('scipost.can_manage_registration_invitations', return_403=True)
def edit_draft_reg_inv(request, draft_id): def edit_draft_reg_inv(request, draft_id):
draft = get_object_or_404(DraftInvitation, id=draft_id) draft = get_object_or_404(DraftInvitation, id=draft_id)
errormessage = ''
if request.method == 'POST': draft_inv_form = DraftInvitationForm(request.POST or None, current_user=request.user,
draft_inv_form = DraftInvitationForm(request.POST) instance=draft)
if draft_inv_form.is_valid(): if draft_inv_form.is_valid():
draft.title = draft_inv_form.cleaned_data['title'] draft = draft_inv_form.save()
draft.first_name = draft_inv_form.cleaned_data['first_name'] messages.success(request, 'Draft invitation saved.')
draft.last_name = draft_inv_form.cleaned_data['last_name'] return redirect(reverse('scipost:registration_invitations'))
draft.email = draft_inv_form.cleaned_data['email']
draft.save() context = {'draft_inv_form': draft_inv_form}
return redirect(reverse('scipost:registration_invitations'))
else:
errormessage = 'The form is invalidly filled'
else:
draft_inv_form = DraftInvitationForm(instance=draft)
context = {'draft_inv_form': draft_inv_form,
'draft': draft,
'errormessage': errormessage, }
return render(request, 'scipost/edit_draft_reg_inv.html', context) return render(request, 'scipost/edit_draft_reg_inv.html', context)
...@@ -511,62 +513,38 @@ def map_draft_reg_inv_to_contributor(request, draft_id, contributor_id): ...@@ -511,62 +513,38 @@ def map_draft_reg_inv_to_contributor(request, draft_id, contributor_id):
def registration_invitations(request, draft_id=None): def registration_invitations(request, draft_id=None):
""" Overview and tools for administrators """ """ Overview and tools for administrators """
# List invitations sent; send new ones # List invitations sent; send new ones
errormessage = ''
associated_contributors = None associated_contributors = None
if request.method == 'POST': initial = {}
# Send invitation from form information if draft_id:
reg_inv_form = RegistrationInvitationForm(request.POST) # Fill draft data if draft_id given
Utils.load({'contributor': request.user.contributor, 'form': reg_inv_form}) draft = get_object_or_404(DraftInvitation, id=draft_id)
if reg_inv_form.is_valid(): associated_contributors = Contributor.objects.filter(
if Utils.email_already_invited(): user__last_name__icontains=draft.last_name)
errormessage = ('DUPLICATE ERROR: ' initial = {
'This email address has already been used for an invitation') 'title': draft.title,
elif Utils.email_already_taken(): 'first_name': draft.first_name,
errormessage = ('DUPLICATE ERROR: ' 'last_name': draft.last_name,
'This email address is already associated to a Contributor') 'email': draft.email,
elif (reg_inv_form.cleaned_data['invitation_type'] == 'F' 'invitation_type': draft.invitation_type,
and not request.user.has_perm('scipost.can_invite_Fellows')): 'cited_in_submission': draft.cited_in_submission,
errormessage = ('You do not have the authorization to send a Fellow-type ' 'cited_in_publication': draft.cited_in_publication,
'invitation. Consider Contributor, or cited (sub/pub). ') }
elif (reg_inv_form.cleaned_data['invitation_type'] == 'R'):
errormessage = ('Referee-type invitations must be made by the Editor-in-charge '
'at the relevant Submission\'s Editorial Page. ')
else:
Utils.create_invitation()
Utils.send_registration_invitation_email()
try:
draft = DraftInvitation.objects.get(
email=reg_inv_form.cleaned_data['email'])
draft.processed = True
draft.save()
except ObjectDoesNotExist:
pass
except MultipleObjectsReturned:
# Delete the first invitation
draft_to_delete = RegistrationInvitation.objects.filter(
email=reg_inv_form.cleaned_data['email']).first()
draft_to_delete.delete()
messages.success(request, 'Registration Invitation sent')
return redirect(reverse('scipost:registration_invitations'))
else:
errormessage = 'The form was not filled validly.'
else: # Send invitation from form information
initial = {} reg_inv_form = RegistrationInvitationForm(request.POST or None, initial=initial,
if draft_id: current_user=request.user)
draft = get_object_or_404(DraftInvitation, id=draft_id) if reg_inv_form.is_valid():
associated_contributors = Contributor.objects.filter( invitation = reg_inv_form.save(commit=False)
user__last_name__icontains=draft.last_name) invitation.invited_by = request.user.contributor
initial = { invitation.save()
'title': draft.title,
'first_name': draft.first_name, Utils.load({'invitation': invitation})
'last_name': draft.last_name, Utils.send_registration_invitation_email()
'email': draft.email, (DraftInvitation.objects.filter(email=reg_inv_form.cleaned_data['email'])
'invitation_type': draft.invitation_type, .update(processed=True))
'cited_in_submission': draft.cited_in_submission,
'cited_in_publication': draft.cited_in_publication, messages.success(request, 'Registration Invitation sent')
} return redirect(reverse('scipost:registration_invitations'))
reg_inv_form = RegistrationInvitationForm(initial=initial)
sent_reg_inv = RegistrationInvitation.objects.filter(responded=False, declined=False) sent_reg_inv = RegistrationInvitation.objects.filter(responded=False, declined=False)
sent_reg_inv_fellows = sent_reg_inv.filter(invitation_type='F').order_by('last_name') sent_reg_inv_fellows = sent_reg_inv.filter(invitation_type='F').order_by('last_name')
...@@ -590,7 +568,7 @@ def registration_invitations(request, draft_id=None): ...@@ -590,7 +568,7 @@ def registration_invitations(request, draft_id=None):
existing_drafts = DraftInvitation.objects.filter(processed=False).order_by('last_name') existing_drafts = DraftInvitation.objects.filter(processed=False).order_by('last_name')
context = { context = {
'reg_inv_form': reg_inv_form, 'errormessage': errormessage, 'reg_inv_form': reg_inv_form,
'sent_reg_inv_fellows': sent_reg_inv_fellows, 'sent_reg_inv_fellows': sent_reg_inv_fellows,
'sent_reg_inv_contrib': sent_reg_inv_contrib, 'sent_reg_inv_contrib': sent_reg_inv_contrib,
'sent_reg_inv_ref': sent_reg_inv_ref, 'sent_reg_inv_ref': sent_reg_inv_ref,
...@@ -758,28 +736,34 @@ def logout_view(request): ...@@ -758,28 +736,34 @@ def logout_view(request):
return redirect(reverse('scipost:index')) return redirect(reverse('scipost:index'))
@login_required
def mark_unavailable_period(request): def mark_unavailable_period(request):
if request.method == 'POST': '''
unav_form = UnavailabilityPeriodForm(request.POST) Mark period unavailable for Contributor using this view.
errormessage = None '''
if unav_form.is_valid(): unav_form = UnavailabilityPeriodForm(request.POST or None)
now = timezone.now() if unav_form.is_valid():
if unav_form.cleaned_data['start'] > unav_form.cleaned_data['end']: unav = unav_form.save(commit=False)
errormessage = 'The start date you have entered is later than the end date.' unav.contributor = request.user.contributor
elif unav_form.cleaned_data['end'] < now.date(): unav.save()
errormessage = 'You have entered an end date in the past.' messages.success(request, 'Unavailability period registered')
if errormessage is not None: return redirect('scipost:personal_page')
return render(request, 'scipost/error.html',
context={'errormessage': errormessage}) # Template acts as a backup in case the form is invalid.
else: context = {'form': unav_form}
unav = UnavailabilityPeriod( return render(request, 'scipost/unavailability_period_form.html', context)
contributor=request.user.contributor,
start=unav_form.cleaned_data['start'],
end=unav_form.cleaned_data['end']) @require_POST
unav.save() @login_required
else: def delete_unavailable_period(request, period_id):
errormessage = 'Please enter valid dates (format: YYYY-MM-DD).' '''
return render(request, 'scipost/error.html', context={'errormessage': errormessage}) Delete period unavailable registered.
'''
unav = get_object_or_404(UnavailabilityPeriod,
contributor=request.user.contributor, id=int(period_id))
unav.delete()
messages.success(request, 'Unavailability period deleted')
return redirect('scipost:personal_page') return redirect('scipost:personal_page')
...@@ -807,9 +791,9 @@ def personal_page(request): ...@@ -807,9 +791,9 @@ def personal_page(request):
# count the number of pending registration requests # count the number of pending registration requests
nr_reg_to_vet = Contributor.objects.filter(user__is_active=True, status=0).count() nr_reg_to_vet = Contributor.objects.filter(user__is_active=True, status=0).count()
nr_reg_awaiting_validation = Contributor.objects.filter( nr_reg_awaiting_validation = (Contributor.objects.awaiting_validation()
user__is_active=False, key_expires__gte=now, # .filter(key_expires__gte=now, key_expires__lte=intwodays)
key_expires__lte=intwodays, status=0).count() .count())
nr_submissions_to_assign = Submission.objects.filter(status__in=['unassigned']).count() nr_submissions_to_assign = Submission.objects.filter(status__in=['unassigned']).count()
nr_recommendations_to_prepare_for_voting = EICRecommendation.objects.filter( nr_recommendations_to_prepare_for_voting = EICRecommendation.objects.filter(
submission__status__in=['voting_in_preparation']).count() submission__status__in=['voting_in_preparation']).count()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment