diff --git a/profiles/templates/profiles/profile_list.html b/profiles/templates/profiles/profile_list.html index 3d81a3edc552838531f2e091d5ae883e17f27544..16abc13ffc2b383276887ae2ae1d71f00446bad0 100644 --- a/profiles/templates/profiles/profile_list.html +++ b/profiles/templates/profiles/profile_list.html @@ -28,17 +28,21 @@ $(document).ready(function($) { <ul> {% if nr_contributors_w_duplicate_names > 0 %} <li><a href="{% url 'scipost:contributor_duplicates' %}?kind=names">Handle Contributors with duplicate names ({{ nr_contributors_w_duplicate_names }} to handle)</a></li> + {% else %} + <li class="text-success">[No name-duplicate Contributors found]</li> {% endif %} {% if nr_contributors_w_duplicate_emails > 0 %} <li><a href="{% url 'scipost:contributor_duplicates' %}?kind=names">Handle Contributors with duplicate emails ({{ nr_contributors_w_duplicate_emails }} to handle)</a></li> + {% else %} + <li class="text-success">[No email-duplicate Contributors found]</li> {% endif %} - <li><a href="{% url 'profiles:duplicates' %}">Check for duplicate Profiles</a></li> + {% if next_contributor_wo_profile %} + <li>Create a Profile for <a href="{% url 'profiles:profile_create' from_type='contributor' pk=next_contributor_wo_profile.id %}">the next</a> Contributor without one ({{ nr_contributors_wo_profile }} to handle)</li> + {% endif %} + <li><a href="{% url 'profiles:duplicates' %}">Check for duplicate Profiles ({{ nr_potential_duplicate_profiles }} to handle)</a></li> {% if next_reginv_wo_profile %} <li>Create a Profile for <a href="{% url 'profiles:profile_create' from_type='registrationinvitation' pk=next_reginv_wo_profile.id %}">the next</a> Registration Invitation without one ({{ nr_reginv_wo_profile }} to handle)</li> {% endif %} - {% if next_contributor_wo_profile %} - <li>Create a Profile for <a href="{% url 'profiles:profile_create' from_type='contributor' pk=next_contributor_wo_profile.id %}">the next</a> Contributor without one ({{ nr_contributors_wo_profile }} to handle)</li> - {% endif %} {% if next_unreg_auth_wo_profile %} <li>Create a Profile for <a href="{% url 'profiles:profile_create' from_type='unregisteredauthor' pk=next_unreg_auth_wo_profile.id %}">the next</a> UnregisteredAuthor without one ({{ nr_unreg_auth_wo_profile }} to handle)</li> {% endif %} diff --git a/profiles/views.py b/profiles/views.py index a0fdc1f82e2db94a65291669ae95a50136a2d986..191f199ddf47ec2f48fc53e1f1410706e847412c 100644 --- a/profiles/views.py +++ b/profiles/views.py @@ -70,7 +70,7 @@ class ProfileCreateView(PermissionsMixin, CreateView): matching_profiles = matching_profiles.filter( Q(last_name=reginv.last_name) | Q(emails__email__in=reginv.email)) - context['matching_profiles'] = matching_profiles[:10] + context['matching_profiles'] = matching_profiles return context def get_initial(self): @@ -217,6 +217,7 @@ class ProfileListView(PermissionsMixin, PaginationMixin, ListView): contributors_w_duplicate_email = Contributor.objects.with_duplicate_email() contributors_w_duplicate_names = Contributor.objects.with_duplicate_names() contributors_wo_profile = Contributor.objects.active().filter(profile__isnull=True) + nr_potential_duplicate_profiles = Profile.objects.potential_duplicates().count() unreg_auth_wo_profile = UnregisteredAuthor.objects.filter(profile__isnull=True) refinv_wo_profile = RefereeInvitation.objects.filter(profile__isnull=True) reginv_wo_profile = RegistrationInvitation.objects.filter(profile__isnull=True) @@ -227,6 +228,7 @@ class ProfileListView(PermissionsMixin, PaginationMixin, ListView): 'nr_contributors_w_duplicate_email': contributors_w_duplicate_email.count(), 'nr_contributors_w_duplicate_names': contributors_w_duplicate_names.count(), 'nr_contributors_wo_profile': contributors_wo_profile.count(), + 'nr_potential_duplicate_profiles': nr_potential_duplicate_profiles, 'next_contributor_wo_profile': contributors_wo_profile.first(), 'nr_unreg_auth_wo_profile': unreg_auth_wo_profile.count(), 'next_unreg_auth_wo_profile': unreg_auth_wo_profile.first(), diff --git a/scipost/forms.py b/scipost/forms.py index 8038304fbe7531b9a47da408cd9095c407d632ae..ef72924e574b1550f45cbb399b7908005193f8ec 100644 --- a/scipost/forms.py +++ b/scipost/forms.py @@ -450,6 +450,8 @@ class ContributorMergeForm(forms.Form): contrib_from_qs.update(status=DISABLED) if contrib_from.orcid_id and not contrib_into.orcid_id: contrib_into_qs.update(orcid_id=contrib_from.orcid_id) + if contrib_from.personalwebpage and not contrib_into.personalwebpage: + contrib_into_qs.update(personalwebpage=contrib_from.personalwebpage) # Step 2: update all ForeignKey relations Affiliation.objects.filter(contributor=contrib_from).update(contributor=contrib_into) @@ -495,132 +497,106 @@ class ContributorMergeForm(forms.Form): for commentary in commentaries: commentary.authors.remove(contrib_from) commentary.authors.add(contrib_into) - commentary.save() commentaries = Commentary.objects.filter(authors_claims__in=[contrib_from,]).all() for commentary in commentaries: commentary.authors_claims.remove(contrib_from) commentary.authors_claims.add(contrib_into) - commentary.save() commentaries = Commentary.objects.filter(authors_false_claims__in=[contrib_from,]).all() for commentary in commentaries: commentary.authors_false_claims.remove(contrib_from) commentary.authors_false_claims.add(contrib_into) - commentary.save() comments = Comment.objects.filter(in_agreement__in=[contrib_from,]).all() for comment in comments: comment.in_agreement.remove(contrib_from) comment.in_agreement.add(contrib_into) - comment.save() comments = Comment.objects.filter(in_notsure__in=[contrib_from,]).all() for comment in comments: comment.in_notsure.remove(contrib_from) comment.in_notsure.add(contrib_into) - comment.save() comments = Comment.objects.filter(in_disagreement__in=[contrib_from,]).all() for comment in comments: comment.in_disagreement.remove(contrib_from) comment.in_disagreement.add(contrib_into) - comment.save() publications = Publication.objects.filter(authors_registered__in=[contrib_from,]).all() for publication in publications: publication.authors_registered.remove(contrib_from) publication.authors_registared.add(contrib_into) - publication.save() publications = Publication.objects.filter(authors_claims__in=[contrib_from,]).all() for publication in publications: publication.authors_claims.remove(contrib_from) publication.authors_claims.add(contrib_into) - publication.save() publications = Publication.objects.filter(authors_false_claims__in=[contrib_from,]).all() for publication in publications: publication.authors_false_claims.remove(contrib_from) publication.authors_false_claims.add(contrib_into) - publication.save() submissions = Submission.objects.filter(authors__in=[contrib_from,]).all() for submission in submissions: submission.authors.remove(contrib_from) submission.authors.add(contrib_into) - submission.save() submissions = Submission.objects.filter(authors_claims__in=[contrib_from,]).all() for submission in submissions: submission.authors_claims.remove(contrib_from) submission.authors_claims.add(contrib_into) - submission.save() submissions = Submission.objects.filter(authors_false_claims__in=[contrib_from,]).all() for submission in submissions: submission.authors_false_claims.remove(contrib_from) submission.authors_false_claims.add(contrib_into) - submission.save() eicrecs = EICRecommendation.objects.filter(eligible_to_vote__in=[contrib_from,]).all() for eicrec in eicrecs: eicrec.eligible_to_vote.remove(contrib_from) eicrec.eligible_to_vote.add(contrib_into) - eicrec.save() eicrecs = EICRecommendation.objects.filter(voted_for__in=[contrib_from,]).all() for eicrec in eicrecs: eicrec.voted_for.remove(contrib_from) eicrec.voted_for.add(contrib_into) - eicrec.save() eicrecs = EICRecommendation.objects.filter(voted_against__in=[contrib_from,]).all() for eicrec in eicrecs: eicrec.voted_against.remove(contrib_from) eicrec.voted_against.add(contrib_into) - eicrec.save() eicrecs = EICRecommendation.objects.filter(voted_abstain__in=[contrib_from,]).all() for eicrec in eicrecs: eicrec.voted_abstain.remove(contrib_from) eicrec.voted_abstain.add(contrib_into) - eicrec.save() thesislinks = ThesisLink.objects.filter(author_as_cont__in=[contrib_from,]).all() for tl in thesislinks: tl.author_as_cont.remove(contrib_from) tl.author_as_cont.add(contrib_into) - tl.save() thesislinks = ThesisLink.objects.filter(author_claims__in=[contrib_from,]).all() for tl in thesislinks: tl.author_claims.remove(contrib_from) tl.author_claims.add(contrib_into) - tl.save() thesislinks = ThesisLink.objects.filter(author_false_claims__in=[contrib_from,]).all() for tl in thesislinks: tl.author_false_claims.remove(contrib_from) tl.author_false_claims.add(contrib_into) - tl.save() thesislinks = ThesisLink.objects.filter(supervisor_as_cont__in=[contrib_from,]).all() for tl in thesislinks: tl.supervisor_as_cont.remove(contrib_from) tl.supervisor_as_cont.add(contrib_into) - tl.save() nominations = Nomination.objects.filter(in_agreement__in=[contrib_from,]).all() for nom in nominations: nom.in_agreement.remove(contrib_from) nom.in_agreement.add(contrib_into) - nom.save() nominations = Nomination.objects.filter(in_notsure__in=[contrib_from,]).all() for nom in nominations: nom.in_notsure.remove(contrib_from) nom.in_notsure.add(contrib_into) - nom.save() nominations = Nomination.objects.filter(in_disagreement__in=[contrib_from,]).all() for nom in nominations: nom.in_disagreement.remove(contrib_from) nom.in_disagreement.add(contrib_into) - nom.save() motions = Motion.objects.filter(in_agreement__in=[contrib_from,]).all() for nom in motions: nom.in_agreement.remove(contrib_from) nom.in_agreement.add(contrib_into) - nom.save() motions = Motion.objects.filter(in_notsure__in=[contrib_from,]).all() for nom in motions: nom.in_notsure.remove(contrib_from) nom.in_notsure.add(contrib_into) - nom.save() motions = Motion.objects.filter(in_disagreement__in=[contrib_from,]).all() for nom in motions: nom.in_disagreement.remove(contrib_from) nom.in_disagreement.add(contrib_into) - nom.save() return Contributor.objects.get(id=contrib_into.id) diff --git a/scipost/managers.py b/scipost/managers.py index 339790d2c12ee78129db7802d01717346d652f4b..54d96ac02a455f9258a6cfd8607c17a0f623e216 100644 --- a/scipost/managers.py +++ b/scipost/managers.py @@ -51,8 +51,10 @@ class ContributorQuerySet(models.QuerySet): """ Returns only potential duplicate Contributors (as identified by first and last names). + Admins and superusers are explicitly excluded. """ - contribs = self.annotate(full_name=Concat('user__last_name', 'user__first_name')) + contribs = self.active().exclude(user__is_superuser=True).exclude(user__is_staff=True + ).annotate(full_name=Concat('user__last_name', 'user__first_name')) duplicates = contribs.values('full_name').annotate( nr_count=Count('full_name')).filter(nr_count__gt=1) return contribs.filter(full_name__in=[item['full_name'] for item in duplicates] @@ -62,7 +64,8 @@ class ContributorQuerySet(models.QuerySet): """ Return Contributors having duplicate emails. """ - duplicates = self.values(lower_email=Lower('user__email')).annotate( + duplicates = self.active().exclude(user__is_superuser=True).exclude(user__is_staff=True + ).values(lower_email=Lower('user__email')).annotate( Count('id')).order_by('user__last_name').filter(id__count__gt=1) return self.annotate(lower_email=Lower('user__email') ).filter(lower_email__in=[dup['lower_email'] for dup in duplicates]) diff --git a/scipost/migrations/0017_auto_20181115_2150.py b/scipost/migrations/0017_auto_20181115_2150.py new file mode 100644 index 0000000000000000000000000000000000000000..0cb61cbe8813cb8ea31cf7c58be61e428b3174f5 --- /dev/null +++ b/scipost/migrations/0017_auto_20181115_2150.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-11-15 20:50 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('scipost', '0016_auto_20180930_1801'), + ] + + operations = [ + migrations.AlterModelOptions( + name='contributor', + options={'ordering': ['user__last_name', 'user__first_name']}, + ), + ] diff --git a/scipost/templates/scipost/contributor_duplicate_list.html b/scipost/templates/scipost/contributor_duplicate_list.html index 37f83f774f7c19595013ab75595f5ac69d9b422f..ae58665e3dc65fff6c90b73f60603e10bf23b2e3 100644 --- a/scipost/templates/scipost/contributor_duplicate_list.html +++ b/scipost/templates/scipost/contributor_duplicate_list.html @@ -1,10 +1,10 @@ -{% extends 'scipost/base.html' %} +{% extends 'profiles/base.html' %} {% load bootstrap %} {% block breadcrumb_items %} {{ block.super }} -<span class="breadcrumb-item">Duplicates</span> +<span class="breadcrumb-item">Contributor duplicates</span> {% endblock %} {% load scipost_extras %}