SciPost Code Repository

Skip to content
Snippets Groups Projects
Commit 4c840cad authored by George Katsikas's avatar George Katsikas :goat:
Browse files

refactor: :recycle:️ add profile orcid unique constraint

parent daded0b3
No related branches found
No related tags found
No related merge requests found
# Generated by Django 5.0.12 on 2025-02-25 08:49
import django.core.validators
from django.db import migrations, models
def blank_to_null(apps, schema_editor):
Profile = apps.get_model("profiles", "Profile")
Profile.objects.filter(orcid_id="").update(orcid_id=None)
def null_to_blank(apps, schema_editor):
Profile = apps.get_model("profiles", "Profile")
Profile.objects.filter(orcid_id=None).update(orcid_id="")
class Migration(migrations.Migration):
dependencies = [
("ontology", "0009_populate_specialty_topics"),
("profiles", "0043_alter_profile_first_name_original_and_more"),
]
operations = [
migrations.AlterField(
model_name="profile",
name="orcid_id",
field=models.CharField(
blank=True,
max_length=20,
null=True,
validators=[
django.core.validators.RegexValidator(
"^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X]{1}$",
"Please follow the ORCID format, e.g.: 0000-0001-2345-6789",
)
],
verbose_name="ORCID id",
),
),
migrations.RunPython(blank_to_null, null_to_blank),
migrations.AddConstraint(
model_name="profile",
constraint=models.UniqueConstraint(
condition=models.Q(("orcid_id__isnull", False)),
fields=("orcid_id",),
name="unique_orcid_id",
violation_error_message="ORCID id must be unique across all profiles.",
),
),
migrations.AddConstraint(
model_name="profile",
constraint=models.CheckConstraint(
check=models.Q(
("orcid_id__isnull", True),
(
"orcid_id__regex",
"^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X]{1}$",
),
_connector="OR",
),
name="orcid_id_format",
violation_error_message="ORCID id must be of the form 'XXXX-XXXX-XXXX-XXXY', where X is a digit and Y is a digit or 'X'.",
),
),
]
......@@ -99,7 +99,11 @@ class Profile(models.Model):
orcid_authenticated = models.BooleanField(default=False)
orcid_id = models.CharField(
max_length=20, verbose_name="ORCID id", blank=True, validators=[orcid_validator]
max_length=20,
verbose_name="ORCID id",
blank=True,
null=True,
validators=[orcid_validator],
)
webpage = models.URLField(max_length=300, blank=True)
......@@ -132,6 +136,21 @@ class Profile(models.Model):
class Meta:
ordering = ["last_name", "first_name"]
constraints = [
models.UniqueConstraint(
fields=["orcid_id"],
name="unique_orcid_id",
condition=Q(orcid_id__isnull=False),
violation_error_message="ORCID id must be unique across all profiles.",
),
models.CheckConstraint(
check=Q(orcid_id__isnull=True)
| Q(orcid_id__regex=r"^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X]{1}$"),
name="orcid_id_format",
violation_error_message="ORCID id must be of the form 'XXXX-XXXX-XXXX-XXXY', "
"where X is a digit and Y is a digit or 'X'.",
),
]
def __str__(self):
return "%s, %s %s" % (
......@@ -168,7 +187,7 @@ class Profile(models.Model):
self.last_name,
self.get_title_display() if self.title != None else "",
self.first_name,
f' ({",".join(r)})' if r else "",
f" ({','.join(r)})" if r else "",
)
@property
......
......@@ -5,6 +5,7 @@ __license__ = "AGPL v3"
import datetime
import bleach
from django.db.models import Q
from django.utils.html import format_html
import pyotp
import re
......@@ -277,6 +278,17 @@ class RegistrationForm(forms.Form):
self.add_error("email", "This email address is already in use")
return self.cleaned_data.get("email", "")
def clean_orcid_id(self):
orcid_id = self.cleaned_data.get("orcid_id", "")
if orcid_id and Profile.objects.filter(orcid_id=orcid_id).exists():
error_message = format_html(
"This ORCID id is already in use. Have you already registered?"
"<a href='/password_reset/'>Reset your password</a> or "
"<a href='mailto:techsupport@scipost.org'>contact tech support</a>."
)
self.add_error("orcid_id", error_message)
return orcid_id
def create_and_save_contributor(self):
user = User.objects.create_user(
**{
......@@ -471,6 +483,16 @@ class UpdatePersonalDataForm(forms.ModelForm):
self.instance.profile.specialties.set(self.cleaned_data["specialties"])
return super().save()
def clean_orcid_id(self):
orcid_id = self.cleaned_data.get("orcid_id", "")
if orcid_id and Profile.objects.filter(orcid_id=orcid_id).exists():
error_message = format_html(
"This ORCID id is already in use by another member. Is it yours? "
"<a href='mailto:techsupport@scipost.org'>Contact tech support</a>."
)
self.add_error("orcid_id", error_message)
return orcid_id
def sync_lists(self):
"""
Pseudo U/S; do not remove
......
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