Added django-simple-history and replaced the old (and unused) PersonHistory class with a history=HistoricalRecords() field on Person. Added the needed migrations and changes to admin, resources, and settings. Related to issues #2505 and #2507.
- Legacy-Id: 15096
This commit is contained in:
parent
53c4ac36db
commit
c7d31b44c3
|
@ -7,7 +7,7 @@ import debug # pyflakes:ignore
|
|||
from ietf.utils.test_utils import TestCase
|
||||
from ietf.doc.models import StateType
|
||||
|
||||
class StateHelpTest(TestCase):
|
||||
class HelpPageTests(TestCase):
|
||||
|
||||
def test_state_index(self):
|
||||
url = reverse('ietf.help.views.state_index')
|
||||
|
@ -21,3 +21,7 @@ class StateHelpTest(TestCase):
|
|||
self.assertIn(name, content)
|
||||
|
||||
|
||||
def test_personal_information_help(self):
|
||||
r = self.client.get('/help/personal-information')
|
||||
self.assertContains(r, 'personal information')
|
||||
self.assertContains(r, 'GDPR')
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.contrib import admin
|
||||
|
||||
|
||||
from ietf.person.models import Email, Alias, Person, PersonHistory, PersonalApiKey, PersonEvent, PersonApiKeyEvent
|
||||
from ietf.person.models import Email, Alias, Person, PersonalApiKey, PersonEvent, PersonApiKeyEvent, HistoricalPerson
|
||||
from ietf.person.name import name_parts
|
||||
|
||||
class EmailAdmin(admin.ModelAdmin):
|
||||
|
@ -33,16 +33,6 @@ class PersonAdmin(admin.ModelAdmin):
|
|||
# actions = None
|
||||
admin.site.register(Person, PersonAdmin)
|
||||
|
||||
class PersonHistoryAdmin(admin.ModelAdmin):
|
||||
def plain_name(self, obj):
|
||||
prefix, first, middle, last, suffix = name_parts(obj.name)
|
||||
return "%s %s" % (first, last)
|
||||
list_display = ['name', 'short', 'plain_name', 'time', 'user', 'person', ]
|
||||
list_filter = ['time']
|
||||
raw_id_fields = ['person', 'user']
|
||||
search_fields = ['name', 'ascii']
|
||||
admin.site.register(PersonHistory, PersonHistoryAdmin)
|
||||
|
||||
class PersonalApiKeyAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'person', 'created', 'endpoint', 'valid', 'count', 'latest', ]
|
||||
list_filter = ['endpoint', 'created', ]
|
||||
|
@ -61,3 +51,14 @@ class PersonApiKeyEventAdmin(admin.ModelAdmin):
|
|||
search_fields = ["person__name", ]
|
||||
raw_id_fields = ['person', ]
|
||||
admin.site.register(PersonApiKeyEvent, PersonApiKeyEventAdmin)
|
||||
|
||||
|
||||
class HistoricalPersonAdmin(admin.ModelAdmin):
|
||||
def plain_name(self, obj):
|
||||
prefix, first, middle, last, suffix = name_parts(obj.name)
|
||||
return "%s %s" % (first, last)
|
||||
list_display = ["history_date", "name", "plain_name", "time", "history_user", "history_change_reason", ]
|
||||
search_fields = ["name", "ascii"]
|
||||
raw_id_fields = ["user", "history_user", ]
|
||||
# actions = None
|
||||
admin.site.register(HistoricalPerson, HistoricalPersonAdmin)
|
||||
|
|
55
ietf/person/migrations/0004_auto_20180427_0646.py
Normal file
55
ietf/person/migrations/0004_auto_20180427_0646.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.12 on 2018-04-27 06:46
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('person', '0003_auto_20180426_0517'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='HistoricalPerson',
|
||||
fields=[
|
||||
('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('time', models.DateTimeField(default=datetime.datetime.now)),
|
||||
('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)),
|
||||
('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)),
|
||||
('user', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': 'history_date',
|
||||
'verbose_name': 'historical person',
|
||||
},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='personhistory',
|
||||
name='person',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='personhistory',
|
||||
name='user',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='PersonHistory',
|
||||
),
|
||||
]
|
|
@ -16,6 +16,7 @@ from django.db import models
|
|||
from django.contrib.auth.models import User
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.text import slugify
|
||||
from simple_history.models import HistoricalRecords
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
|
@ -27,7 +28,9 @@ from ietf.person.name import unidecode_name
|
|||
from ietf.utils.models import ForeignKey, OneToOneField
|
||||
|
||||
|
||||
class PersonInfo(models.Model):
|
||||
class Person(models.Model):
|
||||
history = HistoricalRecords()
|
||||
user = OneToOneField(User, blank=True, null=True)
|
||||
time = models.DateTimeField(default=datetime.datetime.now) # When this Person record entered the system
|
||||
# The normal unicode form of the name. This must be
|
||||
# set to the same value as the ascii-form if equal.
|
||||
|
@ -143,24 +146,21 @@ class PersonInfo(models.Model):
|
|||
def has_drafts(self):
|
||||
from ietf.doc.models import Document
|
||||
return Document.objects.filter(documentauthor__person=self, type='draft').exists()
|
||||
|
||||
def rfcs(self):
|
||||
from ietf.doc.models import Document
|
||||
rfcs = list(Document.objects.filter(documentauthor__person=self, type='draft', states__slug='rfc'))
|
||||
rfcs.sort(key=lambda d: d.canonical_name() )
|
||||
return rfcs
|
||||
|
||||
def active_drafts(self):
|
||||
from ietf.doc.models import Document
|
||||
return Document.objects.filter(documentauthor__person=self, type='draft', states__slug='active').order_by('-time')
|
||||
|
||||
def expired_drafts(self):
|
||||
from ietf.doc.models import Document
|
||||
return Document.objects.filter(documentauthor__person=self, type='draft', states__slug__in=['repl', 'expired', 'auth-rm', 'ietf-rm']).order_by('-time')
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
class Person(PersonInfo):
|
||||
user = OneToOneField(User, blank=True, null=True)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
created = not self.pk
|
||||
super(Person, self).save(*args, **kwargs)
|
||||
|
@ -198,10 +198,6 @@ class Person(PersonInfo):
|
|||
ct1['affiliation']= self.affiliation
|
||||
return ct1
|
||||
|
||||
class PersonHistory(PersonInfo):
|
||||
person = ForeignKey(Person, related_name="history_set")
|
||||
user = ForeignKey(User, blank=True, null=True)
|
||||
|
||||
class Alias(models.Model):
|
||||
"""This is used for alternative forms of a name. This is the
|
||||
primary lookup point for names, and should always contain the
|
||||
|
|
|
@ -6,7 +6,7 @@ from tastypie.cache import SimpleCache
|
|||
|
||||
from ietf import api
|
||||
|
||||
from ietf.person.models import (Person, Email, Alias, PersonHistory, PersonalApiKey, PersonEvent, PersonApiKeyEvent)
|
||||
from ietf.person.models import (Person, Email, Alias, PersonalApiKey, PersonEvent, PersonApiKeyEvent, HistoricalPerson)
|
||||
|
||||
|
||||
from ietf.utils.resources import UserResource
|
||||
|
@ -24,7 +24,6 @@ class PersonResource(ModelResource):
|
|||
"name": ALL,
|
||||
"ascii": ALL,
|
||||
"ascii_short": ALL,
|
||||
"address": ALL,
|
||||
"affiliation": ALL,
|
||||
"photo": ALL,
|
||||
"biography": ALL,
|
||||
|
@ -61,29 +60,6 @@ class AliasResource(ModelResource):
|
|||
}
|
||||
api.person.register(AliasResource())
|
||||
|
||||
from ietf.utils.resources import UserResource
|
||||
class PersonHistoryResource(ModelResource):
|
||||
person = ToOneField(PersonResource, 'person')
|
||||
user = ToOneField(UserResource, 'user', null=True)
|
||||
class Meta:
|
||||
cache = SimpleCache()
|
||||
queryset = PersonHistory.objects.all()
|
||||
serializer = api.Serializer()
|
||||
#resource_name = 'personhistory'
|
||||
filtering = {
|
||||
"id": ALL,
|
||||
"time": ALL,
|
||||
"name": ALL,
|
||||
"ascii": ALL,
|
||||
"ascii_short": ALL,
|
||||
"address": ALL,
|
||||
"affiliation": ALL,
|
||||
"person": ALL_WITH_RELATIONS,
|
||||
"user": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.person.register(PersonHistoryResource())
|
||||
|
||||
|
||||
class PersonalApiKeyResource(ModelResource):
|
||||
person = ToOneField(PersonResource, 'person')
|
||||
class Meta:
|
||||
|
@ -141,3 +117,32 @@ class PersonApiKeyEventResource(ModelResource):
|
|||
"key": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.person.register(PersonApiKeyEventResource())
|
||||
|
||||
|
||||
from ietf.utils.resources import UserResource
|
||||
class HistoricalPersonResource(ModelResource):
|
||||
user = ToOneField(UserResource, 'user', null=True)
|
||||
history_user = ToOneField(UserResource, 'history_user', null=True)
|
||||
class Meta:
|
||||
queryset = HistoricalPerson.objects.all()
|
||||
serializer = api.Serializer()
|
||||
cache = SimpleCache()
|
||||
#resource_name = 'historicalperson'
|
||||
filtering = {
|
||||
"id": ALL,
|
||||
"time": ALL,
|
||||
"name": ALL,
|
||||
"ascii": ALL,
|
||||
"ascii_short": ALL,
|
||||
"affiliation": ALL,
|
||||
"biography": ALL,
|
||||
"photo": ALL,
|
||||
"photo_thumb": ALL,
|
||||
"history_id": ALL,
|
||||
"history_date": ALL,
|
||||
"history_change_reason": ALL,
|
||||
"history_type": ALL,
|
||||
"user": ALL_WITH_RELATIONS,
|
||||
"history_user": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.person.register(HistoricalPersonResource())
|
||||
|
|
|
@ -349,6 +349,7 @@ MIDDLEWARE = (
|
|||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.http.ConditionalGetMiddleware',
|
||||
'simple_history.middleware.HistoryRequestMiddleware',
|
||||
# 'ietf.middleware.sql_log_middleware',
|
||||
'ietf.middleware.SMTPExceptionMiddleware',
|
||||
'ietf.middleware.Utf8ExceptionMiddleware',
|
||||
|
@ -385,6 +386,7 @@ INSTALLED_APPS = (
|
|||
'django_password_strength',
|
||||
'djangobwr',
|
||||
'form_utils',
|
||||
'simple_history',
|
||||
'tastypie',
|
||||
'widget_tweaks',
|
||||
# IETF apps
|
||||
|
|
|
@ -16,6 +16,7 @@ django-bootstrap3>=8.2.1,<9.0.0
|
|||
django-formtools>=1.0 # instead of django.contrib.formtools in 1.8
|
||||
django-markup>=1.1
|
||||
django-password-strength>=1.2.1
|
||||
django-simple-history>=2.0
|
||||
django-tastypie>=0.13.2
|
||||
django-widget-tweaks>=1.3
|
||||
docutils>=0.12
|
||||
|
|
Loading…
Reference in a new issue