Add person, affiliation and country (through django-countries) to
DocumentAuthor, rename author field to email and make it optional (for modeling old email-less submissions), remove the authors many to many referencing field from Document as it is not really pointing the right place. Update the Secretariat tools to show affiliation and country. Add migration for getting rid of the fake email addresses that the migration script created some years ago (just set the author email field to null). - Legacy-Id: 12739
This commit is contained in:
parent
e381dac958
commit
9308948195
|
@ -212,9 +212,9 @@ class ToOneField(tastypie.fields.ToOneField):
|
|||
if not foreign_obj:
|
||||
if not self.null:
|
||||
if callable(self.attribute):
|
||||
raise ApiFieldError("The related resource for resource %s could not be found." % (previous_obj))
|
||||
raise ApiFieldError(u"The related resource for resource %s could not be found." % (previous_obj))
|
||||
else:
|
||||
raise ApiFieldError("The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (previous_obj, attr))
|
||||
raise ApiFieldError(u"The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (previous_obj, attr))
|
||||
return None
|
||||
|
||||
fk_resource = self.get_related_resource(foreign_obj)
|
||||
|
|
|
@ -66,7 +66,7 @@ if "<" in from_email:
|
|||
|
||||
submission = Submission.objects.filter(name=draft).latest('submission_date')
|
||||
document = Document.objects.get(name=draft)
|
||||
emails = [ author.address for author in document.authors.all() ]
|
||||
emails = [ author.email.address for author in document.documentauthor_set.all() if author.email ]
|
||||
|
||||
timestrings = []
|
||||
for file in [ Path(settings.INTERNET_DRAFT_PATH) / ("%s-%s.txt"%(draft, submission.rev)),
|
||||
|
|
|
@ -65,7 +65,7 @@ def get_draft_authors_emails(draft):
|
|||
" Get list of authors for the given draft."
|
||||
|
||||
# This feels 'correct'; however, it creates fairly large delta
|
||||
return [email.email_address() for email in draft.authors.all()]
|
||||
return [author.email.email_address() for author in draft.documentauthor_set.all() if author.email.email_address()]
|
||||
|
||||
# This gives fairly small delta compared to current state,
|
||||
# however, it seems to be wrong (doesn't check for emails being
|
||||
|
|
|
@ -57,7 +57,7 @@ def port_rules_to_typed_system(apps, schema_editor):
|
|||
|
||||
|
||||
elif rule.rule_type in ["author", "author_rfc"]:
|
||||
found_persons = list(try_to_uniquify_person(rule, Person.objects.filter(email__documentauthor__id__gte=1).filter(name__icontains=rule.value).distinct()))
|
||||
found_persons = list(try_to_uniquify_person(rule, Person.objects.filter(documentauthor__id__gte=1).filter(name__icontains=rule.value).distinct()))
|
||||
|
||||
if found_persons:
|
||||
rule.person = found_persons[0]
|
||||
|
|
|
@ -31,7 +31,7 @@ class CommunityListTests(TestCase):
|
|||
|
||||
rule_state_iesg = SearchRule.objects.create(rule_type="state_iesg", state=State.objects.get(type="draft-iesg", slug="lc"), community_list=clist)
|
||||
|
||||
rule_author = SearchRule.objects.create(rule_type="author", state=State.objects.get(type="draft", slug="active"), person=Person.objects.filter(email__documentauthor__document=draft).first(), community_list=clist)
|
||||
rule_author = SearchRule.objects.create(rule_type="author", state=State.objects.get(type="draft", slug="active"), person=Person.objects.filter(documentauthor__document=draft).first(), community_list=clist)
|
||||
|
||||
rule_ad = SearchRule.objects.create(rule_type="ad", state=State.objects.get(type="draft", slug="active"), person=draft.ad, community_list=clist)
|
||||
|
||||
|
@ -113,7 +113,7 @@ class CommunityListTests(TestCase):
|
|||
r = self.client.post(url, {
|
||||
"action": "add_rule",
|
||||
"rule_type": "author_rfc",
|
||||
"author_rfc-person": Person.objects.filter(email__documentauthor__document=draft).first().pk,
|
||||
"author_rfc-person": Person.objects.filter(documentauthor__document=draft).first().pk,
|
||||
"author_rfc-state": State.objects.get(type="draft", slug="rfc").pk,
|
||||
})
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
|
|
@ -88,7 +88,7 @@ def docs_matching_community_list_rule(rule):
|
|||
elif rule.rule_type.startswith("state_"):
|
||||
return docs.filter(states=rule.state)
|
||||
elif rule.rule_type in ["author", "author_rfc"]:
|
||||
return docs.filter(states=rule.state, documentauthor__author__person=rule.person)
|
||||
return docs.filter(states=rule.state, documentauthor__person=rule.person)
|
||||
elif rule.rule_type == "ad":
|
||||
return docs.filter(states=rule.state, ad=rule.person)
|
||||
elif rule.rule_type == "shepherd":
|
||||
|
@ -121,7 +121,7 @@ def community_list_rules_matching_doc(doc):
|
|||
rules |= SearchRule.objects.filter(
|
||||
rule_type__in=["author", "author_rfc"],
|
||||
state__in=states,
|
||||
person__in=list(Person.objects.filter(email__documentauthor__document=doc)),
|
||||
person__in=list(Person.objects.filter(documentauthor__document=doc)),
|
||||
)
|
||||
|
||||
if doc.ad_id:
|
||||
|
|
|
@ -25,7 +25,7 @@ class DocAliasInline(admin.TabularInline):
|
|||
|
||||
class DocAuthorInline(admin.TabularInline):
|
||||
model = DocumentAuthor
|
||||
raw_id_fields = ['author', ]
|
||||
raw_id_fields = ['person', 'email']
|
||||
extra = 1
|
||||
|
||||
class RelatedDocumentInline(admin.TabularInline):
|
||||
|
@ -99,7 +99,7 @@ class DocumentAdmin(admin.ModelAdmin):
|
|||
list_display = ['name', 'rev', 'group', 'pages', 'intended_std_level', 'author_list', 'time']
|
||||
search_fields = ['name']
|
||||
list_filter = ['type']
|
||||
raw_id_fields = ['authors', 'group', 'shepherd', 'ad']
|
||||
raw_id_fields = ['group', 'shepherd', 'ad']
|
||||
inlines = [DocAliasInline, DocAuthorInline, RelatedDocumentInline, ]
|
||||
form = DocumentForm
|
||||
|
||||
|
@ -121,7 +121,7 @@ class DocHistoryAdmin(admin.ModelAdmin):
|
|||
list_display = ['doc', 'rev', 'state', 'group', 'pages', 'intended_std_level', 'author_list', 'time']
|
||||
search_fields = ['doc__name']
|
||||
ordering = ['time', 'doc', 'rev']
|
||||
raw_id_fields = ['doc', 'authors', 'group', 'shepherd', 'ad']
|
||||
raw_id_fields = ['doc', 'group', 'shepherd', 'ad']
|
||||
|
||||
def state(self, instance):
|
||||
return instance.get_state()
|
||||
|
@ -174,7 +174,7 @@ class BallotPositionDocEventAdmin(DocEventAdmin):
|
|||
admin.site.register(BallotPositionDocEvent, BallotPositionDocEventAdmin)
|
||||
|
||||
class DocumentAuthorAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'document', 'author', 'order']
|
||||
search_fields = [ 'document__name', 'author__address', ]
|
||||
list_display = ['id', 'document', 'person', 'email', 'order']
|
||||
search_fields = [ 'document__name', 'person__name', 'email__address', ]
|
||||
admin.site.register(DocumentAuthor, DocumentAuthorAdmin)
|
||||
|
||||
|
|
|
@ -46,8 +46,8 @@ class DocumentFactory(factory.DjangoModelFactory):
|
|||
def authors(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument
|
||||
if create and extracted:
|
||||
order = 0
|
||||
for email in extracted:
|
||||
DocumentAuthor.objects.create(document=obj, author=email, order=order)
|
||||
for person in extracted:
|
||||
DocumentAuthor.objects.create(document=obj, person=person, order=order)
|
||||
order += 1
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_countries.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
@ -32,4 +33,84 @@ class Migration(migrations.Migration):
|
|||
name='formal_languages',
|
||||
field=models.ManyToManyField(help_text=b'Formal languages used in document', to='name.FormalLanguageName', blank=True),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='dochistory',
|
||||
name='authors',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='document',
|
||||
name='authors',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='dochistoryauthor',
|
||||
name='affiliation',
|
||||
field=models.CharField(help_text=b'Organization/company used by author for submission', max_length=100, blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='dochistoryauthor',
|
||||
name='country',
|
||||
field=django_countries.fields.CountryField(blank=True, help_text=b'Country used by author for submission', max_length=2),
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='dochistoryauthor',
|
||||
old_name='author',
|
||||
new_name='email',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='dochistoryauthor',
|
||||
name='email',
|
||||
field=models.ForeignKey(blank=True, to='person.Email', help_text=b'Email address used by author for submission', null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='dochistoryauthor',
|
||||
name='person',
|
||||
field=models.ForeignKey(blank=True, to='person.Person', null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='documentauthor',
|
||||
name='affiliation',
|
||||
field=models.CharField(help_text=b'Organization/company used by author for submission', max_length=100, blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='documentauthor',
|
||||
name='country',
|
||||
field=django_countries.fields.CountryField(blank=True, help_text=b'Country used by author for submission', max_length=2),
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='documentauthor',
|
||||
old_name='author',
|
||||
new_name='email',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='documentauthor',
|
||||
name='email',
|
||||
field=models.ForeignKey(blank=True, to='person.Email', help_text=b'Email address used by author for submission', null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='documentauthor',
|
||||
name='person',
|
||||
field=models.ForeignKey(blank=True, to='person.Person', null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='dochistoryauthor',
|
||||
name='document',
|
||||
field=models.ForeignKey(related_name='documentauthor_set', to='doc.DocHistory'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='dochistoryauthor',
|
||||
name='order',
|
||||
field=models.IntegerField(default=1),
|
||||
),
|
||||
migrations.RunSQL("update doc_documentauthor a inner join person_email e on a.email_id = e.address set a.person_id = e.person_id;", migrations.RunSQL.noop),
|
||||
migrations.RunSQL("update doc_dochistoryauthor a inner join person_email e on a.email_id = e.address set a.person_id = e.person_id;", migrations.RunSQL.noop),
|
||||
migrations.AlterField(
|
||||
model_name='documentauthor',
|
||||
name='person',
|
||||
field=models.ForeignKey(to='person.Person'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='dochistoryauthor',
|
||||
name='person',
|
||||
field=models.ForeignKey(to='person.Person'),
|
||||
),
|
||||
]
|
||||
|
|
50
ietf/doc/migrations/0021_remove_fake_email_adresses.py
Normal file
50
ietf/doc/migrations/0021_remove_fake_email_adresses.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
def fix_invalid_emails(apps, schema_editor):
|
||||
Email = apps.get_model("person", "Email")
|
||||
Role = apps.get_model("group", "Role")
|
||||
RoleHistory = apps.get_model("group", "RoleHistory")
|
||||
|
||||
e = Email.objects.filter(address="unknown-email-Gigi-Karmous-Edwards").first()
|
||||
if e:
|
||||
# according to ftp://ietf.org/ietf/97dec/adsl-minutes-97dec.txt
|
||||
new_e, _ = Email.objects.get_or_create(
|
||||
address="GiGi.Karmous-Edwards@pulse.com",
|
||||
primary=e.primary,
|
||||
active=e.active,
|
||||
person=e.person,
|
||||
)
|
||||
Role.objects.filter(email=e).update(email=new_e)
|
||||
RoleHistory.objects.filter(email=e).update(email=new_e)
|
||||
e.delete()
|
||||
|
||||
e = Email.objects.filter(address="unknown-email-Pat-Thaler").first()
|
||||
if e:
|
||||
# current chair email
|
||||
new_e = Email.objects.get(address="pat.thaler@broadcom.com")
|
||||
Role.objects.filter(email=e).update(email=new_e)
|
||||
RoleHistory.objects.filter(email=e).update(email=new_e)
|
||||
e.delete()
|
||||
|
||||
Email = apps.get_model("person", "Email")
|
||||
DocumentAuthor = apps.get_model("doc", "DocumentAuthor")
|
||||
DocHistoryAuthor = apps.get_model("doc", "DocHistoryAuthor")
|
||||
|
||||
DocumentAuthor.objects.filter(email__address__startswith="unknown-email-").exclude(email__address__contains="@").update(email=None)
|
||||
DocHistoryAuthor.objects.filter(email__address__startswith="unknown-email-").exclude(email__address__contains="@").update(email=None)
|
||||
Email.objects.exclude(address__contains="@").filter(address__startswith="unknown-email-").delete()
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('doc', '0020_auto_20170112_0753'),
|
||||
('person', '0014_auto_20160613_0751'),
|
||||
('group', '0009_auto_20150930_0758'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(fix_invalid_emails, migrations.RunPython.noop),
|
||||
]
|
|
@ -11,6 +11,8 @@ from django.contrib.contenttypes.models import ContentType
|
|||
from django.conf import settings
|
||||
from django.utils.html import mark_safe
|
||||
|
||||
from django_countries.fields import CountryField
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.group.models import Group
|
||||
|
@ -254,7 +256,7 @@ class DocumentInfo(models.Model):
|
|||
return state.name
|
||||
|
||||
def author_list(self):
|
||||
return ", ".join(email.address for email in self.authors.all())
|
||||
return u", ".join(author.email_id for author in self.documentauthor_set.all() if author.email_id)
|
||||
|
||||
# This, and several other ballot related functions here, assume that there is only one active ballot for a document at any point in time.
|
||||
# If that assumption is violated, they will only expose the most recently created ballot
|
||||
|
@ -399,20 +401,32 @@ class RelatedDocument(models.Model):
|
|||
|
||||
return None
|
||||
|
||||
class DocumentAuthor(models.Model):
|
||||
document = models.ForeignKey('Document')
|
||||
author = models.ForeignKey(Email, help_text="Email address used by author for submission")
|
||||
class DocumentAuthorInfo(models.Model):
|
||||
person = models.ForeignKey(Person)
|
||||
# email should only be null for some historic documents
|
||||
email = models.ForeignKey(Email, help_text="Email address used by author for submission", blank=True, null=True)
|
||||
affiliation = models.CharField(max_length=100, blank=True, help_text="Organization/company used by author for submission")
|
||||
country = CountryField(blank=True, help_text="Country used by author for submission")
|
||||
order = models.IntegerField(default=1)
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s %s (%s)" % (self.document.name, self.author.get_name(), self.order)
|
||||
def formatted_email(self):
|
||||
if self.email:
|
||||
return u'"%s" <%s>' % (self.person.plain_ascii(), self.email.address)
|
||||
else:
|
||||
return ""
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
ordering = ["document", "order"]
|
||||
|
||||
|
||||
class DocumentAuthor(DocumentAuthorInfo):
|
||||
document = models.ForeignKey('Document')
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s %s (%s)" % (self.document.name, self.person, self.order)
|
||||
|
||||
class Document(DocumentInfo):
|
||||
name = models.CharField(max_length=255, primary_key=True) # immutable
|
||||
authors = models.ManyToManyField(Email, through=DocumentAuthor, blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
@ -609,16 +623,13 @@ class RelatedDocHistory(models.Model):
|
|||
def __unicode__(self):
|
||||
return u"%s %s %s" % (self.source.doc.name, self.relationship.name.lower(), self.target.name)
|
||||
|
||||
class DocHistoryAuthor(models.Model):
|
||||
document = models.ForeignKey('DocHistory')
|
||||
author = models.ForeignKey(Email)
|
||||
order = models.IntegerField()
|
||||
class DocHistoryAuthor(DocumentAuthorInfo):
|
||||
# use same naming convention as non-history version to make it a bit
|
||||
# easier to write generic code
|
||||
document = models.ForeignKey('DocHistory', related_name="documentauthor_set")
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s %s (%s)" % (self.document.doc.name, self.author.get_name(), self.order)
|
||||
|
||||
class Meta:
|
||||
ordering = ["document", "order"]
|
||||
return u"%s %s (%s)" % (self.document.doc.name, self.person, self.order)
|
||||
|
||||
class DocHistory(DocumentInfo):
|
||||
doc = models.ForeignKey(Document, related_name="history_set")
|
||||
|
@ -627,7 +638,7 @@ class DocHistory(DocumentInfo):
|
|||
# canonical_name and replace the function on Document with a
|
||||
# property
|
||||
name = models.CharField(max_length=255)
|
||||
authors = models.ManyToManyField(Email, through=DocHistoryAuthor, blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.doc.name)
|
||||
|
||||
|
|
|
@ -99,7 +99,6 @@ class DocumentResource(ModelResource):
|
|||
shepherd = ToOneField(EmailResource, 'shepherd', null=True)
|
||||
states = ToManyField(StateResource, 'states', null=True)
|
||||
tags = ToManyField(DocTagNameResource, 'tags', null=True)
|
||||
authors = ToManyField(EmailResource, 'authors', null=True)
|
||||
rfc = CharField(attribute='rfc_number', null=True)
|
||||
class Meta:
|
||||
cache = SimpleCache()
|
||||
|
@ -128,14 +127,14 @@ class DocumentResource(ModelResource):
|
|||
"shepherd": ALL_WITH_RELATIONS,
|
||||
"states": ALL_WITH_RELATIONS,
|
||||
"tags": ALL_WITH_RELATIONS,
|
||||
"authors": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.doc.register(DocumentResource())
|
||||
|
||||
from ietf.person.resources import EmailResource
|
||||
from ietf.person.resources import PersonResource, EmailResource
|
||||
class DocumentAuthorResource(ModelResource):
|
||||
person = ToOneField(PersonResource, 'person')
|
||||
email = ToOneField(EmailResource, 'email', null=True)
|
||||
document = ToOneField(DocumentResource, 'document')
|
||||
author = ToOneField(EmailResource, 'author')
|
||||
class Meta:
|
||||
cache = SimpleCache()
|
||||
queryset = DocumentAuthor.objects.all()
|
||||
|
@ -143,9 +142,12 @@ class DocumentAuthorResource(ModelResource):
|
|||
#resource_name = 'documentauthor'
|
||||
filtering = {
|
||||
"id": ALL,
|
||||
"affiliation": ALL,
|
||||
"country": ALL,
|
||||
"order": ALL,
|
||||
"person": ALL_WITH_RELATIONS,
|
||||
"email": ALL_WITH_RELATIONS,
|
||||
"document": ALL_WITH_RELATIONS,
|
||||
"author": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.doc.register(DocumentAuthorResource())
|
||||
|
||||
|
@ -207,7 +209,6 @@ class DocHistoryResource(ModelResource):
|
|||
doc = ToOneField(DocumentResource, 'doc')
|
||||
states = ToManyField(StateResource, 'states', null=True)
|
||||
tags = ToManyField(DocTagNameResource, 'tags', null=True)
|
||||
authors = ToManyField(EmailResource, 'authors', null=True)
|
||||
class Meta:
|
||||
cache = SimpleCache()
|
||||
queryset = DocHistory.objects.all()
|
||||
|
@ -237,7 +238,6 @@ class DocHistoryResource(ModelResource):
|
|||
"doc": ALL_WITH_RELATIONS,
|
||||
"states": ALL_WITH_RELATIONS,
|
||||
"tags": ALL_WITH_RELATIONS,
|
||||
"authors": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.doc.register(DocHistoryResource())
|
||||
|
||||
|
@ -405,10 +405,11 @@ class InitialReviewDocEventResource(ModelResource):
|
|||
}
|
||||
api.doc.register(InitialReviewDocEventResource())
|
||||
|
||||
from ietf.person.resources import EmailResource
|
||||
from ietf.person.resources import PersonResource, EmailResource
|
||||
class DocHistoryAuthorResource(ModelResource):
|
||||
person = ToOneField(PersonResource, 'person')
|
||||
email = ToOneField(EmailResource, 'email', null=True)
|
||||
document = ToOneField(DocHistoryResource, 'document')
|
||||
author = ToOneField(EmailResource, 'author')
|
||||
class Meta:
|
||||
cache = SimpleCache()
|
||||
queryset = DocHistoryAuthor.objects.all()
|
||||
|
@ -416,9 +417,12 @@ class DocHistoryAuthorResource(ModelResource):
|
|||
#resource_name = 'dochistoryauthor'
|
||||
filtering = {
|
||||
"id": ALL,
|
||||
"affiliation": ALL,
|
||||
"country": ALL,
|
||||
"order": ALL,
|
||||
"person": ALL_WITH_RELATIONS,
|
||||
"email": ALL_WITH_RELATIONS,
|
||||
"document": ALL_WITH_RELATIONS,
|
||||
"author": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.doc.register(DocHistoryAuthorResource())
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ class SearchTests(TestCase):
|
|||
self.assertTrue(draft.title in unicontent(r))
|
||||
|
||||
# find by author
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=author&author=%s" % draft.authors.all()[0].person.name_parts()[1])
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=author&author=%s" % draft.documentauthor_set.first().person.name_parts()[1])
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in unicontent(r))
|
||||
|
||||
|
@ -1223,7 +1223,7 @@ class ChartTests(ResourceTestCaseMixin, TestCase):
|
|||
person = PersonFactory.create()
|
||||
DocumentFactory.create(
|
||||
states=[('draft','active')],
|
||||
authors=[person.email(), ],
|
||||
authors=[person, ],
|
||||
)
|
||||
|
||||
conf_url = urlreverse('ietf.doc.views_stats.chart_conf_person_drafts', kwargs=dict(id=person.id))
|
||||
|
|
|
@ -377,7 +377,10 @@ class EditInfoTests(TestCase):
|
|||
|
||||
DocumentAuthor.objects.create(
|
||||
document=draft,
|
||||
author=Email.objects.get(address="aread@ietf.org"),
|
||||
person=Person.objects.get(email__address="aread@ietf.org"),
|
||||
email=Email.objects.get(address="aread@ietf.org"),
|
||||
country="US",
|
||||
affiliation="",
|
||||
order=1
|
||||
)
|
||||
|
||||
|
@ -1361,7 +1364,9 @@ class ChangeReplacesTests(TestCase):
|
|||
expires=datetime.datetime.now() + datetime.timedelta(days=settings.INTERNET_DRAFT_DAYS_TO_EXPIRE),
|
||||
group=mars_wg,
|
||||
)
|
||||
self.basea.documentauthor_set.create(author=Email.objects.create(address="basea_author@example.com"),order=1)
|
||||
p = Person.objects.create(address="basea_author")
|
||||
e = Email.objects.create(address="basea_author@example.com", person=p)
|
||||
self.basea.documentauthor_set.create(person=p, email=e, order=1)
|
||||
|
||||
self.baseb = Document.objects.create(
|
||||
name="draft-test-base-b",
|
||||
|
@ -1372,7 +1377,9 @@ class ChangeReplacesTests(TestCase):
|
|||
expires=datetime.datetime.now() - datetime.timedelta(days = 365 - settings.INTERNET_DRAFT_DAYS_TO_EXPIRE),
|
||||
group=mars_wg,
|
||||
)
|
||||
self.baseb.documentauthor_set.create(author=Email.objects.create(address="baseb_author@example.com"),order=1)
|
||||
p = Person.objects.create(name="baseb_author")
|
||||
e = Email.objects.create(address="baseb_author@example.com", person=p)
|
||||
self.baseb.documentauthor_set.create(person=p, email=e, order=1)
|
||||
|
||||
self.replacea = Document.objects.create(
|
||||
name="draft-test-replace-a",
|
||||
|
@ -1383,7 +1390,9 @@ class ChangeReplacesTests(TestCase):
|
|||
expires=datetime.datetime.now() + datetime.timedelta(days = settings.INTERNET_DRAFT_DAYS_TO_EXPIRE),
|
||||
group=mars_wg,
|
||||
)
|
||||
self.replacea.documentauthor_set.create(author=Email.objects.create(address="replacea_author@example.com"),order=1)
|
||||
p = Person.objects.create(name="replacea_author")
|
||||
e = Email.objects.create(address="replacea_author@example.com", person=p)
|
||||
self.replacea.documentauthor_set.create(person=p, email=e, order=1)
|
||||
|
||||
self.replaceboth = Document.objects.create(
|
||||
name="draft-test-replace-both",
|
||||
|
@ -1394,7 +1403,9 @@ class ChangeReplacesTests(TestCase):
|
|||
expires=datetime.datetime.now() + datetime.timedelta(days = settings.INTERNET_DRAFT_DAYS_TO_EXPIRE),
|
||||
group=mars_wg,
|
||||
)
|
||||
self.replaceboth.documentauthor_set.create(author=Email.objects.create(address="replaceboth_author@example.com"),order=1)
|
||||
p = Person.objects.create(name="replaceboth_author")
|
||||
e = Email.objects.create(address="replaceboth_author@example.com", person=p)
|
||||
self.replaceboth.documentauthor_set.create(person=p, email=e, order=1)
|
||||
|
||||
self.basea.set_state(State.objects.get(used=True, type="draft", slug="active"))
|
||||
self.baseb.set_state(State.objects.get(used=True, type="draft", slug="expired"))
|
||||
|
|
|
@ -258,10 +258,7 @@ class ReviewTests(TestCase):
|
|||
|
||||
# set up some reviewer-suitability factors
|
||||
reviewer_email = Email.objects.get(person__user__username="reviewer")
|
||||
DocumentAuthor.objects.create(
|
||||
author=reviewer_email,
|
||||
document=doc,
|
||||
)
|
||||
DocumentAuthor.objects.create(person=reviewer_email.person, email=reviewer_email, document=doc)
|
||||
doc.rev = "10"
|
||||
doc.save_with_history([DocEvent.objects.create(doc=doc, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
|
|
|
@ -57,7 +57,6 @@ from ietf.group.models import Role
|
|||
from ietf.group.utils import can_manage_group, can_manage_materials
|
||||
from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream, user_is_person, role_required
|
||||
from ietf.name.models import StreamName, BallotPositionName
|
||||
from ietf.person.models import Email
|
||||
from ietf.utils.history import find_history_active_at
|
||||
from ietf.doc.forms import TelechatForm, NotifyForm
|
||||
from ietf.doc.mails import email_comment
|
||||
|
@ -167,7 +166,7 @@ def document_main(request, name, rev=None):
|
|||
|
||||
can_edit_replaces = has_role(request.user, ("Area Director", "Secretariat", "IRTF Chair", "WG Chair", "RG Chair", "WG Secretary", "RG Secretary"))
|
||||
|
||||
is_author = unicode(request.user) in set([email.address for email in doc.authors.all()])
|
||||
is_author = request.user.is_authenticated() and doc.documentauthor_set.filter(person__user=request.user).exists()
|
||||
can_view_possibly_replaces = can_edit_replaces or is_author
|
||||
|
||||
rfc_number = name[3:] if name.startswith("") else None
|
||||
|
@ -957,11 +956,11 @@ def document_json(request, name, rev=None):
|
|||
data["intended_std_level"] = extract_name(doc.intended_std_level)
|
||||
data["std_level"] = extract_name(doc.std_level)
|
||||
data["authors"] = [
|
||||
dict(name=e.person.name,
|
||||
email=e.address,
|
||||
affiliation=e.person.affiliation)
|
||||
for e in Email.objects.filter(documentauthor__document=doc).select_related("person").order_by("documentauthor__order")
|
||||
]
|
||||
dict(name=author.person.name,
|
||||
email=author.email.address,
|
||||
affiliation=author.affiliation)
|
||||
for author in doc.documentauthor_set.all().select_related("person", "email").order_by("order")
|
||||
]
|
||||
data["shepherd"] = doc.shepherd.formatted_email() if doc.shepherd else None
|
||||
data["ad"] = doc.ad.role_email("ad").formatted_email() if doc.ad else None
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ def retrieve_search_results(form, all_types=False):
|
|||
# radio choices
|
||||
by = query["by"]
|
||||
if by == "author":
|
||||
docs = docs.filter(authors__person__alias__name__icontains=query["author"])
|
||||
docs = docs.filter(documentauthor__person__alias__name__icontains=query["author"])
|
||||
elif by == "group":
|
||||
docs = docs.filter(group__acronym=query["group"])
|
||||
elif by == "area":
|
||||
|
|
|
@ -170,7 +170,7 @@ def chart_data_person_drafts(request, id):
|
|||
if not person:
|
||||
data = []
|
||||
else:
|
||||
data = model_to_timeline_data(DocEvent, doc__authors__person=person, type='new_revision')
|
||||
data = model_to_timeline_data(DocEvent, doc__documentauthor__person=person, type='new_revision')
|
||||
return JsonResponse(data, safe=False)
|
||||
|
||||
|
||||
|
|
|
@ -115,15 +115,15 @@ def all_id2_txt():
|
|||
file_types = file_types_for_drafts()
|
||||
|
||||
authors = {}
|
||||
for a in DocumentAuthor.objects.filter(document__name__startswith="draft-").order_by("order").select_related("author", "author__person").iterator():
|
||||
for a in DocumentAuthor.objects.filter(document__name__startswith="draft-").order_by("order").select_related("email", "person").iterator():
|
||||
if a.document_id not in authors:
|
||||
l = authors[a.document_id] = []
|
||||
else:
|
||||
l = authors[a.document_id]
|
||||
if "@" in a.author.address:
|
||||
l.append(u'%s <%s>' % (a.author.person.plain_name().replace("@", ""), a.author.address.replace(",", "")))
|
||||
if a.email:
|
||||
l.append(u'%s <%s>' % (a.person.plain_name().replace("@", ""), a.email.address.replace(",", "")))
|
||||
else:
|
||||
l.append(a.author.person.plain_name())
|
||||
l.append(a.person.plain_name())
|
||||
|
||||
shepherds = dict((e.pk, e.formatted_email().replace('"', ''))
|
||||
for e in Email.objects.filter(shepherd_document_set__type="draft").select_related("person").distinct())
|
||||
|
@ -234,12 +234,12 @@ def active_drafts_index_by_group(extra_values=()):
|
|||
d["initial_rev_time"] = time
|
||||
|
||||
# add authors
|
||||
for a in DocumentAuthor.objects.filter(document__states=active_state).order_by("order").select_related("author__person"):
|
||||
for a in DocumentAuthor.objects.filter(document__states=active_state).order_by("order").select_related("person"):
|
||||
d = docs_dict.get(a.document_id)
|
||||
if d:
|
||||
if "authors" not in d:
|
||||
d["authors"] = []
|
||||
d["authors"].append(a.author.person.plain_ascii()) # This should probably change to .plain_name() when non-ascii names are permitted
|
||||
d["authors"].append(a.person.plain_ascii()) # This should probably change to .plain_name() when non-ascii names are permitted
|
||||
|
||||
# put docs into groups
|
||||
for d in docs_dict.itervalues():
|
||||
|
|
|
@ -99,7 +99,7 @@ class IndexTests(TestCase):
|
|||
self.assertEqual(t[12], ".pdf,.txt")
|
||||
self.assertEqual(t[13], draft.title)
|
||||
author = draft.documentauthor_set.order_by("order").get()
|
||||
self.assertEqual(t[14], u"%s <%s>" % (author.author.person.name, author.author.address))
|
||||
self.assertEqual(t[14], u"%s <%s>" % (author.person.name, author.email.address))
|
||||
self.assertEqual(t[15], u"%s <%s>" % (draft.shepherd.person.name, draft.shepherd.address))
|
||||
self.assertEqual(t[16], u"%s <%s>" % (draft.ad.plain_ascii(), draft.ad.email_address()))
|
||||
|
||||
|
|
|
@ -63,15 +63,15 @@ def get_document_emails(ipr):
|
|||
messages = []
|
||||
for rel in ipr.iprdocrel_set.all():
|
||||
doc = rel.document.document
|
||||
authors = doc.authors.all()
|
||||
|
||||
|
||||
if is_draft(doc):
|
||||
doc_info = 'Internet-Draft entitled "{}" ({})'.format(doc.title,doc.name)
|
||||
else:
|
||||
doc_info = 'RFC entitled "{}" (RFC{})'.format(doc.title,get_rfc_num(doc))
|
||||
|
||||
addrs = gather_address_lists('ipr_posted_on_doc',doc=doc).as_strings(compact=False)
|
||||
author_names = ', '.join([a.person.name for a in authors])
|
||||
|
||||
author_names = ', '.join(a.person.name for a in doc.documentauthor_set.select_related("person"))
|
||||
|
||||
context = dict(
|
||||
doc_info=doc_info,
|
||||
|
|
|
@ -199,7 +199,7 @@ class Recipient(models.Model):
|
|||
submission = kwargs['submission']
|
||||
doc=submission.existing_document()
|
||||
if doc:
|
||||
old_authors = [i.author.formatted_email() for i in doc.documentauthor_set.all() if not i.author.invalid_address()]
|
||||
old_authors = [author.formatted_email() for author in doc.documentauthor_set.all() if author.email]
|
||||
new_authors = [u'"%s" <%s>' % (author["name"], author["email"]) for author in submission.authors_parsed() if author["email"]]
|
||||
addrs.extend(old_authors)
|
||||
if doc.group and set(old_authors)!=set(new_authors):
|
||||
|
|
|
@ -12,9 +12,6 @@ def insert_initial_formal_language_names(apps, schema_editor):
|
|||
FormalLanguageName.objects.get_or_create(slug="json", name="JSON", desc="Javascript Object Notation", order=5)
|
||||
FormalLanguageName.objects.get_or_create(slug="xml", name="XML", desc="Extensible Markup Language", order=6)
|
||||
|
||||
def noop(apps, schema_editor):
|
||||
pass
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
|
@ -22,5 +19,5 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(insert_initial_formal_language_names, noop)
|
||||
migrations.RunPython(insert_initial_formal_language_names, migrations.RunPython.noop)
|
||||
]
|
||||
|
|
|
@ -14,7 +14,8 @@ from ietf.name.models import (TimeSlotTypeName, GroupStateName, DocTagName, Inte
|
|||
ConstraintName, MeetingTypeName, DocRelationshipName, RoomResourceName, IprLicenseTypeName,
|
||||
LiaisonStatementTagName, FeedbackTypeName, LiaisonStatementState, StreamName,
|
||||
BallotPositionName, DBTemplateTypeName, NomineePositionStateName,
|
||||
ReviewRequestStateName, ReviewTypeName, ReviewResultName)
|
||||
ReviewRequestStateName, ReviewTypeName, ReviewResultName,
|
||||
FormalLanguageName)
|
||||
|
||||
|
||||
class TimeSlotTypeNameResource(ModelResource):
|
||||
|
@ -456,3 +457,20 @@ class ReviewResultNameResource(ModelResource):
|
|||
}
|
||||
api.name.register(ReviewResultNameResource())
|
||||
|
||||
|
||||
|
||||
class FormalLanguageNameResource(ModelResource):
|
||||
class Meta:
|
||||
queryset = FormalLanguageName.objects.all()
|
||||
serializer = api.Serializer()
|
||||
cache = SimpleCache()
|
||||
#resource_name = 'formallanguagename'
|
||||
filtering = {
|
||||
"slug": ALL,
|
||||
"name": ALL,
|
||||
"desc": ALL,
|
||||
"used": ALL,
|
||||
"order": ALL,
|
||||
}
|
||||
api.name.register(FormalLanguageNameResource())
|
||||
|
||||
|
|
|
@ -125,18 +125,18 @@ class PersonInfo(models.Model):
|
|||
|
||||
def has_drafts(self):
|
||||
from ietf.doc.models import Document
|
||||
return Document.objects.filter(authors__person=self, type='draft').exists()
|
||||
return Document.objects.filter(documentauthor__person=self, type='draft').exists()
|
||||
def rfcs(self):
|
||||
from ietf.doc.models import Document
|
||||
rfcs = list(Document.objects.filter(authors__person=self, type='draft', states__slug='rfc'))
|
||||
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(authors__person=self, type='draft', states__slug='active').order_by('-time')
|
||||
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(authors__person=self, type='draft', states__slug__in=['repl', 'expired', 'auth-rm', 'ietf-rm']).order_by('-time')
|
||||
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
|
||||
|
@ -231,15 +231,11 @@ class Email(models.Model):
|
|||
else:
|
||||
return self.address
|
||||
|
||||
def invalid_address(self):
|
||||
# we have some legacy authors with unknown email addresses
|
||||
return self.address.startswith("unknown-email") and "@" not in self.address
|
||||
|
||||
def email_address(self):
|
||||
"""Get valid, current email address; in practise, for active,
|
||||
non-invalid addresses it is just the address field. In other
|
||||
cases, we default to person's email address."""
|
||||
if self.invalid_address() or not self.active:
|
||||
if not self.active:
|
||||
if self.person:
|
||||
return self.person.email_address()
|
||||
return
|
||||
|
|
|
@ -752,7 +752,7 @@ def make_assignment_choices(email_queryset, review_req):
|
|||
connections[r.person_id] = "is group {}".format(r.name)
|
||||
if doc.shepherd:
|
||||
connections[doc.shepherd.person_id] = "is shepherd of document"
|
||||
for author in DocumentAuthor.objects.filter(document=doc, author__person__in=possible_person_ids).values_list("author__person", flat=True):
|
||||
for author in DocumentAuthor.objects.filter(document=doc, person__in=possible_person_ids).values_list("person", flat=True):
|
||||
connections[author] = "is author of document"
|
||||
|
||||
# unavailable periods
|
||||
|
|
|
@ -48,12 +48,12 @@ def get_authors(draft):
|
|||
Takes a draft object and returns a list of authors suitable for a tombstone document
|
||||
"""
|
||||
authors = []
|
||||
for a in draft.authors.all():
|
||||
for a in draft.documentauthor_set.all():
|
||||
initial = ''
|
||||
prefix, first, middle, last, suffix = a.person.name_parts()
|
||||
if first:
|
||||
initial = first + '. '
|
||||
entry = '%s%s <%s>' % (initial,last,a.address)
|
||||
entry = '%s%s <%s>' % (initial,last,a.email.address)
|
||||
authors.append(entry)
|
||||
return authors
|
||||
|
||||
|
@ -64,10 +64,10 @@ def get_abbr_authors(draft):
|
|||
"""
|
||||
initial = ''
|
||||
result = ''
|
||||
authors = DocumentAuthor.objects.filter(document=draft)
|
||||
authors = DocumentAuthor.objects.filter(document=draft).order_by("order")
|
||||
|
||||
if authors:
|
||||
prefix, first, middle, last, suffix = authors[0].author.person.name_parts()
|
||||
prefix, first, middle, last, suffix = authors[0].person.name_parts()
|
||||
if first:
|
||||
initial = first[0] + '. '
|
||||
result = '%s%s' % (initial,last)
|
||||
|
@ -140,9 +140,9 @@ def get_fullcc_list(draft):
|
|||
"""
|
||||
emails = {}
|
||||
# get authors
|
||||
for author in draft.authors.all():
|
||||
if author.address not in emails:
|
||||
emails[author.address] = '"%s"' % (author.person.name)
|
||||
for author in draft.documentauthor_set.all():
|
||||
if author.email and author.email.address not in emails:
|
||||
emails[author.email.address] = '"%s"' % (author.person.name)
|
||||
|
||||
if draft.group.acronym != 'none':
|
||||
# add chairs
|
||||
|
|
|
@ -4,6 +4,8 @@ import os
|
|||
|
||||
from django import forms
|
||||
|
||||
from django_countries.fields import countries
|
||||
|
||||
from ietf.doc.models import Document, DocAlias, State
|
||||
from ietf.name.models import IntendedStdLevelName, DocRelationshipName
|
||||
from ietf.group.models import Group
|
||||
|
@ -104,6 +106,8 @@ class AuthorForm(forms.Form):
|
|||
'''
|
||||
person = forms.CharField(max_length=50,widget=forms.TextInput(attrs={'class':'name-autocomplete'}),help_text="To see a list of people type the first name, or last name, or both.")
|
||||
email = forms.CharField(widget=forms.Select(),help_text="Select an email.")
|
||||
affiliation = forms.CharField(max_length=100, required=False, help_text="Affiliation")
|
||||
country = forms.ChoiceField(choices=[('', "(Not specified)")] + list(countries), required=False, help_text="Country")
|
||||
|
||||
# check for id within parenthesis to ensure name was selected from the list
|
||||
def clean_person(self):
|
||||
|
|
|
@ -541,7 +541,7 @@ def approvals(request):
|
|||
@role_required('Secretariat')
|
||||
def author_delete(request, id, oid):
|
||||
'''
|
||||
This view deletes the specified author(email) from the draft
|
||||
This view deletes the specified author from the draft
|
||||
'''
|
||||
DocumentAuthor.objects.get(id=oid).delete()
|
||||
messages.success(request, 'The author was deleted successfully')
|
||||
|
@ -574,14 +574,20 @@ def authors(request, id):
|
|||
|
||||
return redirect('drafts_view', id=id)
|
||||
|
||||
print form.is_valid(), form.errors
|
||||
|
||||
if form.is_valid():
|
||||
author = form.cleaned_data['email']
|
||||
person = form.cleaned_data['person']
|
||||
email = form.cleaned_data['email']
|
||||
affiliation = form.cleaned_data.get('affiliation') or ""
|
||||
country = form.cleaned_data.get('country') or ""
|
||||
|
||||
authors = draft.documentauthor_set.all()
|
||||
if authors:
|
||||
order = authors.aggregate(Max('order')).values()[0] + 1
|
||||
else:
|
||||
order = 1
|
||||
DocumentAuthor.objects.create(document=draft,author=author,order=order)
|
||||
DocumentAuthor.objects.create(document=draft, person=person, email=email, affiliation=affiliation, country=country, order=order)
|
||||
|
||||
messages.success(request, 'Author added successfully!')
|
||||
return redirect('drafts_authors', id=id)
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th>Affiliation</th>
|
||||
<th>Country</th>
|
||||
<th>Order</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
|
@ -31,8 +33,10 @@
|
|||
<tbody>
|
||||
{% for author in draft.documentauthor_set.all %}
|
||||
<tr class="{% cycle row1,row2 %}">
|
||||
<td>{{ author.author.person }}</td>
|
||||
<td>{{ author.author }}</td>
|
||||
<td>{{ author.person }}</td>
|
||||
<td>{{ author.email }}</td>
|
||||
<td>{{ author.affiliation }}</td>
|
||||
<td>{{ author.country.name }}</td>
|
||||
<td>{{ author.order }}</td>
|
||||
<td><a href="{% url "drafts_author_delete" id=draft.pk oid=author.id %}">Delete</a></td>
|
||||
</tr>
|
||||
|
@ -49,6 +53,10 @@
|
|||
<tr>
|
||||
<td>{{ form.person.errors }}{{ form.person }}{% if form.person.help_text %}<br>{{ form.person.help_text }}{% endif %}</td>
|
||||
<td>{{ form.email.errors }}{{ form.email }}{% if form.email.help_text %}<br>{{ form.email.help_text }}{% endif %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ form.affiliation.errors }}{{ form.affiliation }}{% if form.affiliation.help_text %}<br>{{ form.affiliation.help_text }}{% endif %}</td>
|
||||
<td>{{ form.country.errors }}{{ form.country }}{% if form.country.help_text %}<br>{{ form.country.help_text }}{% endif %}</td>
|
||||
<td><input type="submit" name="submit" value="Add" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
<div class="inline-related">
|
||||
<h2>Author(s)</h2>
|
||||
<table>
|
||||
{% for author in draft.authors.all %}
|
||||
{% for author in draft.documentauthor_set.all %}
|
||||
<tr><td><a href="{% url "ietf.secr.rolodex.views.view" id=author.person.pk %}">{{ author.person.name }}</a></td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
<h2>Author(s)</h2>
|
||||
<table class="full-width">
|
||||
{% for author in draft.documentauthor_set.all %}
|
||||
<tr><td><a href="{% url "rolodex_view" id=author.author.person.id %}">{{ author.author.person.name }}</a></td></tr>
|
||||
<tr><td><a href="{% url "rolodex_view" id=author.person.id %}">{{ author.person.name }}</a></td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div> <!-- inline-related -->
|
||||
|
|
|
@ -293,6 +293,7 @@ INSTALLED_APPS = (
|
|||
'tastypie',
|
||||
'widget_tweaks',
|
||||
'django_markup',
|
||||
'django_countries',
|
||||
# IETF apps
|
||||
'ietf.api',
|
||||
'ietf.community',
|
||||
|
|
|
@ -3,7 +3,6 @@ import itertools
|
|||
import json
|
||||
import calendar
|
||||
import os
|
||||
import re
|
||||
from collections import defaultdict
|
||||
|
||||
from django.shortcuts import render
|
||||
|
@ -141,7 +140,7 @@ def document_stats(request, stats_type=None, document_type=None):
|
|||
|
||||
bins = defaultdict(list)
|
||||
|
||||
for name, author_count in generate_canonical_names(docalias_qs.values_list("name").annotate(Count("document__authors"))):
|
||||
for name, author_count in generate_canonical_names(docalias_qs.values_list("name").annotate(Count("document__documentauthor"))):
|
||||
bins[author_count].append(name)
|
||||
|
||||
series_data = []
|
||||
|
|
|
@ -65,7 +65,8 @@ class Submission(models.Model):
|
|||
if line:
|
||||
parsed = parse_email_line(line)
|
||||
if not parsed["email"]:
|
||||
parsed["email"] = ensure_person_email_info_exists(**parsed).address
|
||||
person, email = ensure_person_email_info_exists(**parsed)
|
||||
parsed["email"] = email.address
|
||||
res.append(parsed)
|
||||
self._cached_authors_parsed = res
|
||||
return self._cached_authors_parsed
|
||||
|
|
|
@ -19,7 +19,7 @@ from ietf.group.utils import setup_default_community_list_for_group
|
|||
from ietf.meeting.models import Meeting
|
||||
from ietf.message.models import Message
|
||||
from ietf.name.models import FormalLanguageName
|
||||
from ietf.person.models import Person, Email
|
||||
from ietf.person.models import Person
|
||||
from ietf.person.factories import UserFactory, PersonFactory
|
||||
from ietf.submit.models import Submission, Preapproval
|
||||
from ietf.submit.mail import add_submission_email, process_response_email
|
||||
|
@ -249,9 +249,10 @@ class SubmitTests(TestCase):
|
|||
self.assertEqual(draft.stream_id, "ietf")
|
||||
self.assertTrue(draft.expires >= datetime.datetime.now() + datetime.timedelta(days=settings.INTERNET_DRAFT_DAYS_TO_EXPIRE - 1))
|
||||
self.assertEqual(draft.get_state("draft-stream-%s" % draft.stream_id).slug, "wg-doc")
|
||||
self.assertEqual(draft.authors.count(), 1)
|
||||
self.assertEqual(draft.authors.all()[0].get_name(), "Author Name")
|
||||
self.assertEqual(draft.authors.all()[0].address, "author@example.com")
|
||||
authors = draft.documentauthor_set.all()
|
||||
self.assertEqual(len(authors), 1)
|
||||
self.assertEqual(authors[0].person.plain_name(), "Author Name")
|
||||
self.assertEqual(authors[0].email.address, "author@example.com")
|
||||
self.assertEqual(set(draft.formal_languages.all()), set(FormalLanguageName.objects.filter(slug="json")))
|
||||
self.assertEqual(draft.relations_that_doc("replaces").count(), 1)
|
||||
self.assertTrue(draft.relations_that_doc("replaces").first().target, replaced_alias)
|
||||
|
@ -290,12 +291,12 @@ class SubmitTests(TestCase):
|
|||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="added_comment", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
if not change_authors:
|
||||
draft.documentauthor_set.all().delete()
|
||||
ensure_person_email_info_exists('Author Name','author@example.com')
|
||||
draft.documentauthor_set.create(author=Email.objects.get(address='author@example.com'))
|
||||
author_person, author_email = ensure_person_email_info_exists('Author Name','author@example.com')
|
||||
draft.documentauthor_set.create(person=author_person, email=author_email)
|
||||
else:
|
||||
# Make it such that one of the previous authors has an invalid email address
|
||||
bogus_email = ensure_person_email_info_exists('Bogus Person',None)
|
||||
DocumentAuthor.objects.create(document=draft,author=bogus_email,order=draft.documentauthor_set.latest('order').order+1)
|
||||
bogus_person, bogus_email = ensure_person_email_info_exists('Bogus Person',None)
|
||||
DocumentAuthor.objects.create(document=draft, person=bogus_person, email=bogus_email, order=draft.documentauthor_set.latest('order').order+1)
|
||||
|
||||
prev_author = draft.documentauthor_set.all()[0]
|
||||
|
||||
|
@ -342,7 +343,7 @@ class SubmitTests(TestCase):
|
|||
confirm_email = outbox[-1]
|
||||
self.assertTrue("Confirm submission" in confirm_email["Subject"])
|
||||
self.assertTrue(name in confirm_email["Subject"])
|
||||
self.assertTrue(prev_author.author.address in confirm_email["To"])
|
||||
self.assertTrue(prev_author.email.address in confirm_email["To"])
|
||||
if change_authors:
|
||||
self.assertTrue("author@example.com" not in confirm_email["To"])
|
||||
self.assertTrue("submitter@example.com" not in confirm_email["To"])
|
||||
|
@ -423,9 +424,10 @@ class SubmitTests(TestCase):
|
|||
self.assertEqual(draft.stream_id, "ietf")
|
||||
self.assertEqual(draft.get_state_slug("draft-stream-%s" % draft.stream_id), "wg-doc")
|
||||
self.assertEqual(draft.get_state_slug("draft-iana-review"), "changed")
|
||||
self.assertEqual(draft.authors.count(), 1)
|
||||
self.assertEqual(draft.authors.all()[0].get_name(), "Author Name")
|
||||
self.assertEqual(draft.authors.all()[0].address, "author@example.com")
|
||||
authors = draft.documentauthor_set.all()
|
||||
self.assertEqual(len(authors), 1)
|
||||
self.assertEqual(authors[0].person.plain_name(), "Author Name")
|
||||
self.assertEqual(authors[0].email.address, "author@example.com")
|
||||
self.assertEqual(len(outbox), mailbox_before + 3)
|
||||
self.assertTrue((u"I-D Action: %s" % name) in outbox[-3]["Subject"])
|
||||
self.assertTrue((u"I-D Action: %s" % name) in draft.message_set.order_by("-time")[0].subject)
|
||||
|
|
|
@ -125,7 +125,7 @@ def docevent_from_submission(request, submission, desc, who=None):
|
|||
else:
|
||||
submitter_parsed = submission.submitter_parsed()
|
||||
if submitter_parsed["name"] and submitter_parsed["email"]:
|
||||
by = ensure_person_email_info_exists(submitter_parsed["name"], submitter_parsed["email"]).person
|
||||
by, _ = ensure_person_email_info_exists(submitter_parsed["name"], submitter_parsed["email"])
|
||||
else:
|
||||
by = system
|
||||
|
||||
|
@ -179,7 +179,7 @@ def post_submission(request, submission, approvedDesc):
|
|||
system = Person.objects.get(name="(System)")
|
||||
submitter_parsed = submission.submitter_parsed()
|
||||
if submitter_parsed["name"] and submitter_parsed["email"]:
|
||||
submitter = ensure_person_email_info_exists(submitter_parsed["name"], submitter_parsed["email"]).person
|
||||
submitter, _ = ensure_person_email_info_exists(submitter_parsed["name"], submitter_parsed["email"])
|
||||
submitter_info = u'%s <%s>' % (submitter_parsed["name"], submitter_parsed["email"])
|
||||
else:
|
||||
submitter = system
|
||||
|
@ -341,10 +341,9 @@ def update_replaces_from_submission(request, submission, draft):
|
|||
if rdoc == draft:
|
||||
continue
|
||||
|
||||
# TODO - I think the .exists() is in the wrong place below....
|
||||
if (is_secretariat
|
||||
or (draft.group in is_chair_of and (rdoc.group.type_id == "individ" or rdoc.group in is_chair_of))
|
||||
or (submitter_email and rdoc.authors.filter(address__iexact=submitter_email)).exists()):
|
||||
or (submitter_email and rdoc.documentauthor_set.filter(email__address__iexact=submitter_email).exists())):
|
||||
approved.append(r)
|
||||
else:
|
||||
if r not in existing_suggested:
|
||||
|
@ -424,23 +423,24 @@ def ensure_person_email_info_exists(name, email):
|
|||
email.person = person
|
||||
email.save()
|
||||
|
||||
return email
|
||||
return person, email
|
||||
|
||||
def update_authors(draft, submission):
|
||||
authors = []
|
||||
persons = []
|
||||
for order, author in enumerate(submission.authors_parsed()):
|
||||
email = ensure_person_email_info_exists(author["name"], author["email"])
|
||||
person, email = ensure_person_email_info_exists(author["name"], author["email"])
|
||||
|
||||
a = DocumentAuthor.objects.filter(document=draft, author=email).first()
|
||||
a = DocumentAuthor.objects.filter(document=draft, person=person).first()
|
||||
if not a:
|
||||
a = DocumentAuthor(document=draft, author=email)
|
||||
a = DocumentAuthor(document=draft, person=person)
|
||||
|
||||
a.email = email
|
||||
a.order = order
|
||||
a.save()
|
||||
|
||||
authors.append(email)
|
||||
persons.append(person)
|
||||
|
||||
draft.documentauthor_set.exclude(author__in=authors).delete()
|
||||
draft.documentauthor_set.exclude(person__in=persons).delete()
|
||||
|
||||
def cancel_submission(submission):
|
||||
submission.state = DraftSubmissionStateName.objects.get(slug="cancel")
|
||||
|
|
|
@ -259,7 +259,7 @@ def submission_status(request, submission_id, access_token=None):
|
|||
group_authors_changed = False
|
||||
doc = submission.existing_document()
|
||||
if doc and doc.group:
|
||||
old_authors = [ i.author.person for i in doc.documentauthor_set.all() ]
|
||||
old_authors = [ author.person for author in doc.documentauthor_set.all() ]
|
||||
new_authors = [ get_person_from_name_email(**p) for p in submission.authors_parsed() ]
|
||||
group_authors_changed = set(old_authors)!=set(new_authors)
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
<reference anchor='{{doc_bibtype}}.{{doc.name|slice:"6:"}}'>
|
||||
<front>
|
||||
<title>{{doc.title}}</title>
|
||||
{% for entry in doc.authors.all %}{% with entry.address as email %}{% with entry.person as author %}
|
||||
<author initials='{{author.initials}}' surname='{{author.last_name}}' fullname='{{author.name}}'>
|
||||
<organization>{{author.affiliation}}</organization>
|
||||
{% for author in doc.documentauthor_set.all %}
|
||||
<author initials='{{ author.person.initials }}' surname='{{ author.person.last_name }}' fullname='{{ author.person.name }}'>
|
||||
<organization>{{ author.affiliation }}</organization>
|
||||
</author>
|
||||
{% endwith %}{% endwith %}{% endfor %}
|
||||
{% endfor %}
|
||||
<date month='{{doc.time|date:"F"}}' day='{{doc.time.day}}' year='{{doc.time.year}}' />
|
||||
<abstract><t>{{doc.abstract}}</t></abstract>
|
||||
</front>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
publisher = {% templatetag openbrace %}Internet Engineering Task Force{% templatetag closebrace %},
|
||||
note = {% templatetag openbrace %}Work in Progress{% templatetag closebrace %},
|
||||
url = {% templatetag openbrace %}https://tools.ietf.org/html/{{doc.name}}-{{doc.rev}}{% templatetag closebrace %},{% endif %}
|
||||
author = {% templatetag openbrace %}{% for entry in doc.authors.all %}{% with entry.person as author %}{{author.name}}{% endwith %}{% if not forloop.last %} and {% endif %}{% endfor %}{% templatetag closebrace %},
|
||||
author = {% templatetag openbrace %}{% for author in doc.documentauthor_set.all %}{{ author.person.name}}{% if not forloop.last %} and {% endif %}{% endfor %}{% templatetag closebrace %},
|
||||
title = {% templatetag openbrace %}{% templatetag openbrace %}{{doc.title}}{% templatetag closebrace %}{% templatetag closebrace %},
|
||||
pagetotal = {{ doc.pages }},
|
||||
year = {{ doc.pub_date.year }},
|
||||
|
|
|
@ -570,13 +570,13 @@
|
|||
<h4>Authors</h4>
|
||||
<p>
|
||||
{% for author in doc.documentauthor_set.all %}
|
||||
{% if not author.author.invalid_address %}
|
||||
{% if author.email %}
|
||||
<span class="fa fa-envelope-o"></span>
|
||||
<a href="mailto:{{ author.author.address }}">
|
||||
<a href="mailto:{{ author.email.address }}">
|
||||
{% endif %}
|
||||
{{ author.author.person }}
|
||||
{% if not author.author.invalid_address %}
|
||||
({{ author.author.address }})</a>
|
||||
{{ author.person }}
|
||||
{% if author.email %}
|
||||
({{ author.email.address }})</a>
|
||||
{% endif %}
|
||||
{% if not forloop.last %}<br>{% endif %}
|
||||
{% endfor %}
|
||||
|
|
|
@ -91,7 +91,7 @@ def make_immutable_base_data():
|
|||
|
||||
# one area
|
||||
area = create_group(name="Far Future", acronym="farfut", type_id="area", parent=ietf)
|
||||
create_person(area, "ad", name="Areað Irector", username="ad", email_address="aread@ietf.org")
|
||||
create_person(area, "ad", name=u"Areað Irector", username="ad", email_address="aread@ietf.org")
|
||||
|
||||
# second area
|
||||
opsarea = create_group(name="Operations", acronym="ops", type_id="area", parent=ietf)
|
||||
|
@ -276,7 +276,8 @@ def make_test_data():
|
|||
|
||||
DocumentAuthor.objects.create(
|
||||
document=draft,
|
||||
author=Email.objects.get(address="aread@ietf.org"),
|
||||
person=Person.objects.get(email__address="aread@ietf.org"),
|
||||
email=Email.objects.get(address="aread@ietf.org"),
|
||||
order=1
|
||||
)
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ decorator>=3.4.0
|
|||
defusedxml>=0.4.1 # for TastyPie when ussing xml; not a declared dependency
|
||||
Django>=1.8.16,<1.9
|
||||
django-bootstrap3>=5.1.1,<7.0.0 # django-bootstrap 7.0 requires django 1.8
|
||||
django-countries>=4.0
|
||||
django-formtools>=1.0 # instead of django.contrib.formtools in 1.8
|
||||
django-markup>=1.1
|
||||
django-tastypie>=0.13.1
|
||||
|
|
Loading…
Reference in a new issue