Added a new field name_from_draft to Person, to hold the name field equivalent as captured from drafts, in case name has been modified by the user and we're asked to remove that info under GDPR. Added history for Email, and also an origin field to capture from where we got an email address (draft name, username, meeting registration, etc.) Added a log.assertion() to Email.save() in order to ensure we don't create any email without setting origin.

- Legacy-Id: 15126
This commit is contained in:
Henrik Levkowetz 2018-05-05 12:37:15 +00:00
parent 61a16856ad
commit 37f0d141e9
3 changed files with 58 additions and 29 deletions

View file

@ -1,23 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.12 on 2018-04-26 05:17
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('person', '0002_auto_20180330_0808'),
]
operations = [
migrations.RemoveField(
model_name='person',
name='address',
),
migrations.RemoveField(
model_name='personhistory',
name='address',
),
]

View file

@ -1,21 +1,43 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.12 on 2018-04-27 06:46
# Generated by Django 1.11.12 on 2018-05-04 15:19
from __future__ import unicode_literals
import datetime
from django.conf import settings
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import ietf.utils.models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('person', '0003_auto_20180426_0517'),
('person', '0002_auto_20180330_0808'),
]
operations = [
migrations.CreateModel(
name='HistoricalEmail',
fields=[
('address', models.CharField(db_index=True, max_length=64, validators=[django.core.validators.EmailValidator()])),
('time', models.DateTimeField(blank=True, editable=False)),
('primary', models.BooleanField(default=False)),
('origin', models.CharField(default=b'', editable=False, max_length=150)),
('active', models.BooleanField(default=True)),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
'verbose_name': 'historical email',
},
),
migrations.CreateModel(
name='HistoricalPerson',
fields=[
@ -24,10 +46,10 @@ class Migration(migrations.Migration):
('name', models.CharField(db_index=True, help_text=b'Preferred form of name.', max_length=255, verbose_name=b'Full Name (Unicode)')),
('ascii', models.CharField(help_text=b'Name as rendered in ASCII (Latin, unaccented) characters.', max_length=255, verbose_name=b'Full Name (ASCII)')),
('ascii_short', models.CharField(blank=True, help_text=b'Example: A. Nonymous. Fill in this with initials and surname only if taking the initials and surname of the ASCII name above produces an incorrect initials-only form. (Blank is OK).', max_length=32, null=True, verbose_name=b'Abbreviated Name (ASCII)')),
('affiliation', models.CharField(blank=True, help_text=b'Employer, university, sponsor, etc.', max_length=255)),
('biography', models.TextField(blank=True, help_text=b'Short biography for use on leadership pages. Use plain text or reStructuredText markup.')),
('photo', models.TextField(blank=True, default=None, max_length=100)),
('photo_thumb', models.TextField(blank=True, default=None, max_length=100)),
('name_from_draft', models.CharField(editable=False, help_text=b'Name as found in a draft submission.', max_length=255, null=True, verbose_name=b'Full Name (from submission)')),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
@ -49,7 +71,30 @@ class Migration(migrations.Migration):
model_name='personhistory',
name='user',
),
migrations.RemoveField(
model_name='person',
name='address',
),
migrations.RemoveField(
model_name='person',
name='affiliation',
),
migrations.AddField(
model_name='email',
name='origin',
field=models.CharField(default=b'', editable=False, max_length=150),
),
migrations.AddField(
model_name='person',
name='name_from_draft',
field=models.CharField(editable=False, help_text=b'Name as found in a draft submission.', max_length=255, null=True, verbose_name=b'Full Name (from submission)'),
),
migrations.DeleteModel(
name='PersonHistory',
),
migrations.AddField(
model_name='historicalemail',
name='person',
field=ietf.utils.models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='person.Person'),
),
]

View file

@ -25,6 +25,7 @@ from ietf.utils.mail import send_mail_preformatted
from ietf.utils.storage import NoLocationMigrationFileSystemStorage
from ietf.utils.mail import formataddr
from ietf.person.name import unidecode_name
from ietf.utils import log
from ietf.utils.models import ForeignKey, OneToOneField
@ -39,10 +40,10 @@ class Person(models.Model):
ascii = models.CharField("Full Name (ASCII)", max_length=255, help_text="Name as rendered in ASCII (Latin, unaccented) characters.")
# The short ascii-form of the name. Also in alias table if non-null
ascii_short = models.CharField("Abbreviated Name (ASCII)", max_length=32, null=True, blank=True, help_text="Example: A. Nonymous. Fill in this with initials and surname only if taking the initials and surname of the ASCII name above produces an incorrect initials-only form. (Blank is OK).")
affiliation = models.CharField(max_length=255, blank=True, help_text="Employer, university, sponsor, etc.")
biography = models.TextField(blank=True, help_text="Short biography for use on leadership pages. Use plain text or reStructuredText markup.")
photo = models.ImageField(storage=NoLocationMigrationFileSystemStorage(), upload_to=settings.PHOTOS_DIRNAME, blank=True, default=None)
photo_thumb = models.ImageField(storage=NoLocationMigrationFileSystemStorage(), upload_to=settings.PHOTOS_DIRNAME, blank=True, default=None)
name_from_draft = models.CharField("Full Name (from submission)", null=True, max_length=255, editable=False, help_text="Name as found in a draft submission.")
def __unicode__(self):
return self.plain_name()
@ -195,7 +196,6 @@ class Person(models.Model):
ct1['href'] = urljoin(hostscheme, self.json_url())
ct1['name'] = self.name
ct1['ascii'] = self.ascii
ct1['affiliation']= self.affiliation
return ct1
class Alias(models.Model):
@ -226,12 +226,15 @@ class Alias(models.Model):
verbose_name_plural = "Aliases"
class Email(models.Model):
history = HistoricalRecords()
address = models.CharField(max_length=64, primary_key=True, validators=[validate_email])
person = ForeignKey(Person, null=True)
time = models.DateTimeField(auto_now_add=True)
primary = models.BooleanField(default=False)
origin = models.CharField(max_length=150, default='', editable=False) # User.username or Document.name
active = models.BooleanField(default=True) # Old email addresses are *not* purged, as history
# information points to persons through these
# information points to persons through these
def __unicode__(self):
return self.address or "Email object with id: %s"%self.pk
@ -275,6 +278,10 @@ class Email(models.Model):
return
return self.address
def save(self, *args, **kwargs):
if not self.origin:
log.assertion('self.origin')
super(Email, self).save(*args, **kwargs)
# "{key.id}{salt}{hash}
KEY_STRUCT = "i12s32s"