diff --git a/affiliations/__init__.py b/affiliations/__init__.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..82323b3dfc6109a67eb86b3f5207b5736e368fa2 100644 --- a/affiliations/__init__.py +++ b/affiliations/__init__.py @@ -0,0 +1 @@ +default_app_config = 'affiliations.apps.AffiliationsConfig' diff --git a/affiliations/apps.py b/affiliations/apps.py index 4be3888cf81c22bba2e2bb970420f125bb3d8e55..3b0241f47f2c626e9b2d1007395a6d85bbc807df 100644 --- a/affiliations/apps.py +++ b/affiliations/apps.py @@ -1,5 +1,13 @@ from django.apps import AppConfig +from django.db.models.signals import post_save class AffiliationsConfig(AppConfig): name = 'affiliations' + + def ready(self): + super().ready() + + from . import models, signals + post_save.connect(signals.notify_new_affiliation, + sender=models.Affiliation) diff --git a/affiliations/forms.py b/affiliations/forms.py index f7cfd8f015bab31ac84593bdbaec4e7a5ed26f20..5fc623c480c74f0134b0276d160155534806d354 100644 --- a/affiliations/forms.py +++ b/affiliations/forms.py @@ -17,6 +17,6 @@ class AffiliationMergeForm(forms.ModelForm): def save(self, commit=True): old_affiliation = self.cleaned_data['affiliation'] if commit: - old_affiliation.contributors.update(_affiliation=self.instance) + old_affiliation.contributors.update(affiliation=self.instance) old_affiliation.delete() return self.instance diff --git a/affiliations/migrations/0004_auto_20171101_2208.py b/affiliations/migrations/0004_auto_20171101_2208.py new file mode 100644 index 0000000000000000000000000000000000000000..4b85c2f77dc99947cd550ea8af9dc2872820b34c --- /dev/null +++ b/affiliations/migrations/0004_auto_20171101_2208.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-11-01 21:08 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('affiliations', '0003_auto_20171101_2022'), + ] + + operations = [ + migrations.AlterModelOptions( + name='affiliation', + options={'ordering': ['country']}, + ), + ] diff --git a/affiliations/models.py b/affiliations/models.py index f5c175605caae8f2aacc0dc1211e7bac49c580f8..97492153582d7d02f367908299852c992be70663 100644 --- a/affiliations/models.py +++ b/affiliations/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.urls import reverse from django_countries.fields import CountryField @@ -16,5 +17,12 @@ class Affiliation(models.Model): type = models.CharField(max_length=16, choices=AFFILIATION_TYPES, default=AFFILIATION_UNIVERSITY) + class Meta: + default_related_name = 'affiliations' + ordering = ['country'] + def __str__(self): - return self.name + return '{name} ({country})'.format(name=self.name, country=self.get_country_display()) + + def get_absolute_url(self): + return reverse('affiliations:affiliation_details', args=(self.object.id,)) diff --git a/affiliations/signals.py b/affiliations/signals.py new file mode 100644 index 0000000000000000000000000000000000000000..c0e02335c15e91d132934a83a4eb13c32a20585b --- /dev/null +++ b/affiliations/signals.py @@ -0,0 +1,17 @@ +from django.contrib.auth.models import User + +from notifications.models import FakeActors +from notifications.signals import notify + + +def notify_new_affiliation(sender, instance, created, **kwargs): + """ + Notify the SciPost Administration about a new Affiliation created to check it. + """ + if created: + administrators = User.objects.filter(groups__name='SciPost Administrators') + actor, __ = FakeActors.objects.get_or_create(name='A SciPost user') + for user in administrators: + notify.send(sender=sender, recipient=user, actor=actor, + verb=' created a new Affiliation instance. You may want to validate it.', + target=instance) diff --git a/affiliations/views.py b/affiliations/views.py index d31da46badc4f1d9e93977311a2a5ad546c46b3c..bae15ec4bea735dcf753bdc74920be8214923210 100644 --- a/affiliations/views.py +++ b/affiliations/views.py @@ -1,4 +1,4 @@ -from django.shortcuts import render, redirect +from django.shortcuts import redirect from django.contrib import messages from django.urls import reverse from django.views.generic.edit import UpdateView @@ -32,9 +32,6 @@ class AffiliationUpdateView(UpdateView): messages.success(self.request, 'Affiliation saved') return super().form_valid(*args, **kwargs) - def get_success_url(self): - return reverse('affiliations:affiliation_details', args=(self.object.id,)) - def merge_affiliations(request, affiliation_id): """ diff --git a/notifications/migrations/0003_fakeactors.py b/notifications/migrations/0003_fakeactors.py new file mode 100644 index 0000000000000000000000000000000000000000..d254da9d3748ba9bb62c850f48a8f3b696304b02 --- /dev/null +++ b/notifications/migrations/0003_fakeactors.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-11-01 21:08 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('notifications', '0002_auto_20171021_1821'), + ] + + operations = [ + migrations.CreateModel( + name='FakeActors', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=256)), + ], + ), + ] diff --git a/notifications/models.py b/notifications/models.py index d7d9fef894b28bc7af060517cb9d136c502f0940..4e54bf7c86e9642511b916be8a31d93e499e2a1f 100644 --- a/notifications/models.py +++ b/notifications/models.py @@ -9,6 +9,16 @@ from .constants import NOTIFICATION_TYPES from .managers import NotificationQuerySet +class FakeActors(models.Model): + """ + This Model acts as a surrogate person that either is unknown, deceased, fake, etc. etc. + """ + name = models.CharField(max_length=256) + + def __str__(self): + return self.name + + class Notification(models.Model): """ Action model describing the actor acting out a verb (on an optional diff --git a/petitions/views.py b/petitions/views.py index b702d80784f700c223fe6be5da4f6228a3955790..86c527ccc405f6270909f55622607d7cfff08f70 100644 --- a/petitions/views.py +++ b/petitions/views.py @@ -26,8 +26,8 @@ def petition(request, slug): 'first_name': request.user.first_name, 'last_name': request.user.last_name, 'email': request.user.email, - 'country_of_employment': request.user.contributor.country_of_employment, - 'affiliation': request.user.contributor.affiliation, + 'country_of_employment': request.user.contributor.affiliation.country_of_employment, + 'affiliation': request.user.contributor.affiliation.name, } form = SignPetitionForm(request.POST or None, initial=initial, petition=petition, diff --git a/proceedings/templates/partials/proceedings/description.html b/proceedings/templates/partials/proceedings/description.html index d6ae4a1161497b54bd526dbf2899ca710f1f2e3b..df878ae1e9a035ed18e496cba0653f29324030d5 100644 --- a/proceedings/templates/partials/proceedings/description.html +++ b/proceedings/templates/partials/proceedings/description.html @@ -15,7 +15,7 @@ <h3>Guest Fellows responsible for this Issue</h3> <ul> {% for fellow in proceedings.fellowships.guests %} - <li>{{ fellow.contributor.get_title_display }} {{ fellow.contributor.user.first_name }} {{ fellow.contributor.user.last_name }}{% if fellow.contributor.affiliation %}, {{ fellow.contributor.affiliation }}{% endif %}</li> + <li>{{ fellow.contributor.get_title_display }} {{ fellow.contributor.user.first_name }} {{ fellow.contributor.user.last_name }}{% if fellow.contributor.affiliation.name %}, {{ fellow.contributor.affiliation.name }}{% endif %}</li> {% endfor %} </ul> {% endif %} diff --git a/scipost/forms.py b/scipost/forms.py index 614c14f44fad3314c1e6333c434e8ad634e56d21..b0164430eff527a90985a8b5d64c007441e6ebd7 100644 --- a/scipost/forms.py +++ b/scipost/forms.py @@ -24,6 +24,7 @@ from .decorators import has_contributor from .models import Contributor, DraftInvitation, RegistrationInvitation,\ UnavailabilityPeriod, PrecookedEmail +from affiliations.models import Affiliation from common.forms import MonthYearWidget from partners.decorators import has_contact @@ -115,14 +116,17 @@ class RegistrationForm(forms.Form): 'password': self.cleaned_data['password'], 'is_active': False }) + affiliation, __ = Affiliation.objects.get_or_create( + country=self.cleaned_data['country_of_employment'], + name=self.cleaned_data['affiliation'], + ) contributor, new = Contributor.objects.get_or_create(**{ 'user': user, 'invitation_key': self.cleaned_data.get('invitation_key', ''), 'title': self.cleaned_data['title'], 'orcid_id': self.cleaned_data['orcid_id'], - 'country_of_employment': self.cleaned_data['country_of_employment'], 'address': self.cleaned_data['address'], - 'affiliation': self.cleaned_data['affiliation'], + 'affiliation': affiliation, 'personalwebpage': self.cleaned_data['personalwebpage'], }) @@ -257,39 +261,47 @@ class UpdateUserDataForm(forms.ModelForm): class UpdatePersonalDataForm(forms.ModelForm): + country_of_employment = LazyTypedChoiceField(choices=countries, widget=CountrySelectWidget()) + affiliation = forms.CharField(max_length=300) + class Meta: model = Contributor - fields = ['title', 'discipline', 'expertises', 'orcid_id', 'country_of_employment', - 'affiliation', 'address', 'personalwebpage' - ] - widgets = {'country_of_employment': CountrySelectWidget()} + fields = [ + 'title', + 'discipline', + 'expertises', + 'orcid_id', + 'address', + 'personalwebpage' + ] - # def __init__(self, *args, **kwargs): - # super().__init__(*args, **kwargs) - # self.fields['mail_subscription'] = forms.ModelMultipleChoiceField( - # queryset=MailchimpList.objects.open_to_subscribe(kwargs['instance']).distinct(), - # widget=forms.CheckboxSelectMultiple(), - # label='Subscribe to the following mailing lists:', - # required=False) - # self.fields['mailing_lists'] = forms.ModelMultipleChoiceField( - # queryset=MailchimpList.objects.open_to_subscribe(kwargs['instance']).distinct(), - # widget=forms.CheckboxSelectMultiple(), - # label='Subscribe to the following mailing lists:', - # required=False) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['country_of_employment'].initial = self.instance.affiliation.country + self.fields['affiliation'].initial = self.instance.affiliation.name + + def save(self, commit=True): + contributor = super().save(commit) + if commit: + if contributor.affiliation.contributors.count() == 1: + # Just update if there are no other people using this Affiliation + affiliation = contributor.affiliation + affiliation.name = self.cleaned_data['affiliation'] + affiliation.country = self.cleaned_data['country_of_employment'] + affiliation.save() + else: + affiliation, __ = Affiliation.objects.get_or_create( + name=self.cleaned_data['affiliation'], + country=self.cleaned_data['country_of_employment']) + contributor.affiliation = affiliation + contributor.save() + return contributor def sync_lists(self): + """ + Pseudo U/S; do not remove + """ return - # contributor = self.instance - # original_lists = list(self.fields['mailing_lists'].queryset) - # - # # Subscribe to lists - # for _list in self.cleaned_data['mailing_lists']: - # _list.update_membership([contributor]) - # original_lists.remove(_list) - # - # # Unsubscribe from the leftovers - # for _list in original_lists: - # _list.update_membership([contributor], status='unsubscribed') def propagate_orcid(self): """ diff --git a/scipost/migrations/0067_auto_20171101_2132.py b/scipost/migrations/0067_auto_20171101_2132.py new file mode 100644 index 0000000000000000000000000000000000000000..a202ec2ae8d6b264c5c6aec50d234aa31c718eda --- /dev/null +++ b/scipost/migrations/0067_auto_20171101_2132.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-11-01 20:32 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('scipost', '0066_contributor__affiliation'), + ] + + operations = [ + migrations.RenameField( + model_name='contributor', + old_name='affiliation', + new_name='old_affiliation', + ), + migrations.RenameField( + model_name='contributor', + old_name='country_of_employment', + new_name='old_country_of_employment', + ), + migrations.AlterField( + model_name='contributor', + name='_affiliation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='contributors', to='affiliations.Affiliation'), + ), + ] diff --git a/scipost/migrations/0068_auto_20171101_2132.py b/scipost/migrations/0068_auto_20171101_2132.py new file mode 100644 index 0000000000000000000000000000000000000000..f59223bee41208b98d73e363ccea8ab890db2be7 --- /dev/null +++ b/scipost/migrations/0068_auto_20171101_2132.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-11-01 20:32 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('scipost', '0067_auto_20171101_2132'), + ] + + operations = [ + migrations.RenameField( + model_name='contributor', + old_name='_affiliation', + new_name='affiliation', + ), + ] diff --git a/scipost/models.py b/scipost/models.py index 3b03789c2e45f609bf91e1780cedfe7a5b45f7ae..813cb7cafdea95ea4344a8d228e94015a796a50f 100644 --- a/scipost/models.py +++ b/scipost/models.py @@ -50,10 +50,10 @@ class Contributor(models.Model): blank=True, null=True) orcid_id = models.CharField(max_length=20, verbose_name="ORCID id", blank=True) - country_of_employment = CountryField() - affiliation = models.CharField(max_length=300, verbose_name='affiliation') - _affiliation = models.ForeignKey('affiliations.Affiliation', null=True, blank=True, - related_name='contributors') + old_country_of_employment = CountryField() + old_affiliation = models.CharField(max_length=300, verbose_name='affiliation') + affiliation = models.ForeignKey('affiliations.Affiliation', null=True, blank=True, + related_name='contributors') address = models.CharField(max_length=1000, verbose_name="address", blank=True) personalwebpage = models.URLField(verbose_name='personal web page', diff --git a/scipost/templates/scipost/_private_info_as_table.html b/scipost/templates/scipost/_private_info_as_table.html index 04d525681719b0e696584c1584c9baeaaa12d04b..e8fc45a526e8990e585abc8ec624290d102d5308 100644 --- a/scipost/templates/scipost/_private_info_as_table.html +++ b/scipost/templates/scipost/_private_info_as_table.html @@ -5,8 +5,8 @@ <tr><td>Email: </td><td> </td><td>{{ contributor.user.email }}</td></tr> <tr><td>ORCID id: </td><td> </td><td>{{ contributor.orcid_id }}</td></tr> <tr><td>Country of employment: </td><td> </td> - <td>{{ contributor.country_of_employment.name }}</td></tr> - <tr><td>Affiliation: </td><td> </td><td>{{ contributor.affiliation }}</td></tr> + <td>{{ contributor.affiliation.get_country_display }}</td></tr> + <tr><td>Affiliation: </td><td> </td><td>{{ contributor.affiliation.name }}</td></tr> <tr><td>Address: </td><td> </td><td>{{ contributor.address }}</td></tr> <tr><td>Personal web page: </td><td> </td><td>{{ contributor.personalwebpage }}</td></tr> <tr><td>Accept SciPost emails: </td><td> </td><td>{{ contributor.accepts_SciPost_emails }}</td></tr> diff --git a/scipost/templates/scipost/_public_info_as_table.html b/scipost/templates/scipost/_public_info_as_table.html index e41461ee178b3bdd9e01b9b0ba92804abf6b04ca..0b141e6b260a2e08880791bc6555a13d95d9dd4b 100644 --- a/scipost/templates/scipost/_public_info_as_table.html +++ b/scipost/templates/scipost/_public_info_as_table.html @@ -3,7 +3,7 @@ <tr><td>First name: </td><td> </td><td>{{ contributor.user.first_name }}</td></tr> <tr><td>Last name: </td><td> </td><td>{{ contributor.user.last_name }}</td></tr> <tr><td>ORCID id: </td><td> </td><td>{{ contributor.orcid_id|default:'-' }}</td></tr> - <tr><td>Country of employment: </td><td> </td><td>{{ contributor.country_of_employment.name|default:'-'}}</td></tr> - <tr><td>Affiliation: </td><td> </td><td>{{ contributor.affiliation|default:'-' }}</td></tr> + <tr><td>Country of employment: </td><td> </td><td>{{ contributor.affiliation.get_country_display|default:'-'}}</td></tr> + <tr><td>Affiliation: </td><td> </td><td>{{ contributor.affiliation.name|default:'-' }}</td></tr> <tr><td>Personal web page: </td><td> </td><td>{{ contributor.personalwebpage|default:'-' }}</td></tr> </table> diff --git a/submissions/templates/submissions/_report_tex_template.html b/submissions/templates/submissions/_report_tex_template.html index ceb16ce3c1644e379d0b935a45f29b7034851fc6..264dbc3a367163d594c6c1cc759e570a9325fb8b 100644 --- a/submissions/templates/submissions/_report_tex_template.html +++ b/submissions/templates/submissions/_report_tex_template.html @@ -48,7 +48,7 @@ Report by {% if report.anonymous %}Anonymous{% else %}{{report.author.user.first \begin{center} %%%%%%%%%% AFFILIATIONS -{\bf 1} {{report.author.affiliation}}\\ +{\bf 1} {{report.author.affiliation.name}}\\ \end{center} {% endif %}