Merge pull request #6153 from rjsparks/nomoredocalias

feat: remove DocAlias
This commit is contained in:
Jennifer Richards 2023-08-30 17:48:54 -03:00 committed by GitHub
commit c085f0f8ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
157 changed files with 9285 additions and 9558 deletions

View file

@ -131,6 +131,7 @@ jobs:
run: | run: |
echo "Running checks..." echo "Running checks..."
./ietf/manage.py check ./ietf/manage.py check
./ietf/manage.py migrate --fake-initial
echo "Starting datatracker..." echo "Starting datatracker..."
./ietf/manage.py runserver 0.0.0.0:8000 --settings=settings_local & ./ietf/manage.py runserver 0.0.0.0:8000 --settings=settings_local &
echo "Waiting for datatracker to be ready..." echo "Waiting for datatracker to be ready..."

View file

@ -1,151 +0,0 @@
#!/usr/bin/env python
# Copyright The IETF Trust 2017-2019, All Rights Reserved
import datetime
import os
import sys
from pathlib import Path
from contextlib import closing
os.environ["DJANGO_SETTINGS_MODULE"] = "ietf.settings"
import django
django.setup()
from django.conf import settings
from django.core.validators import validate_email, ValidationError
from ietf.utils.draft import PlaintextDraft
from ietf.submit.utils import update_authors
from ietf.utils.timezone import date_today
import debug # pyflakes:ignore
from ietf.doc.models import Document, NewRevisionDocEvent, DocEvent, State
from ietf.person.models import Person
system = Person.objects.get(name="(System)")
expired = State.objects.get(type='draft',slug='expired')
names = set()
print 'collecting draft names ...'
versions = 0
for p in Path(settings.INTERNET_DRAFT_PATH).glob('draft*.txt'):
n = str(p).split('/')[-1].split('-')
if n[-1][:2].isdigit():
name = '-'.join(n[:-1])
if '--' in name or '.txt' in name or '[' in name or '=' in name or '&' in name:
continue
if name.startswith('draft-draft-'):
continue
if name == 'draft-ietf-trade-iotp-v1_0-dsig':
continue
if len(n[-1]) != 6:
continue
if name.startswith('draft-mlee-'):
continue
names.add('-'.join(n[:-1]))
count=0
print 'iterating through names ...'
for name in sorted(names):
if not Document.objects.filter(name=name).exists():
paths = list(Path(settings.INTERNET_DRAFT_PATH).glob('%s-??.txt'%name))
paths.sort()
doc = None
for p in paths:
n = str(p).split('/')[-1].split('-')
rev = n[-1][:2]
with open(str(p)) as txt_file:
raw = txt_file.read()
try:
text = raw.decode('utf8')
except UnicodeDecodeError:
text = raw.decode('latin1')
try:
draft = PlaintextDraft(text, txt_file.name, name_from_source=True)
except Exception as e:
print name, rev, "Can't parse", p,":",e
continue
if draft.errors and draft.errors.keys()!=['draftname',]:
print "Errors - could not process", name, rev, datetime.datetime.fromtimestamp(p.stat().st_mtime, datetime.timezone.utc), draft.errors, draft.get_title().encode('utf8')
else:
time = datetime.datetime.fromtimestamp(p.stat().st_mtime, datetime.timezone.utc)
if not doc:
doc = Document.objects.create(name=name,
time=time,
type_id='draft',
title=draft.get_title(),
abstract=draft.get_abstract(),
rev = rev,
pages=draft.get_pagecount(),
words=draft.get_wordcount(),
expires=time+datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE),
)
DocAlias.objects.create(name=doc.name).docs.add(doc)
doc.states.add(expired)
# update authors
authors = []
for author in draft.get_author_list():
full_name, first_name, middle_initial, last_name, name_suffix, email, country, company = author
author_name = full_name.replace("\n", "").replace("\r", "").replace("<", "").replace(">", "").strip()
if email:
try:
validate_email(email)
except ValidationError:
email = ""
def turn_into_unicode(s):
if s is None:
return u""
if isinstance(s, unicode):
return s
else:
try:
return s.decode("utf-8")
except UnicodeDecodeError:
try:
return s.decode("latin-1")
except UnicodeDecodeError:
return ""
author_name = turn_into_unicode(author_name)
email = turn_into_unicode(email)
company = turn_into_unicode(company)
authors.append({
"name": author_name,
"email": email,
"affiliation": company,
"country": country
})
dummysubmission=type('', (), {})() #https://stackoverflow.com/questions/19476816/creating-an-empty-object-in-python
dummysubmission.authors = authors
update_authors(doc,dummysubmission)
# add a docevent with words explaining where this came from
events = []
e = NewRevisionDocEvent.objects.create(
type="new_revision",
doc=doc,
rev=rev,
by=system,
desc="New version available: <b>%s-%s.txt</b>" % (doc.name, doc.rev),
time=time,
)
events.append(e)
e = DocEvent.objects.create(
type="comment",
doc = doc,
rev = rev,
by = system,
desc = "Revision added from id-archive on %s by %s"%(date_today(),sys.argv[0]),
time=time,
)
events.append(e)
doc.time = time
doc.rev = rev
doc.save_with_history(events)
print "Added",name, rev

View file

@ -0,0 +1,155 @@
#!/usr/bin/env python
# Copyright The IETF Trust 2017-2019, All Rights Reserved
## Holding on to this as documentation - it was originally in bin
## If resuscitated, it will need to bemake python3, learn about the "rfc" document type
## and made into a management command
# import datetime
# import os
# import sys
# from pathlib import Path
# from contextlib import closing
# os.environ["DJANGO_SETTINGS_MODULE"] = "ietf.settings"
# import django
# django.setup()
# from django.conf import settings
# from django.core.validators import validate_email, ValidationError
# from ietf.utils.draft import PlaintextDraft
# from ietf.submit.utils import update_authors
# from ietf.utils.timezone import date_today
# import debug # pyflakes:ignore
# from ietf.doc.models import Document, NewRevisionDocEvent, DocEvent, State
# from ietf.person.models import Person
# system = Person.objects.get(name="(System)")
# expired = State.objects.get(type='draft',slug='expired')
# names = set()
# print 'collecting draft names ...'
# versions = 0
# for p in Path(settings.INTERNET_DRAFT_PATH).glob('draft*.txt'):
# n = str(p).split('/')[-1].split('-')
# if n[-1][:2].isdigit():
# name = '-'.join(n[:-1])
# if '--' in name or '.txt' in name or '[' in name or '=' in name or '&' in name:
# continue
# if name.startswith('draft-draft-'):
# continue
# if name == 'draft-ietf-trade-iotp-v1_0-dsig':
# continue
# if len(n[-1]) != 6:
# continue
# if name.startswith('draft-mlee-'):
# continue
# names.add('-'.join(n[:-1]))
# count=0
# print 'iterating through names ...'
# for name in sorted(names):
# if not Document.objects.filter(name=name).exists():
# paths = list(Path(settings.INTERNET_DRAFT_PATH).glob('%s-??.txt'%name))
# paths.sort()
# doc = None
# for p in paths:
# n = str(p).split('/')[-1].split('-')
# rev = n[-1][:2]
# with open(str(p)) as txt_file:
# raw = txt_file.read()
# try:
# text = raw.decode('utf8')
# except UnicodeDecodeError:
# text = raw.decode('latin1')
# try:
# draft = PlaintextDraft(text, txt_file.name, name_from_source=True)
# except Exception as e:
# print name, rev, "Can't parse", p,":",e
# continue
# if draft.errors and draft.errors.keys()!=['draftname',]:
# print "Errors - could not process", name, rev, datetime.datetime.fromtimestamp(p.stat().st_mtime, datetime.timezone.utc), draft.errors, draft.get_title().encode('utf8')
# else:
# time = datetime.datetime.fromtimestamp(p.stat().st_mtime, datetime.timezone.utc)
# if not doc:
# doc = Document.objects.create(name=name,
# time=time,
# type_id='draft',
# title=draft.get_title(),
# abstract=draft.get_abstract(),
# rev = rev,
# pages=draft.get_pagecount(),
# words=draft.get_wordcount(),
# expires=time+datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE),
# )
# DocAlias.objects.create(name=doc.name).docs.add(doc)
# doc.states.add(expired)
# # update authors
# authors = []
# for author in draft.get_author_list():
# full_name, first_name, middle_initial, last_name, name_suffix, email, country, company = author
# author_name = full_name.replace("\n", "").replace("\r", "").replace("<", "").replace(">", "").strip()
# if email:
# try:
# validate_email(email)
# except ValidationError:
# email = ""
# def turn_into_unicode(s):
# if s is None:
# return u""
# if isinstance(s, unicode):
# return s
# else:
# try:
# return s.decode("utf-8")
# except UnicodeDecodeError:
# try:
# return s.decode("latin-1")
# except UnicodeDecodeError:
# return ""
# author_name = turn_into_unicode(author_name)
# email = turn_into_unicode(email)
# company = turn_into_unicode(company)
# authors.append({
# "name": author_name,
# "email": email,
# "affiliation": company,
# "country": country
# })
# dummysubmission=type('', (), {})() #https://stackoverflow.com/questions/19476816/creating-an-empty-object-in-python
# dummysubmission.authors = authors
# update_authors(doc,dummysubmission)
# # add a docevent with words explaining where this came from
# events = []
# e = NewRevisionDocEvent.objects.create(
# type="new_revision",
# doc=doc,
# rev=rev,
# by=system,
# desc="New version available: <b>%s-%s.txt</b>" % (doc.name, doc.rev),
# time=time,
# )
# events.append(e)
# e = DocEvent.objects.create(
# type="comment",
# doc = doc,
# rev = rev,
# by = system,
# desc = "Revision added from id-archive on %s by %s"%(date_today(),sys.argv[0]),
# time=time,
# )
# events.append(e)
# doc.time = time
# doc.rev = rev
# doc.save_with_history(events)
# print "Added",name, rev

File diff suppressed because it is too large Load diff

View file

@ -993,7 +993,7 @@ class RfcdiffSupportTests(TestCase):
) )
num_received = received num_received = received
received = self.getJson(dict(name=rfc.canonical_name())) received = self.getJson(dict(name=rfc.name))
self.assertEqual(num_received, received, 'RFC by canonical name gives same result as by number') self.assertEqual(num_received, received, 'RFC by canonical name gives same result as by number')
received = self.getJson(dict(name=f'RfC {number}')) received = self.getJson(dict(name=f'RfC {number}'))
@ -1032,7 +1032,7 @@ class RfcdiffSupportTests(TestCase):
draft = reload_db_objects(draft) draft = reload_db_objects(draft)
# Some old rfcs had tombstones that shouldn't be used for comparisons # Some old rfcs had tombstones that shouldn't be used for comparisons
received = self.getJson(dict(name=rfc.canonical_name())) received = self.getJson(dict(name=rfc.name))
self.assertTrue(received['previous'].endswith('00')) self.assertTrue(received['previous'].endswith('00'))
def do_rfc_with_broken_history_test(self, draft_name): def do_rfc_with_broken_history_test(self, draft_name):
@ -1048,7 +1048,7 @@ class RfcdiffSupportTests(TestCase):
received, received,
dict( dict(
content_url=rfc.get_href(), content_url=rfc.get_href(),
name=rfc.canonical_name(), name=rfc.name,
previous=f'{draft.name}-10', previous=f'{draft.name}-10',
previous_url= f'{settings.IETF_ID_ARCHIVE_URL}{draft.name}-10.txt', previous_url= f'{settings.IETF_ID_ARCHIVE_URL}{draft.name}-10.txt',
), ),

View file

@ -328,7 +328,7 @@ def rfcdiff_latest_json(request, name, rev=None):
response = dict() response = dict()
condition, document, history, found_rev = find_doc_for_rfcdiff(name, rev) condition, document, history, found_rev = find_doc_for_rfcdiff(name, rev)
if document.type_id == "rfc": if document.type_id == "rfc":
draft_alias = next(iter(document.related_that('became_rfc')), None) draft = next(iter(document.related_that('became_rfc')), None)
if condition == 'no such document': if condition == 'no such document':
raise Http404 raise Http404
elif condition in ('historic version', 'current version'): elif condition in ('historic version', 'current version'):
@ -336,8 +336,7 @@ def rfcdiff_latest_json(request, name, rev=None):
if doc.type_id == "rfc": if doc.type_id == "rfc":
response['content_url'] = doc.get_href() response['content_url'] = doc.get_href()
response['name']=doc.name response['name']=doc.name
if draft_alias: if draft:
draft = draft_alias.document
prev_rev = draft.rev prev_rev = draft.rev
if doc.rfc_number in HAS_TOMBSTONE and prev_rev != '00': if doc.rfc_number in HAS_TOMBSTONE and prev_rev != '00':
prev_rev = f'{(int(draft.rev)-1):02d}' prev_rev = f'{(int(draft.rev)-1):02d}'

File diff suppressed because it is too large Load diff

View file

@ -99,7 +99,7 @@ if newpid == 0:
pipe("%s -a %s %s" % (settings.RSYNC_BINARY,settings.RFC_TEXT_RSYNC_SOURCE,settings.RFC_PATH)) pipe("%s -a %s %s" % (settings.RSYNC_BINARY,settings.RFC_TEXT_RSYNC_SOURCE,settings.RFC_PATH))
for rfc in new_rfcs: for rfc in new_rfcs:
rebuild_reference_relations(rfc) rebuild_reference_relations(rfc)
log("Updated references for %s"%rfc.canonical_name()) log("Updated references for %s"%rfc.name)
except: except:
subject = "Exception in updating references for new rfcs: %s : %s" % (sys.exc_info()[0],sys.exc_info()[1]) subject = "Exception in updating references for new rfcs: %s : %s" % (sys.exc_info()[0],sys.exc_info()[1])
msg = "%s\n%s\n----\n%s"%(sys.exc_info()[0],sys.exc_info()[1],traceback.format_tb(sys.exc_info()[2])) msg = "%s\n%s\n----\n%s"%(sys.exc_info()[0],sys.exc_info()[1],traceback.format_tb(sys.exc_info()[2]))

View file

@ -60,7 +60,7 @@ def reset_name_contains_index_for_rule(rule):
if not rule.rule_type == "name_contains": if not rule.rule_type == "name_contains":
return return
rule.name_contains_index.set(Document.objects.filter(docalias__name__regex=rule.text)) rule.name_contains_index.set(Document.objects.filter(name__regex=rule.text))
def update_name_contains_indexes_with_new_doc(doc): def update_name_contains_indexes_with_new_doc(doc):
for r in SearchRule.objects.filter(rule_type="name_contains"): for r in SearchRule.objects.filter(rule_type="name_contains"):

View file

@ -129,7 +129,7 @@ def manage_list(request, username=None, acronym=None, group_type=None):
@login_required @login_required
def track_document(request, name, username=None, acronym=None): def track_document(request, name, username=None, acronym=None):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if request.method == "POST": if request.method == "POST":
clist = lookup_community_list(username, acronym) clist = lookup_community_list(username, acronym)
@ -153,7 +153,7 @@ def track_document(request, name, username=None, acronym=None):
@login_required @login_required
def untrack_document(request, name, username=None, acronym=None): def untrack_document(request, name, username=None, acronym=None):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
clist = lookup_community_list(username, acronym) clist = lookup_community_list(username, acronym)
if not can_manage_community_list(request.user, clist): if not can_manage_community_list(request.user, clist):
permission_denied(request, "You do not have permission to access this view") permission_denied(request, "You do not have permission to access this view")

View file

@ -7,7 +7,7 @@ from django.db import models
from django import forms from django import forms
from .models import (StateType, State, RelatedDocument, DocumentAuthor, Document, RelatedDocHistory, from .models import (StateType, State, RelatedDocument, DocumentAuthor, Document, RelatedDocHistory,
DocHistoryAuthor, DocHistory, DocAlias, DocReminder, DocEvent, NewRevisionDocEvent, DocHistoryAuthor, DocHistory, DocReminder, DocEvent, NewRevisionDocEvent,
StateDocEvent, ConsensusDocEvent, BallotType, BallotDocEvent, WriteupDocEvent, LastCallDocEvent, StateDocEvent, ConsensusDocEvent, BallotType, BallotDocEvent, WriteupDocEvent, LastCallDocEvent,
TelechatDocEvent, BallotPositionDocEvent, ReviewRequestDocEvent, InitialReviewDocEvent, TelechatDocEvent, BallotPositionDocEvent, ReviewRequestDocEvent, InitialReviewDocEvent,
AddedMessageEvent, SubmissionDocEvent, DeletedEvent, EditedAuthorsDocEvent, DocumentURL, AddedMessageEvent, SubmissionDocEvent, DeletedEvent, EditedAuthorsDocEvent, DocumentURL,
@ -27,10 +27,6 @@ class StateAdmin(admin.ModelAdmin):
filter_horizontal = ["next_states"] filter_horizontal = ["next_states"]
admin.site.register(State, StateAdmin) admin.site.register(State, StateAdmin)
# class DocAliasInline(admin.TabularInline):
# model = DocAlias
# extra = 1
class DocAuthorInline(admin.TabularInline): class DocAuthorInline(admin.TabularInline):
model = DocumentAuthor model = DocumentAuthor
raw_id_fields = ['person', 'email'] raw_id_fields = ['person', 'email']
@ -45,7 +41,7 @@ class RelatedDocumentInline(admin.TabularInline):
model = RelatedDocument model = RelatedDocument
fk_name= 'source' fk_name= 'source'
def this(self, instance): def this(self, instance):
return instance.source.canonical_name() return instance.source.name
readonly_fields = ['this', ] readonly_fields = ['this', ]
fields = ['this', 'relationship', 'target', ] fields = ['this', 'relationship', 'target', ]
raw_id_fields = ['target'] raw_id_fields = ['target']
@ -71,7 +67,7 @@ class DocumentForm(forms.ModelForm):
class DocumentAuthorAdmin(admin.ModelAdmin): class DocumentAuthorAdmin(admin.ModelAdmin):
list_display = ['id', 'document', 'person', 'email', 'affiliation', 'country', 'order'] list_display = ['id', 'document', 'person', 'email', 'affiliation', 'country', 'order']
search_fields = ['document__docalias__name', 'person__name', 'email__address', 'affiliation', 'country'] search_fields = ['document__name', 'person__name', 'email__address', 'affiliation', 'country']
raw_id_fields = ["document", "person", "email"] raw_id_fields = ["document", "person", "email"]
admin.site.register(DocumentAuthor, DocumentAuthorAdmin) admin.site.register(DocumentAuthor, DocumentAuthorAdmin)
@ -109,14 +105,6 @@ class DocHistoryAdmin(admin.ModelAdmin):
admin.site.register(DocHistory, DocHistoryAdmin) admin.site.register(DocHistory, DocHistoryAdmin)
class DocAliasAdmin(admin.ModelAdmin):
list_display = ['name', 'targets']
search_fields = ['name', 'docs__name']
raw_id_fields = ['docs']
def targets(self, obj):
return ', '.join([o.name for o in obj.docs.all()])
admin.site.register(DocAlias, DocAliasAdmin)
class DocReminderAdmin(admin.ModelAdmin): class DocReminderAdmin(admin.ModelAdmin):
list_display = ['id', 'event', 'type', 'due', 'active'] list_display = ['id', 'event', 'type', 'due', 'active']
list_filter = ['type', 'due', 'active'] list_filter = ['type', 'due', 'active']

View file

@ -12,7 +12,7 @@ from typing import Optional # pyflakes:ignore
from django.conf import settings from django.conf import settings
from django.utils import timezone from django.utils import timezone
from ietf.doc.models import ( Document, DocEvent, NewRevisionDocEvent, DocAlias, State, DocumentAuthor, from ietf.doc.models import ( Document, DocEvent, NewRevisionDocEvent, State, DocumentAuthor,
StateDocEvent, BallotPositionDocEvent, BallotDocEvent, BallotType, IRSGBallotDocEvent, TelechatDocEvent, StateDocEvent, BallotPositionDocEvent, BallotDocEvent, BallotType, IRSGBallotDocEvent, TelechatDocEvent,
DocumentActionHolder, BofreqEditorDocEvent, BofreqResponsibleDocEvent, DocExtResource ) DocumentActionHolder, BofreqEditorDocEvent, BofreqResponsibleDocEvent, DocExtResource )
from ietf.group.models import Group from ietf.group.models import Group
@ -52,15 +52,6 @@ class BaseDocumentFactory(factory.django.DjangoModelFactory):
newrevisiondocevent = factory.RelatedFactory('ietf.doc.factories.NewRevisionDocEventFactory','doc') newrevisiondocevent = factory.RelatedFactory('ietf.doc.factories.NewRevisionDocEventFactory','doc')
@factory.post_generation
def other_aliases(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument
alias = DocAliasFactory(name=obj.name)
alias.docs.add(obj)
if create and extracted:
for name in extracted:
alias = DocAliasFactory(name=name)
alias.docs.add(obj)
@factory.post_generation @factory.post_generation
def states(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument def states(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument
if create and extracted: if create and extracted:
@ -128,12 +119,6 @@ class RfcFactory(BaseDocumentFactory):
else: else:
obj.set_state(State.objects.get(type_id='rfc',slug='published')) obj.set_state(State.objects.get(type_id='rfc',slug='published'))
@factory.post_generation
def reset_canonical_name(obj, create, extracted, **kwargs):
if hasattr(obj, '_canonical_name'):
del obj._canonical_name
return None
class IndividualDraftFactory(BaseDocumentFactory): class IndividualDraftFactory(BaseDocumentFactory):
@ -285,23 +270,6 @@ class ReviewFactory(BaseDocumentFactory):
name = factory.LazyAttribute(lambda o: 'review-doesnotexist-00-%s-%s'%(o.group.acronym,date_today().isoformat())) name = factory.LazyAttribute(lambda o: 'review-doesnotexist-00-%s-%s'%(o.group.acronym,date_today().isoformat()))
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='review') group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='review')
class DocAliasFactory(factory.django.DjangoModelFactory):
class Meta:
model = DocAlias
@factory.post_generation
def document(self, create, extracted, **kwargs):
if create and extracted:
self.docs.add(extracted)
@factory.post_generation
def docs(self, create, extracted, **kwargs):
if create and extracted:
for doc in extracted:
if not doc in self.docs.all():
self.docs.add(doc)
class DocEventFactory(factory.django.DjangoModelFactory): class DocEventFactory(factory.django.DjangoModelFactory):
class Meta: class Meta:
model = DocEvent model = DocEvent

View file

@ -36,7 +36,7 @@ class DocumentChangesFeed(Feed):
feed_type = Atom1Feed feed_type = Atom1Feed
def get_object(self, request, name): def get_object(self, request, name):
return Document.objects.get(docalias__name=name) return Document.objects.get(name=name)
def title(self, obj): def title(self, obj):
return "Changes for %s" % obj.display_name() return "Changes for %s" % obj.display_name()
@ -46,7 +46,7 @@ class DocumentChangesFeed(Feed):
raise FeedDoesNotExist raise FeedDoesNotExist
return urlreverse( return urlreverse(
"ietf.doc.views_doc.document_history", "ietf.doc.views_doc.document_history",
kwargs=dict(name=obj.canonical_name()), kwargs=dict(name=obj.name),
) )
def subtitle(self, obj): def subtitle(self, obj):
@ -86,7 +86,7 @@ class DocumentChangesFeed(Feed):
return ( return (
urlreverse( urlreverse(
"ietf.doc.views_doc.document_history", "ietf.doc.views_doc.document_history",
kwargs=dict(name=item.doc.canonical_name()), kwargs=dict(name=item.doc.name),
) )
+ "#history-%s" % item.pk + "#history-%s" % item.pk
) )
@ -208,13 +208,13 @@ class RfcFeed(Feed):
return [doc for doc, time in results] return [doc for doc, time in results]
def item_title(self, item): def item_title(self, item):
return "%s : %s" % (item.canonical_name(), item.title) return "%s : %s" % (item.name, item.title)
def item_description(self, item): def item_description(self, item):
return item.abstract return item.abstract
def item_link(self, item): def item_link(self, item):
return "https://rfc-editor.org/info/%s" % item.canonical_name() return "https://rfc-editor.org/info/%s" % item.name
def item_pubdate(self, item): def item_pubdate(self, item):
return item.publication_time return item.publication_time
@ -229,7 +229,7 @@ class RfcFeed(Feed):
for fmt, media_type in [("txt", "text/plain"), ("html", "text/html")]: for fmt, media_type in [("txt", "text/plain"), ("html", "text/html")]:
media_contents.append( media_contents.append(
{ {
"url": f"https://rfc-editor.org/rfc/{item.canonical_name()}.{fmt}", "url": f"https://rfc-editor.org/rfc/{item.name}.{fmt}",
"media_type": media_type, "media_type": media_type,
"is_format_of": self.item_link(item), "is_format_of": self.item_link(item),
} }
@ -237,7 +237,7 @@ class RfcFeed(Feed):
if item.rfc_number not in [571, 587]: if item.rfc_number not in [571, 587]:
media_contents.append( media_contents.append(
{ {
"url": f"https://www.rfc-editor.org/rfc/pdfrfc/{item.canonical_name()}.txt.pdf", "url": f"https://www.rfc-editor.org/rfc/pdfrfc/{item.name}.txt.pdf",
"media_type": "application/pdf", "media_type": "application/pdf",
"is_format_of": self.item_link(item), "is_format_of": self.item_link(item),
} }
@ -245,7 +245,7 @@ class RfcFeed(Feed):
else: else:
media_contents.append( media_contents.append(
{ {
"url": f"https://www.rfc-editor.org/rfc/{item.canonical_name()}.xml", "url": f"https://www.rfc-editor.org/rfc/{item.name}.xml",
"media_type": "application/rfc+xml", "media_type": "application/rfc+xml",
} }
) )
@ -256,16 +256,16 @@ class RfcFeed(Feed):
]: ]:
media_contents.append( media_contents.append(
{ {
"url": f"https://rfc-editor.org/rfc/{item.canonical_name()}.{fmt}", "url": f"https://rfc-editor.org/rfc/{item.name}.{fmt}",
"media_type": media_type, "media_type": media_type,
"is_format_of": f"https://www.rfc-editor.org/rfc/{item.canonical_name()}.xml", "is_format_of": f"https://www.rfc-editor.org/rfc/{item.name}.xml",
} }
) )
extra.update({"media_contents": media_contents}) extra.update({"media_contents": media_contents})
extra.update({"doi": "10.17487/%s" % item.canonical_name().upper()}) extra.update({"doi": "10.17487/%s" % item.name.upper()})
extra.update( extra.update(
{"doiuri": "http://dx.doi.org/10.17487/%s" % item.canonical_name().upper()} {"doiuri": "http://dx.doi.org/10.17487/%s" % item.name.upper()}
) )
# R104 Publisher (Mandatory - but we need a string from them first) # R104 Publisher (Mandatory - but we need a string from them first)

View file

@ -13,7 +13,7 @@ from django.urls import reverse as urlreverse
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import Document, DocAlias from ietf.doc.models import Document
from ietf.doc.utils import uppercase_std_abbreviated_name from ietf.doc.utils import uppercase_std_abbreviated_name
from ietf.utils.fields import SearchableField from ietf.utils.fields import SearchableField
@ -69,19 +69,3 @@ class SearchableDocumentsField(SearchableField):
class SearchableDocumentField(SearchableDocumentsField): class SearchableDocumentField(SearchableDocumentsField):
"""Specialized to only return one Document""" """Specialized to only return one Document"""
max_entries = 1 max_entries = 1
class SearchableDocAliasesField(SearchableDocumentsField):
"""Search DocAliases instead of Documents"""
model = DocAlias # type: Type[models.Model]
def doc_type_filter(self, queryset):
"""Filter to include only desired doc type
For DocAlias, pass through to the docs to check type.
"""
return queryset.filter(docs__type=self.doc_type)
class SearchableDocAliasField(SearchableDocAliasesField):
"""Specialized to only return one DocAlias"""
max_entries = 1

View file

@ -19,7 +19,7 @@ from ietf.doc.templatetags.mail_filters import std_level_prompt
from ietf.utils import log from ietf.utils import log
from ietf.utils.mail import send_mail, send_mail_text from ietf.utils.mail import send_mail, send_mail_text
from ietf.ipr.utils import iprs_from_docs, related_docs from ietf.ipr.utils import iprs_from_docs, related_docs
from ietf.doc.models import WriteupDocEvent, LastCallDocEvent, DocAlias, ConsensusDocEvent from ietf.doc.models import WriteupDocEvent, LastCallDocEvent, ConsensusDocEvent
from ietf.doc.utils import needed_ballot_positions from ietf.doc.utils import needed_ballot_positions
from ietf.doc.utils_bofreq import bofreq_editors, bofreq_responsible from ietf.doc.utils_bofreq import bofreq_editors, bofreq_responsible
from ietf.group.models import Role from ietf.group.models import Role
@ -202,7 +202,7 @@ def generate_last_call_announcement(request, doc):
doc.filled_title = textwrap.fill(doc.title, width=70, subsequent_indent=" " * 3) doc.filled_title = textwrap.fill(doc.title, width=70, subsequent_indent=" " * 3)
iprs = iprs_from_docs(related_docs(DocAlias.objects.get(name=doc.canonical_name()))) iprs = iprs_from_docs(related_docs(Document.objects.get(name=doc.name)))
if iprs: if iprs:
ipr_links = [ urlreverse("ietf.ipr.views.show", kwargs=dict(id=i.id)) for i in iprs] ipr_links = [ urlreverse("ietf.ipr.views.show", kwargs=dict(id=i.id)) for i in iprs]
ipr_links = [ settings.IDTRACKER_BASE_URL+url if not url.startswith("http") else url for url in ipr_links ] ipr_links = [ settings.IDTRACKER_BASE_URL+url if not url.startswith("http") else url for url in ipr_links ]
@ -670,7 +670,7 @@ def send_review_possibly_replaces_request(request, doc, submitter_info):
to = set(addrs.to) to = set(addrs.to)
cc = set(addrs.cc) cc = set(addrs.cc)
possibly_replaces = Document.objects.filter(name__in=[alias.name for alias in doc.related_that_doc("possibly-replaces")]) possibly_replaces = Document.objects.filter(name__in=[related.name for related in doc.related_that_doc("possibly-replaces")])
for other_doc in possibly_replaces: for other_doc in possibly_replaces:
(other_to, other_cc) = gather_address_lists('doc_replacement_suggested',doc=other_doc) (other_to, other_cc) = gather_address_lists('doc_replacement_suggested',doc=other_doc)
to.update(other_to) to.update(other_to)

View file

@ -16,7 +16,7 @@ from pathlib import Path
from django.conf import settings from django.conf import settings
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from ietf.doc.models import Document, DocAlias, DocEvent, State from ietf.doc.models import Document, DocEvent, State
from ietf.utils.text import xslugify from ietf.utils.text import xslugify
@ -95,7 +95,6 @@ class Command(BaseCommand):
uploaded_filename=filename, uploaded_filename=filename,
) )
doc.set_state(State.objects.get(type_id="statement", slug="active")) doc.set_state(State.objects.get(type_id="statement", slug="active"))
DocAlias.objects.create(name=doc.name).docs.add(doc)
year, month, day = [int(part) for part in date_string.split("-")] year, month, day = [int(part) for part in date_string.split("-")]
e1 = DocEvent.objects.create( e1 = DocEvent.objects.create(
time=datetime.datetime( time=datetime.datetime(

View file

@ -8,7 +8,7 @@ def forward(apps, schema_editor):
Document = apps.get_model("doc", "Document") Document = apps.get_model("doc", "Document")
RelatedDocument = apps.get_model("doc", "RelatedDocument") RelatedDocument = apps.get_model("doc", "RelatedDocument")
for rfc_alias in DocAlias.objects.filter(name__startswith="rfc").exclude( for rfc_alias in DocAlias.objects.filter(name__startswith="rfc").exclude(
docs__type__slug="rfc" docs__type_id="rfc"
): ):
# Move these over to the RFC # Move these over to the RFC
RelatedDocument.objects.filter( RelatedDocument.objects.filter(

View file

@ -0,0 +1,16 @@
# Copyright The IETF Trust 2023, All Rights Reserved
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("ipr", "0002_iprdocrel_no_aliases"),
("doc", "0014_relate_hist_no_aliases"),
]
operations = [
migrations.DeleteModel(
name="DocAlias",
),
]

View file

@ -37,7 +37,6 @@ from ietf.name.models import ( DocTypeName, DocTagName, StreamName, IntendedStdL
from ietf.person.models import Email, Person from ietf.person.models import Email, Person
from ietf.person.utils import get_active_balloters from ietf.person.utils import get_active_balloters
from ietf.utils import log from ietf.utils import log
from ietf.utils.admin import admin_link
from ietf.utils.decorators import memoize from ietf.utils.decorators import memoize
from ietf.utils.validators import validate_no_control_chars from ietf.utils.validators import validate_no_control_chars
from ietf.utils.mail import formataddr from ietf.utils.mail import formataddr
@ -173,7 +172,7 @@ class DocumentInfo(models.Model):
if self.uploaded_filename: if self.uploaded_filename:
self._cached_base_name = self.uploaded_filename self._cached_base_name = self.uploaded_filename
elif self.type_id == 'rfc': elif self.type_id == 'rfc':
self._cached_base_name = "%s.txt" % self.canonical_name() self._cached_base_name = "%s.txt" % self.name
elif self.type_id == 'draft': elif self.type_id == 'draft':
if self.is_dochistory(): if self.is_dochistory():
self._cached_base_name = "%s-%s.txt" % (self.doc.name, self.rev) self._cached_base_name = "%s-%s.txt" % (self.doc.name, self.rev)
@ -181,7 +180,7 @@ class DocumentInfo(models.Model):
self._cached_base_name = "%s-%s.txt" % (self.name, self.rev) self._cached_base_name = "%s-%s.txt" % (self.name, self.rev)
elif self.type_id in ["slides", "agenda", "minutes", "bluesheets", "procmaterials", ] and self.meeting_related(): elif self.type_id in ["slides", "agenda", "minutes", "bluesheets", "procmaterials", ] and self.meeting_related():
ext = 'pdf' if self.type_id == 'procmaterials' else 'txt' ext = 'pdf' if self.type_id == 'procmaterials' else 'txt'
self._cached_base_name = f'{self.canonical_name()}-{self.rev}.{ext}' self._cached_base_name = f'{self.name}-{self.rev}.{ext}'
elif self.type_id == 'review': elif self.type_id == 'review':
# TODO: This will be wrong if a review is updated on the same day it was created (or updated more than once on the same day) # TODO: This will be wrong if a review is updated on the same day it was created (or updated more than once on the same day)
self._cached_base_name = "%s.txt" % self.name self._cached_base_name = "%s.txt" % self.name
@ -189,9 +188,9 @@ class DocumentInfo(models.Model):
self._cached_base_name = "%s-%s.md" % (self.name, self.rev) self._cached_base_name = "%s-%s.md" % (self.name, self.rev)
else: else:
if self.rev: if self.rev:
self._cached_base_name = "%s-%s.txt" % (self.canonical_name(), self.rev) self._cached_base_name = "%s-%s.txt" % (self.name, self.rev)
else: else:
self._cached_base_name = "%s.txt" % (self.canonical_name(), ) self._cached_base_name = "%s.txt" % (self.name, )
return self._cached_base_name return self._cached_base_name
def get_file_name(self): def get_file_name(self):
@ -355,7 +354,7 @@ class DocumentInfo(models.Model):
elif state.slug == "repl": elif state.slug == "repl":
rs = self.related_that("replaces") rs = self.related_that("replaces")
if rs: if rs:
return mark_safe("Replaced by " + ", ".join("<a href=\"%s\">%s</a>" % (urlreverse('ietf.doc.views_doc.document_main', kwargs=dict(name=alias.document.name)), alias.document) for alias in rs)) return mark_safe("Replaced by " + ", ".join("<a href=\"%s\">%s</a>" % (urlreverse('ietf.doc.views_doc.document_main', kwargs=dict(name=related.name)), related) for related in rs))
else: else:
return "Replaced" return "Replaced"
elif state.slug == "active": elif state.slug == "active":
@ -493,10 +492,10 @@ class DocumentInfo(models.Model):
return related return related
def related_that(self, relationship): def related_that(self, relationship):
return list(set([x.source.docalias.get(name=x.source.name) for x in self.relations_that(relationship)])) return list(set([x.source for x in self.relations_that(relationship)]))
def all_related_that(self, relationship, related=None): def all_related_that(self, relationship, related=None):
return list(set([x.source.docalias.get(name=x.source.name) for x in self.all_relations_that(relationship)])) return list(set([x.source for x in self.all_relations_that(relationship)]))
def related_that_doc(self, relationship): def related_that_doc(self, relationship):
return list(set([x.target for x in self.relations_that_doc(relationship)])) return list(set([x.target for x in self.relations_that_doc(relationship)]))
@ -507,7 +506,7 @@ class DocumentInfo(models.Model):
def replaces(self): def replaces(self):
return set([ d for r in self.related_that_doc("replaces") for d in r.docs.all() ]) return set([ d for r in self.related_that_doc("replaces") for d in r.docs.all() ])
def replaces_canonical_name(self): def replaces_name(self):
s = set([ r.document for r in self.related_that_doc("replaces")]) s = set([ r.document for r in self.related_that_doc("replaces")])
first = list(s)[0] if s else None first = list(s)[0] if s else None
return None if first is None else first.filename_with_rev() return None if first is None else first.filename_with_rev()
@ -540,7 +539,7 @@ class DocumentInfo(models.Model):
if self.get_state_slug() == "rfc": if self.get_state_slug() == "rfc":
try: try:
html = Path( html = Path(
os.path.join(settings.RFC_PATH, self.canonical_name() + ".html") os.path.join(settings.RFC_PATH, self.name + ".html")
).read_text() ).read_text()
except (IOError, UnicodeDecodeError): except (IOError, UnicodeDecodeError):
return None return None
@ -805,7 +804,7 @@ class Document(DocumentInfo):
name = self.name name = self.name
url = None url = None
if self.type_id == "draft" and self.get_state_slug() == "rfc": if self.type_id == "draft" and self.get_state_slug() == "rfc":
name = self.canonical_name() name = self.name
url = urlreverse('ietf.doc.views_doc.document_main', kwargs={ 'name': name }, urlconf="ietf.urls") url = urlreverse('ietf.doc.views_doc.document_main', kwargs={ 'name': name }, urlconf="ietf.urls")
elif self.type_id in ('slides','bluesheets','recording'): elif self.type_id in ('slides','bluesheets','recording'):
session = self.session_set.first() session = self.session_set.first()
@ -843,22 +842,8 @@ class Document(DocumentInfo):
e = model.objects.filter(doc=self).filter(**filter_args).order_by('-time', '-id').first() e = model.objects.filter(doc=self).filter(**filter_args).order_by('-time', '-id').first()
return e return e
def canonical_name(self):
if not hasattr(self, '_canonical_name'):
name = self.name
if self.type_id == "draft" and self.get_state_slug() == "rfc":
a = self.docalias.filter(name__startswith="rfc").order_by('-name').first()
if a:
name = a.name
self._canonical_name = name
return self._canonical_name
def canonical_docalias(self):
return self.docalias.get(name=self.name)
def display_name(self): def display_name(self):
name = self.canonical_name() name = self.name
if name.startswith('rfc'): if name.startswith('rfc'):
name = name.upper() name = name.upper()
return name return name
@ -953,8 +938,9 @@ class Document(DocumentInfo):
def ipr(self,states=('posted','removed')): def ipr(self,states=('posted','removed')):
"""Returns the IPR disclosures against this document (as a queryset over IprDocRel).""" """Returns the IPR disclosures against this document (as a queryset over IprDocRel)."""
from ietf.ipr.models import IprDocRel # from ietf.ipr.models import IprDocRel
return IprDocRel.objects.filter(document__docs=self, disclosure__state__in=states) # return IprDocRel.objects.filter(document__docs=self, disclosure__state__in=states) # TODO - clear these comments away
return self.iprdocrel_set.filter(disclosure__state__in=states)
def related_ipr(self): def related_ipr(self):
"""Returns the IPR disclosures against this document and those documents this """Returns the IPR disclosures against this document and those documents this
@ -963,8 +949,8 @@ class Document(DocumentInfo):
from ietf.ipr.models import IprDocRel from ietf.ipr.models import IprDocRel
iprs = ( iprs = (
IprDocRel.objects.filter( IprDocRel.objects.filter(
document__in=list(self.docalias.all()) document__in=[self]
+ [x.docalias.first() for x in self.all_related_that_doc(("obs", "replaces"))] # this really is docalias until IprDocRel changes + self.all_related_that_doc(("obs", "replaces"))
) )
.filter(disclosure__state__in=("posted", "removed")) .filter(disclosure__state__in=("posted", "removed"))
.values_list("disclosure", flat=True) .values_list("disclosure", flat=True)
@ -1123,10 +1109,7 @@ class DocHistoryAuthor(DocumentAuthorInfo):
class DocHistory(DocumentInfo): class DocHistory(DocumentInfo):
doc = ForeignKey(Document, related_name="history_set") doc = ForeignKey(Document, related_name="history_set")
# the name here is used to capture the canonical name at the time
# - it would perhaps be more elegant to simply call the attribute
# canonical_name and replace the function on Document with a
# property
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
def __str__(self): def __str__(self):
@ -1138,11 +1121,6 @@ class DocHistory(DocumentInfo):
def get_related_proceedings_material(self): def get_related_proceedings_material(self):
return self.doc.get_related_proceedings_material() return self.doc.get_related_proceedings_material()
def canonical_name(self):
if hasattr(self, '_canonical_name'):
return self._canonical_name
return self.name
def latest_event(self, *args, **kwargs): def latest_event(self, *args, **kwargs):
kwargs["time__lte"] = self.time kwargs["time__lte"] = self.time
return self.doc.latest_event(*args, **kwargs) return self.doc.latest_event(*args, **kwargs)
@ -1157,10 +1135,6 @@ class DocHistory(DocumentInfo):
def groupmilestone_set(self): def groupmilestone_set(self):
return self.doc.groupmilestone_set return self.doc.groupmilestone_set
@property
def docalias(self):
return self.doc.docalias
def is_dochistory(self): def is_dochistory(self):
return True return True
@ -1178,25 +1152,6 @@ class DocHistory(DocumentInfo):
verbose_name = "document history" verbose_name = "document history"
verbose_name_plural = "document histories" verbose_name_plural = "document histories"
class DocAlias(models.Model):
"""This is used for documents that may appear under multiple names,
and in particular for RFCs, which for continuity still keep the
same immutable Document.name, in the tables, but will be referred
to by RFC number, primarily, after achieving RFC status.
"""
name = models.CharField(max_length=255, unique=True)
docs = models.ManyToManyField(Document, related_name='docalias')
@property
def document(self):
return self.docs.first()
def __str__(self):
return u"%s-->%s" % (self.name, ','.join([force_str(d.name) for d in self.docs.all() if isinstance(d, Document) ]))
document_link = admin_link("document")
class Meta:
verbose_name = "document alias"
verbose_name_plural = "document aliases"
class DocReminder(models.Model): class DocReminder(models.Model):
event = ForeignKey('DocEvent') event = ForeignKey('DocEvent')

View file

@ -12,7 +12,7 @@ from tastypie.cache import SimpleCache
from ietf import api from ietf import api
from ietf.doc.models import (BallotType, DeletedEvent, StateType, State, Document, from ietf.doc.models import (BallotType, DeletedEvent, StateType, State, Document,
DocumentAuthor, DocEvent, StateDocEvent, DocHistory, ConsensusDocEvent, DocAlias, DocumentAuthor, DocEvent, StateDocEvent, DocHistory, ConsensusDocEvent,
TelechatDocEvent, DocReminder, LastCallDocEvent, NewRevisionDocEvent, WriteupDocEvent, TelechatDocEvent, DocReminder, LastCallDocEvent, NewRevisionDocEvent, WriteupDocEvent,
InitialReviewDocEvent, DocHistoryAuthor, BallotDocEvent, RelatedDocument, InitialReviewDocEvent, DocHistoryAuthor, BallotDocEvent, RelatedDocument,
RelatedDocHistory, BallotPositionDocEvent, AddedMessageEvent, SubmissionDocEvent, RelatedDocHistory, BallotPositionDocEvent, AddedMessageEvent, SubmissionDocEvent,
@ -286,21 +286,6 @@ class ConsensusDocEventResource(ModelResource):
} }
api.doc.register(ConsensusDocEventResource()) api.doc.register(ConsensusDocEventResource())
class DocAliasResource(ModelResource):
document = ToOneField(DocumentResource, 'document')
class Meta:
cache = SimpleCache()
queryset = DocAlias.objects.all()
serializer = api.Serializer()
detail_uri_name = 'name'
#resource_name = 'docalias'
ordering = ['id', ]
filtering = {
"name": ALL,
"document": ALL_WITH_RELATIONS,
}
api.doc.register(DocAliasResource())
from ietf.person.resources import PersonResource from ietf.person.resources import PersonResource
class TelechatDocEventResource(ModelResource): class TelechatDocEventResource(ModelResource):
by = ToOneField(PersonResource, 'by') by = ToOneField(PersonResource, 'by')
@ -490,7 +475,7 @@ api.doc.register(BallotDocEventResource())
from ietf.name.resources import DocRelationshipNameResource from ietf.name.resources import DocRelationshipNameResource
class RelatedDocumentResource(ModelResource): class RelatedDocumentResource(ModelResource):
source = ToOneField(DocumentResource, 'source') source = ToOneField(DocumentResource, 'source')
target = ToOneField(DocAliasResource, 'target') target = ToOneField(DocumentResource, 'target')
relationship = ToOneField(DocRelationshipNameResource, 'relationship') relationship = ToOneField(DocRelationshipNameResource, 'relationship')
class Meta: class Meta:
cache = SimpleCache() cache = SimpleCache()
@ -509,7 +494,7 @@ api.doc.register(RelatedDocumentResource())
from ietf.name.resources import DocRelationshipNameResource from ietf.name.resources import DocRelationshipNameResource
class RelatedDocHistoryResource(ModelResource): class RelatedDocHistoryResource(ModelResource):
source = ToOneField(DocHistoryResource, 'source') source = ToOneField(DocHistoryResource, 'source')
target = ToOneField(DocAliasResource, 'target') target = ToOneField(DocumentResource, 'target')
relationship = ToOneField(DocRelationshipNameResource, 'relationship') relationship = ToOneField(DocRelationshipNameResource, 'relationship')
class Meta: class Meta:
cache = SimpleCache() cache = SimpleCache()

View file

@ -22,7 +22,7 @@ from django.utils import timezone
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import BallotDocEvent, DocAlias from ietf.doc.models import BallotDocEvent, Document
from ietf.doc.models import ConsensusDocEvent from ietf.doc.models import ConsensusDocEvent
from ietf.ietfauth.utils import can_request_rfc_publication as utils_can_request_rfc_publication from ietf.ietfauth.utils import can_request_rfc_publication as utils_can_request_rfc_publication
from ietf.utils.html import sanitize_fragment from ietf.utils.html import sanitize_fragment
@ -139,15 +139,16 @@ def rfceditor_info_url(rfcnum : str):
return urljoin(settings.RFC_EDITOR_INFO_BASE_URL, f'rfc{rfcnum}') return urljoin(settings.RFC_EDITOR_INFO_BASE_URL, f'rfc{rfcnum}')
def doc_canonical_name(name): def doc_name(name):
"""Check whether a given document exists, and return its canonical name""" """Check whether a given document exists, and return its canonical name"""
def find_unique(n): def find_unique(n):
key = hash(n) key = hash(n)
found = cache.get(key) found = cache.get(key)
if not found: if not found:
exact = DocAlias.objects.filter(name=n).first() exact = Document.objects.filter(name=n).first()
found = exact.name if exact else "_" found = exact.name if exact else "_"
# TODO review this cache policy (and the need for these entire function)
cache.set(key, found, timeout=60*60*24) # cache for one day cache.set(key, found, timeout=60*60*24) # cache for one day
return None if found == "_" else found return None if found == "_" else found
@ -173,7 +174,7 @@ def doc_canonical_name(name):
def link_charter_doc_match(match): def link_charter_doc_match(match):
if not doc_canonical_name(match[0]): if not doc_name(match[0]):
return match[0] return match[0]
url = urlreverse( url = urlreverse(
"ietf.doc.views_doc.document_main", "ietf.doc.views_doc.document_main",
@ -186,7 +187,7 @@ def link_non_charter_doc_match(match):
name = match[0] name = match[0]
# handle "I-D.*"" reference-style matches # handle "I-D.*"" reference-style matches
name = re.sub(r"^i-d\.(.*)", r"draft-\1", name, flags=re.IGNORECASE) name = re.sub(r"^i-d\.(.*)", r"draft-\1", name, flags=re.IGNORECASE)
cname = doc_canonical_name(name) cname = doc_name(name)
if not cname: if not cname:
return match[0] return match[0]
if name == cname: if name == cname:
@ -201,7 +202,7 @@ def link_non_charter_doc_match(match):
url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=cname)) url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=cname))
return f'<a href="{url}">{match[0]}</a>' return f'<a href="{url}">{match[0]}</a>'
cname = doc_canonical_name(name) cname = doc_name(name)
if not cname: if not cname:
return match[0] return match[0]
if name == cname: if name == cname:
@ -221,7 +222,7 @@ def link_non_charter_doc_match(match):
def link_other_doc_match(match): def link_other_doc_match(match):
doc = match[2].strip().lower() doc = match[2].strip().lower()
rev = match[3] rev = match[3]
if not doc_canonical_name(doc + rev): if not doc_name(doc + rev):
return match[0] return match[0]
url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=doc + rev)) url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=doc + rev))
return f'<a href="{url}">{match[1]}</a>' return f'<a href="{url}">{match[1]}</a>'
@ -255,6 +256,7 @@ def urlize_ietf_docs(string, autoescape=None):
string, string,
flags=re.IGNORECASE | re.ASCII, flags=re.IGNORECASE | re.ASCII,
) )
return mark_safe(string) return mark_safe(string)
@ -267,7 +269,7 @@ def urlize_related_source_list(related, document_html=False):
names = set() names = set()
titles = set() titles = set()
for rel in related: for rel in related:
name=rel.source.canonical_name() name=rel.source.name
title = rel.source.title title = rel.source.title
if name in names and title in titles: if name in names and title in titles:
continue continue
@ -288,7 +290,7 @@ def urlize_related_target_list(related, document_html=False):
"""Convert a list of RelatedDocuments into list of links using the target document's canonical name""" """Convert a list of RelatedDocuments into list of links using the target document's canonical name"""
links = [] links = []
for rel in related: for rel in related:
name=rel.target.canonical_name() name=rel.target.name
title = rel.target.title title = rel.target.title
url = urlreverse('ietf.doc.views_doc.document_main' if document_html is False else 'ietf.doc.views_doc.document_html', kwargs=dict(name=name)) url = urlreverse('ietf.doc.views_doc.document_main' if document_html is False else 'ietf.doc.views_doc.document_html', kwargs=dict(name=name))
name = escape(name) name = escape(name)

View file

@ -3,12 +3,12 @@
from django.conf import settings from django.conf import settings
from ietf.doc.factories import ( from ietf.doc.factories import (
WgDraftFactory, WgRfcFactory,
IndividualDraftFactory, IndividualDraftFactory,
CharterFactory, CharterFactory,
NewRevisionDocEventFactory, NewRevisionDocEventFactory,
) )
from ietf.doc.models import State, DocEvent, DocAlias from ietf.doc.models import DocEvent
from ietf.doc.templatetags.ietf_filters import urlize_ietf_docs, is_valid_url from ietf.doc.templatetags.ietf_filters import urlize_ietf_docs, is_valid_url
from ietf.person.models import Person from ietf.person.models import Person
from ietf.utils.test_utils import TestCase from ietf.utils.test_utils import TestCase
@ -25,23 +25,21 @@ class IetfFiltersTests(TestCase):
self.assertEqual(is_valid_url(url), result) self.assertEqual(is_valid_url(url), result)
def test_urlize_ietf_docs(self): def test_urlize_ietf_docs(self):
wg_id = WgDraftFactory() rfc = WgRfcFactory(rfc_number=123456,std_level_id="bcp")
wg_id.set_state(State.objects.get(type="draft", slug="rfc")) rfc.save_with_history(
wg_id.std_level_id = "bcp"
wg_id.save_with_history(
[ [
DocEvent.objects.create( DocEvent.objects.create(
doc=wg_id, doc=rfc,
rev=wg_id.rev, rev=rfc.rev,
type="published_rfc", type="published_rfc",
by=Person.objects.get(name="(System)"), by=Person.objects.get(name="(System)"),
) )
] ]
) )
DocAlias.objects.create(name="rfc123456").docs.add(wg_id) # TODO - bring these into existance when subseries are well modeled
DocAlias.objects.create(name="bcp123456").docs.add(wg_id) # DocAlias.objects.create(name="bcp123456").docs.add(rfc)
DocAlias.objects.create(name="std123456").docs.add(wg_id) # DocAlias.objects.create(name="std123456").docs.add(rfc)
DocAlias.objects.create(name="fyi123456").docs.add(wg_id) # DocAlias.objects.create(name="fyi123456").docs.add(rfc)
id = IndividualDraftFactory(name="draft-me-rfc123456bis") id = IndividualDraftFactory(name="draft-me-rfc123456bis")
id_num = IndividualDraftFactory(name="draft-rosen-rfcefdp-update-2026") id_num = IndividualDraftFactory(name="draft-rosen-rfcefdp-update-2026")
@ -59,15 +57,17 @@ class IetfFiltersTests(TestCase):
cases = [ cases = [
("no change", "no change"), ("no change", "no change"),
("bCp123456", '<a href="/doc/bcp123456/">bCp123456</a>'),
("Std 00123456", '<a href="/doc/std123456/">Std 00123456</a>'), # TODO: rework subseries when we add them
( # ("bCp123456", '<a href="/doc/bcp123456/">bCp123456</a>'),
"FyI 0123456 changes std 00123456", # ("Std 00123456", '<a href="/doc/std123456/">Std 00123456</a>'),
'<a href="/doc/fyi123456/">FyI 0123456</a> changes <a href="/doc/std123456/">std 00123456</a>', # (
), # "FyI 0123456 changes std 00123456",
# '<a href="/doc/fyi123456/">FyI 0123456</a> changes <a href="/doc/std123456/">std 00123456</a>',
# ),
("rfc123456", '<a href="/doc/rfc123456/">rfc123456</a>'), ("rfc123456", '<a href="/doc/rfc123456/">rfc123456</a>'),
("Rfc 0123456", '<a href="/doc/rfc123456/">Rfc 0123456</a>'), ("Rfc 0123456", '<a href="/doc/rfc123456/">Rfc 0123456</a>'),
(wg_id.name, f'<a href="/doc/{wg_id.name}/">{wg_id.name}</a>'), (rfc.name, f'<a href="/doc/{rfc.name}/">{rfc.name}</a>'),
( (
f"{id.name}-{id.rev}.txt", f"{id.name}-{id.rev}.txt",
f'<a href="/doc/{id.name}/{id.rev}/">{id.name}-{id.rev}.txt</a>', f'<a href="/doc/{id.name}/{id.rev}/">{id.name}-{id.rev}.txt</a>',

View file

@ -33,7 +33,7 @@ from tastypie.test import ResourceTestCaseMixin
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import ( Document, DocAlias, DocRelationshipName, RelatedDocument, State, from ietf.doc.models import ( Document, DocRelationshipName, RelatedDocument, State,
DocEvent, BallotPositionDocEvent, LastCallDocEvent, WriteupDocEvent, NewRevisionDocEvent, BallotType, DocEvent, BallotPositionDocEvent, LastCallDocEvent, WriteupDocEvent, NewRevisionDocEvent, BallotType,
EditedAuthorsDocEvent ) EditedAuthorsDocEvent )
from ietf.doc.factories import ( DocumentFactory, DocEventFactory, CharterFactory, from ietf.doc.factories import ( DocumentFactory, DocEventFactory, CharterFactory,
@ -324,7 +324,6 @@ class SearchTests(TestCase):
draft.set_state(State.objects.get(type='draft-iesg', slug='lc')) draft.set_state(State.objects.get(type='draft-iesg', slug='lc'))
rfc = IndividualDraftFactory(ad=ad) rfc = IndividualDraftFactory(ad=ad)
rfc.set_state(State.objects.get(type='draft', slug='rfc')) rfc.set_state(State.objects.get(type='draft', slug='rfc'))
DocAlias.objects.create(name='rfc6666').docs.add(rfc)
conflrev = DocumentFactory(type_id='conflrev',ad=ad) conflrev = DocumentFactory(type_id='conflrev',ad=ad)
conflrev.set_state(State.objects.get(type='conflrev', slug='iesgeval')) conflrev.set_state(State.objects.get(type='conflrev', slug='iesgeval'))
statchg = DocumentFactory(type_id='statchg',ad=ad) statchg = DocumentFactory(type_id='statchg',ad=ad)
@ -348,7 +347,7 @@ class SearchTests(TestCase):
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.assertContains(r, draft.name) self.assertContains(r, draft.name)
self.assertContains(r, escape(draft.action_holders.first().name)) self.assertContains(r, escape(draft.action_holders.first().name))
self.assertContains(r, rfc.canonical_name()) self.assertContains(r, rfc.name)
self.assertContains(r, conflrev.name) self.assertContains(r, conflrev.name)
self.assertContains(r, statchg.name) self.assertContains(r, statchg.name)
self.assertContains(r, charter.name) self.assertContains(r, charter.name)
@ -396,7 +395,7 @@ class SearchTests(TestCase):
r = self.client.get(urlreverse('ietf.doc.views_search.index_all_drafts')) r = self.client.get(urlreverse('ietf.doc.views_search.index_all_drafts'))
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.assertContains(r, draft.name) self.assertContains(r, draft.name)
self.assertContains(r, rfc.canonical_name().upper()) self.assertContains(r, rfc.name.upper())
r = self.client.get(urlreverse('ietf.doc.views_search.index_active_drafts')) r = self.client.get(urlreverse('ietf.doc.views_search.index_active_drafts'))
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
@ -415,19 +414,6 @@ class SearchTests(TestCase):
data = r.json() data = r.json()
self.assertEqual(data[0]["id"], draft.pk) self.assertEqual(data[0]["id"], draft.pk)
# DocAlias
doc_alias = draft.docalias.first()
url = urlreverse('ietf.doc.views_search.ajax_select2_search_docs', kwargs={
"model_name": "docalias",
"doc_type": "draft",
})
r = self.client.get(url, dict(q=doc_alias.name))
self.assertEqual(r.status_code, 200)
data = r.json()
self.assertEqual(data[0]["id"], doc_alias.pk)
def test_recent_drafts(self): def test_recent_drafts(self):
# Three drafts to show with various warnings # Three drafts to show with various warnings
drafts = WgDraftFactory.create_batch(3,states=[('draft','active'),('draft-iesg','ad-eval')]) drafts = WgDraftFactory.create_batch(3,states=[('draft','active'),('draft-iesg','ad-eval')])
@ -656,7 +642,7 @@ Man Expires September 22, 2015 [Page 3]
if settings.USER_PREFERENCE_DEFAULTS['full_draft'] == 'off': if settings.USER_PREFERENCE_DEFAULTS['full_draft'] == 'off':
self.assertContains(r, "Show full document") self.assertContains(r, "Show full document")
self.assertNotContains(r, "Deimos street") self.assertNotContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name()) self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title) self.assertContains(r, replaced.title)
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name)) + "?include_text=0") r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name)) + "?include_text=0")
@ -664,7 +650,7 @@ Man Expires September 22, 2015 [Page 3]
self.assertContains(r, "Active Internet-Draft") self.assertContains(r, "Active Internet-Draft")
self.assertContains(r, "Show full document") self.assertContains(r, "Show full document")
self.assertNotContains(r, "Deimos street") self.assertNotContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name()) self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title) self.assertContains(r, replaced.title)
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name)) + "?include_text=foo") r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name)) + "?include_text=foo")
@ -672,7 +658,7 @@ Man Expires September 22, 2015 [Page 3]
self.assertContains(r, "Active Internet-Draft") self.assertContains(r, "Active Internet-Draft")
self.assertNotContains(r, "Show full document") self.assertNotContains(r, "Show full document")
self.assertContains(r, "Deimos street") self.assertContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name()) self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title) self.assertContains(r, replaced.title)
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name)) + "?include_text=1") r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name)) + "?include_text=1")
@ -680,7 +666,7 @@ Man Expires September 22, 2015 [Page 3]
self.assertContains(r, "Active Internet-Draft") self.assertContains(r, "Active Internet-Draft")
self.assertNotContains(r, "Show full document") self.assertNotContains(r, "Show full document")
self.assertContains(r, "Deimos street") self.assertContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name()) self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title) self.assertContains(r, replaced.title)
self.client.cookies = SimpleCookie({str('full_draft'): str('on')}) self.client.cookies = SimpleCookie({str('full_draft'): str('on')})
@ -689,7 +675,7 @@ Man Expires September 22, 2015 [Page 3]
self.assertContains(r, "Active Internet-Draft") self.assertContains(r, "Active Internet-Draft")
self.assertNotContains(r, "Show full document") self.assertNotContains(r, "Show full document")
self.assertContains(r, "Deimos street") self.assertContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name()) self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title) self.assertContains(r, replaced.title)
self.client.cookies = SimpleCookie({str('full_draft'): str('off')}) self.client.cookies = SimpleCookie({str('full_draft'): str('off')})
@ -698,7 +684,7 @@ Man Expires September 22, 2015 [Page 3]
self.assertContains(r, "Active Internet-Draft") self.assertContains(r, "Active Internet-Draft")
self.assertContains(r, "Show full document") self.assertContains(r, "Show full document")
self.assertNotContains(r, "Deimos street") self.assertNotContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name()) self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title) self.assertContains(r, replaced.title)
self.client.cookies = SimpleCookie({str('full_draft'): str('foo')}) self.client.cookies = SimpleCookie({str('full_draft'): str('foo')})
@ -708,7 +694,7 @@ Man Expires September 22, 2015 [Page 3]
if settings.USER_PREFERENCE_DEFAULTS['full_draft'] == 'off': if settings.USER_PREFERENCE_DEFAULTS['full_draft'] == 'off':
self.assertContains(r, "Show full document") self.assertContains(r, "Show full document")
self.assertNotContains(r, "Deimos street") self.assertNotContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name()) self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title) self.assertContains(r, replaced.title)
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=draft.name))) r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=draft.name)))
@ -735,16 +721,16 @@ Man Expires September 22, 2015 [Page 3]
rfc = WgRfcFactory() rfc = WgRfcFactory()
rfc.save_with_history([DocEventFactory(doc=rfc)]) rfc.save_with_history([DocEventFactory(doc=rfc)])
(Path(settings.RFC_PATH) / rfc.get_base_name()).touch() (Path(settings.RFC_PATH) / rfc.get_base_name()).touch()
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.canonical_name()))) r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.name)))
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
q = PyQuery(r.content) q = PyQuery(r.content)
self.assertEqual(q('title').text(), f'RFC {rfc.rfc_number} - {rfc.title}') self.assertEqual(q('title').text(), f'RFC {rfc.rfc_number} - {rfc.title}')
# synonyms for the rfc should be redirected to its canonical view # synonyms for the rfc should be redirected to its canonical view
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.rfc_number))) r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.rfc_number)))
self.assertRedirects(r, urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.canonical_name()))) self.assertRedirects(r, urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.name)))
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=f'RFC {rfc.rfc_number}'))) r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=f'RFC {rfc.rfc_number}')))
self.assertRedirects(r, urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.canonical_name()))) self.assertRedirects(r, urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.name)))
# expired draft # expired draft
draft.set_state(State.objects.get(type="draft", slug="expired")) draft.set_state(State.objects.get(type="draft", slug="expired"))
@ -771,7 +757,7 @@ Man Expires September 22, 2015 [Page 3]
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name))) r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name)))
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.assertContains(r, "Replaced Internet-Draft") self.assertContains(r, "Replaced Internet-Draft")
self.assertContains(r, replacement.canonical_name()) self.assertContains(r, replacement.name)
self.assertContains(r, replacement.title) self.assertContains(r, replacement.title)
rel.delete() rel.delete()
@ -801,13 +787,13 @@ Man Expires September 22, 2015 [Page 3]
self.assertContains(r, "RFC 123456") self.assertContains(r, "RFC 123456")
self.assertContains(r, draft.name) self.assertContains(r, draft.name)
# obs/updates included with RFC # obs/updates included with RFC
self.assertContains(r, obsoleted.canonical_name()) self.assertContains(r, obsoleted.name)
self.assertContains(r, obsoleted.title) self.assertContains(r, obsoleted.title)
self.assertContains(r, obsoleted_by.canonical_name()) self.assertContains(r, obsoleted_by.name)
self.assertContains(r, obsoleted_by.title) self.assertContains(r, obsoleted_by.title)
self.assertContains(r, updated.canonical_name()) self.assertContains(r, updated.name)
self.assertContains(r, updated.title) self.assertContains(r, updated.title)
self.assertContains(r, updated_by.canonical_name()) self.assertContains(r, updated_by.name)
self.assertContains(r, updated_by.title) self.assertContains(r, updated_by.title)
# naked RFC - also weird that we test a PS from the ISE # naked RFC - also weird that we test a PS from the ISE
@ -859,7 +845,7 @@ Man Expires September 22, 2015 [Page 3]
r = self.client.get( r = self.client.get(
urlreverse( urlreverse(
'ietf.doc.views_doc.document_main', 'ietf.doc.views_doc.document_main',
kwargs={'name': draft.canonical_name()}, kwargs={'name': draft.name},
) )
) )
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
@ -2712,20 +2698,20 @@ class Idnits2SupportTests(TestCase):
rfc = WgRfcFactory() rfc = WgRfcFactory()
draft = WgDraftFactory() draft = WgDraftFactory()
draft.relateddocument_set.create(relationship_id="became_rfc", target=rfc) draft.relateddocument_set.create(relationship_id="became_rfc", target=rfc)
url = urlreverse('ietf.doc.views_doc.idnits2_state', kwargs=dict(name=rfc.canonical_name())) url = urlreverse('ietf.doc.views_doc.idnits2_state', kwargs=dict(name=rfc.name))
r = self.client.get(url) r = self.client.get(url)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.assertContains(r,'rfcnum') self.assertContains(r,'rfcnum')
draft = WgDraftFactory() draft = WgDraftFactory()
url = urlreverse('ietf.doc.views_doc.idnits2_state', kwargs=dict(name=draft.canonical_name())) url = urlreverse('ietf.doc.views_doc.idnits2_state', kwargs=dict(name=draft.name))
r = self.client.get(url) r = self.client.get(url)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.assertNotContains(r,'rfcnum') self.assertNotContains(r,'rfcnum')
self.assertContains(r,'Unknown') self.assertContains(r,'Unknown')
draft = WgDraftFactory(intended_std_level_id='ps') draft = WgDraftFactory(intended_std_level_id='ps')
url = urlreverse('ietf.doc.views_doc.idnits2_state', kwargs=dict(name=draft.canonical_name())) url = urlreverse('ietf.doc.views_doc.idnits2_state', kwargs=dict(name=draft.name))
r = self.client.get(url) r = self.client.get(url)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.assertContains(r,'Proposed') self.assertContains(r,'Proposed')

View file

@ -18,7 +18,7 @@ from django.utils import timezone
from ietf.group.factories import RoleFactory from ietf.group.factories import RoleFactory
from ietf.doc.factories import BofreqFactory, NewRevisionDocEventFactory from ietf.doc.factories import BofreqFactory, NewRevisionDocEventFactory
from ietf.doc.models import State, Document, DocAlias, NewRevisionDocEvent from ietf.doc.models import State, Document, NewRevisionDocEvent
from ietf.doc.utils_bofreq import bofreq_editors, bofreq_responsible from ietf.doc.utils_bofreq import bofreq_editors, bofreq_responsible
from ietf.ietfauth.utils import has_role from ietf.ietfauth.utils import has_role
from ietf.person.factories import PersonFactory from ietf.person.factories import PersonFactory
@ -32,7 +32,7 @@ class BofreqTests(TestCase):
settings_temp_path_overrides = TestCase.settings_temp_path_overrides + ['BOFREQ_PATH'] settings_temp_path_overrides = TestCase.settings_temp_path_overrides + ['BOFREQ_PATH']
def write_bofreq_file(self, bofreq): def write_bofreq_file(self, bofreq):
fname = Path(settings.BOFREQ_PATH) / ("%s-%s.md" % (bofreq.canonical_name(), bofreq.rev)) fname = Path(settings.BOFREQ_PATH) / ("%s-%s.md" % (bofreq.name, bofreq.rev))
with fname.open("w") as f: with fname.open("w") as f:
f.write(f"""# This is a test bofreq. f.write(f"""# This is a test bofreq.
Version: {bofreq.rev} Version: {bofreq.rev}
@ -366,7 +366,6 @@ This test section has some text.
name = f"bofreq-{xslugify(nobody.last_name())[:64]}-{postdict['title']}".replace(' ','-') name = f"bofreq-{xslugify(nobody.last_name())[:64]}-{postdict['title']}".replace(' ','-')
bofreq = Document.objects.filter(name=name,type_id='bofreq').first() bofreq = Document.objects.filter(name=name,type_id='bofreq').first()
self.assertIsNotNone(bofreq) self.assertIsNotNone(bofreq)
self.assertIsNotNone(DocAlias.objects.filter(name=name).first())
self.assertEqual(bofreq.title, postdict['title']) self.assertEqual(bofreq.title, postdict['title'])
self.assertEqual(bofreq.rev, '00') self.assertEqual(bofreq.rev, '00')
self.assertEqual(bofreq.get_state_slug(), 'proposed') self.assertEqual(bofreq.get_state_slug(), 'proposed')

View file

@ -388,7 +388,7 @@ class ConflictReviewSubmitTests(TestCase):
# Right now, nothing to test - we let people put whatever the web browser will let them put into that textbox # Right now, nothing to test - we let people put whatever the web browser will let them put into that textbox
# sane post using textbox # sane post using textbox
path = os.path.join(settings.CONFLICT_REVIEW_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev)) path = os.path.join(settings.CONFLICT_REVIEW_PATH, '%s-%s.txt' % (doc.name, doc.rev))
self.assertEqual(doc.rev,'00') self.assertEqual(doc.rev,'00')
self.assertFalse(os.path.exists(path)) self.assertFalse(os.path.exists(path))
r = self.client.post(url,dict(content="Some initial review text\n",submit_response="1")) r = self.client.post(url,dict(content="Some initial review text\n",submit_response="1"))
@ -408,7 +408,7 @@ class ConflictReviewSubmitTests(TestCase):
# A little additional setup # A little additional setup
# doc.rev is u'00' per the test setup - double-checking that here - if it fails, the breakage is in setUp # doc.rev is u'00' per the test setup - double-checking that here - if it fails, the breakage is in setUp
self.assertEqual(doc.rev,'00') self.assertEqual(doc.rev,'00')
path = os.path.join(settings.CONFLICT_REVIEW_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev)) path = os.path.join(settings.CONFLICT_REVIEW_PATH, '%s-%s.txt' % (doc.name, doc.rev))
with io.open(path,'w') as f: with io.open(path,'w') as f:
f.write('This is the old proposal.') f.write('This is the old proposal.')
f.close() f.close()
@ -435,7 +435,7 @@ class ConflictReviewSubmitTests(TestCase):
self.assertEqual(r.status_code, 302) self.assertEqual(r.status_code, 302)
doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission') doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
self.assertEqual(doc.rev,'01') self.assertEqual(doc.rev,'01')
path = os.path.join(settings.CONFLICT_REVIEW_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev)) path = os.path.join(settings.CONFLICT_REVIEW_PATH, '%s-%s.txt' % (doc.name, doc.rev))
with io.open(path) as f: with io.open(path) as f:
self.assertEqual(f.read(),"This is a new proposal.") self.assertEqual(f.read(),"This is a new proposal.")
f.close() f.close()

View file

@ -19,11 +19,8 @@ class Downref(TestCase):
super().setUp() super().setUp()
PersonFactory(name='Plain Man',user__username='plain') PersonFactory(name='Plain Man',user__username='plain')
self.draft = WgDraftFactory(name='draft-ietf-mars-test') self.draft = WgDraftFactory(name='draft-ietf-mars-test')
self.draftalias = self.draft.docalias.get(name='draft-ietf-mars-test')
self.doc = WgDraftFactory(name='draft-ietf-mars-approved-document',states=[('draft-iesg','rfcqueue')]) self.doc = WgDraftFactory(name='draft-ietf-mars-approved-document',states=[('draft-iesg','rfcqueue')])
self.docalias = self.doc.docalias.get(name='draft-ietf-mars-approved-document')
self.rfc = WgRfcFactory(rfc_number=9998) self.rfc = WgRfcFactory(rfc_number=9998)
self.rfcalias = self.rfc.docalias.get(name='rfc9998')
RelatedDocument.objects.create(source=self.doc, target=self.rfc, relationship_id='downref-approval') RelatedDocument.objects.create(source=self.doc, target=self.rfc, relationship_id='downref-approval')
def test_downref_registry(self): def test_downref_registry(self):

View file

@ -15,7 +15,7 @@ from django.conf import settings
from django.urls import reverse as urlreverse from django.urls import reverse as urlreverse
from django.utils import timezone from django.utils import timezone
from ietf.doc.models import Document, State, DocAlias, NewRevisionDocEvent from ietf.doc.models import Document, State, NewRevisionDocEvent
from ietf.group.factories import RoleFactory from ietf.group.factories import RoleFactory
from ietf.group.models import Group from ietf.group.models import Group
from ietf.meeting.factories import MeetingFactory, SessionFactory from ietf.meeting.factories import MeetingFactory, SessionFactory
@ -54,7 +54,6 @@ class GroupMaterialTests(TestCase):
doc = Document.objects.create(name="slides-testteam-test-file", rev="01", type_id="slides", group=group) doc = Document.objects.create(name="slides-testteam-test-file", rev="01", type_id="slides", group=group)
doc.set_state(State.objects.get(type="slides", slug="active")) doc.set_state(State.objects.get(type="slides", slug="active"))
doc.set_state(State.objects.get(type="reuse_policy", slug="multiple")) doc.set_state(State.objects.get(type="reuse_policy", slug="multiple"))
DocAlias.objects.create(name=doc.name).docs.add(doc)
NewRevisionDocEvent.objects.create(doc=doc,by=Person.objects.get(name="(System)"),rev='00',type='new_revision',desc='New revision available') NewRevisionDocEvent.objects.create(doc=doc,by=Person.objects.get(name="(System)"),rev='00',type='new_revision',desc='New revision available')
NewRevisionDocEvent.objects.create(doc=doc,by=Person.objects.get(name="(System)"),rev='01',type='new_revision',desc='New revision available') NewRevisionDocEvent.objects.create(doc=doc,by=Person.objects.get(name="(System)"),rev='01',type='new_revision',desc='New revision available')

View file

@ -23,7 +23,7 @@ import ietf.review.mailarch
from ietf.doc.factories import ( NewRevisionDocEventFactory, IndividualDraftFactory, WgDraftFactory, from ietf.doc.factories import ( NewRevisionDocEventFactory, IndividualDraftFactory, WgDraftFactory,
WgRfcFactory, ReviewFactory, DocumentFactory) WgRfcFactory, ReviewFactory, DocumentFactory)
from ietf.doc.models import ( Document, DocumentAuthor, RelatedDocument, DocEvent, ReviewRequestDocEvent, from ietf.doc.models import ( DocumentAuthor, RelatedDocument, DocEvent, ReviewRequestDocEvent,
ReviewAssignmentDocEvent, ) ReviewAssignmentDocEvent, )
from ietf.group.factories import RoleFactory, ReviewTeamFactory from ietf.group.factories import RoleFactory, ReviewTeamFactory
from ietf.group.models import Group from ietf.group.models import Group
@ -922,7 +922,8 @@ class ReviewTests(TestCase):
date_today().isoformat(), date_today().isoformat(),
] ]
review_name = "-".join(c for c in name_components if c).lower() review_name = "-".join(c for c in name_components if c).lower()
Document.objects.create(name=review_name,type_id='review',group=assignment.review_request.team)
ReviewFactory(name=review_name,type_id='review',group=assignment.review_request.team)
r = self.client.post(url, data={ r = self.client.post(url, data={
"result": ReviewResultName.objects.get(reviewteamsettings_review_results_set__group=assignment.review_request.team, slug="ready").pk, "result": ReviewResultName.objects.get(reviewteamsettings_review_results_set__group=assignment.review_request.team, slug="ready").pk,
@ -938,10 +939,9 @@ class ReviewTests(TestCase):
}) })
self.assertEqual(r.status_code, 302) self.assertEqual(r.status_code, 302)
r2 = self.client.get(r.url) r2 = self.client.get(r.url)
# FIXME-LARS: this fails when the tests are run with --debug-mode, i.e., DEBUG is set: self.assertEqual(r2.status_code, 200)
if not settings.DEBUG: self.assertEqual(len(r2.context['messages']),1)
self.assertEqual(len(r2.context['messages']),1) self.assertIn('Attempt to save review failed', list(r2.context['messages'])[0].message)
self.assertIn('Attempt to save review failed', list(r2.context['messages'])[0].message)
def test_partially_complete_review(self): def test_partially_complete_review(self):
assignment, url = self.setup_complete_review_test() assignment, url = self.setup_complete_review_test()

View file

@ -41,7 +41,7 @@ class IssueRSABBallotTests(TestCase):
self.client.login(username="rsab-chair", password="rsab-chair+password") self.client.login(username="rsab-chair", password="rsab-chair+password")
for name in [ for name in [
doc.canonical_name() doc.name
for doc in (individual_draft, wg_draft, rg_draft, ed_rfc) for doc in (individual_draft, wg_draft, rg_draft, ed_rfc)
]: ]:
url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=name)) url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=name))

View file

@ -12,7 +12,7 @@ from django.template.loader import render_to_string
from django.urls import reverse as urlreverse from django.urls import reverse as urlreverse
from ietf.doc.factories import StatementFactory, DocEventFactory from ietf.doc.factories import StatementFactory, DocEventFactory
from ietf.doc.models import Document, DocAlias, State, NewRevisionDocEvent from ietf.doc.models import Document, State, NewRevisionDocEvent
from ietf.group.models import Group from ietf.group.models import Group
from ietf.person.factories import PersonFactory from ietf.person.factories import PersonFactory
from ietf.utils.mail import outbox, empty_outbox from ietf.utils.mail import outbox, empty_outbox
@ -241,7 +241,6 @@ This test section has some text.
name=name, type_id="statement" name=name, type_id="statement"
).first() ).first()
self.assertIsNotNone(statement) self.assertIsNotNone(statement)
self.assertIsNotNone(DocAlias.objects.filter(name=name).first())
self.assertEqual(statement.title, postdict["title"]) self.assertEqual(statement.title, postdict["title"])
self.assertEqual(statement.rev, "00") self.assertEqual(statement.rev, "00")
self.assertEqual(statement.get_state_slug(), "active") self.assertEqual(statement.get_state_slug(), "active")

View file

@ -396,9 +396,9 @@ class StatusChangeTests(TestCase):
self.assertTrue(notification['Subject'].startswith('Approved:')) self.assertTrue(notification['Subject'].startswith('Approved:'))
notification_text = get_payload_text(notification) notification_text = get_payload_text(notification)
self.assertIn('The AD has approved changing the status', notification_text) self.assertIn('The AD has approved changing the status', notification_text)
self.assertIn(Document.objects.get(name='rfc9999').canonical_name(), notification_text) self.assertIn(Document.objects.get(name='rfc9999').name, notification_text)
self.assertIn(Document.objects.get(name='rfc9998').canonical_name(), notification_text) self.assertIn(Document.objects.get(name='rfc9998').name, notification_text)
self.assertNotIn(Document.objects.get(name='rfc14').canonical_name(), notification_text) self.assertNotIn(Document.objects.get(name='rfc14').name, notification_text)
self.assertNotIn('No value found for', notification_text) # make sure all interpolation values were set self.assertNotIn('No value found for', notification_text) # make sure all interpolation values were set
else: else:
self.assertEqual(len(outbox), 0) self.assertEqual(len(outbox), 0)
@ -501,7 +501,7 @@ class StatusChangeSubmitTests(TestCase):
# Right now, nothing to test - we let people put whatever the web browser will let them put into that textbox # Right now, nothing to test - we let people put whatever the web browser will let them put into that textbox
# sane post using textbox # sane post using textbox
path = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev)) path = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.name, doc.rev))
self.assertEqual(doc.rev,'00') self.assertEqual(doc.rev,'00')
self.assertFalse(os.path.exists(path)) self.assertFalse(os.path.exists(path))
r = self.client.post(url,dict(content="Some initial review text\n",submit_response="1")) r = self.client.post(url,dict(content="Some initial review text\n",submit_response="1"))
@ -520,7 +520,7 @@ class StatusChangeSubmitTests(TestCase):
# A little additional setup # A little additional setup
# doc.rev is u'00' per the test setup - double-checking that here - if it fails, the breakage is in setUp # doc.rev is u'00' per the test setup - double-checking that here - if it fails, the breakage is in setUp
self.assertEqual(doc.rev,'00') self.assertEqual(doc.rev,'00')
path = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev)) path = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.name, doc.rev))
with io.open(path,'w') as f: with io.open(path,'w') as f:
f.write('This is the old proposal.') f.write('This is the old proposal.')
f.close() f.close()
@ -552,7 +552,7 @@ class StatusChangeSubmitTests(TestCase):
self.assertEqual(r.status_code, 302) self.assertEqual(r.status_code, 302)
doc = Document.objects.get(name='status-change-imaginary-mid-review') doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertEqual(doc.rev,'01') self.assertEqual(doc.rev,'01')
path = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev)) path = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.name, doc.rev))
with io.open(path) as f: with io.open(path) as f:
self.assertEqual(f.read(),"This is a new proposal.") self.assertEqual(f.read(),"This is a new proposal.")
f.close() f.close()

View file

@ -340,16 +340,16 @@ class RebuildReferenceRelationsTests(TestCase):
'Test conditions set up incorrectly: wrong prior document relationships') 'Test conditions set up incorrectly: wrong prior document relationships')
for other_doc in [self.normative, self.informative, self.unknown]: for other_doc in [self.normative, self.informative, self.unknown]:
self.assertEqual( self.assertEqual(
self.doc.relateddocument_set.filter(target__name=other_doc.canonical_name()).count(), self.doc.relateddocument_set.filter(target__name=other_doc.name).count(),
0, 0,
'Test conditions set up incorrectly: new documents already related', 'Test conditions set up incorrectly: new documents already related',
) )
def _get_refs_return_value(self): def _get_refs_return_value(self):
return { return {
self.normative.canonical_name(): Draft.REF_TYPE_NORMATIVE, self.normative.name: Draft.REF_TYPE_NORMATIVE,
self.informative.canonical_name(): Draft.REF_TYPE_INFORMATIVE, self.informative.name: Draft.REF_TYPE_INFORMATIVE,
self.unknown.canonical_name(): Draft.REF_TYPE_UNKNOWN, self.unknown.name: Draft.REF_TYPE_UNKNOWN,
'draft-not-found': Draft.REF_TYPE_NORMATIVE, 'draft-not-found': Draft.REF_TYPE_NORMATIVE,
} }
@ -388,9 +388,9 @@ class RebuildReferenceRelationsTests(TestCase):
self.assertCountEqual( self.assertCountEqual(
self.doc.relateddocument_set.values_list('target__name', 'relationship__slug'), self.doc.relateddocument_set.values_list('target__name', 'relationship__slug'),
[ [
(self.normative.canonical_name(), 'refnorm'), (self.normative.name, 'refnorm'),
(self.informative.canonical_name(), 'refinfo'), (self.informative.name, 'refinfo'),
(self.unknown.canonical_name(), 'refunk'), (self.unknown.name, 'refunk'),
(self.updated.name, 'updates'), (self.updated.name, 'updates'),
] ]
) )
@ -419,9 +419,9 @@ class RebuildReferenceRelationsTests(TestCase):
self.assertCountEqual( self.assertCountEqual(
self.doc.relateddocument_set.values_list('target__name', 'relationship__slug'), self.doc.relateddocument_set.values_list('target__name', 'relationship__slug'),
[ [
(self.normative.canonical_name(), 'refnorm'), (self.normative.name, 'refnorm'),
(self.informative.canonical_name(), 'refinfo'), (self.informative.name, 'refinfo'),
(self.unknown.canonical_name(), 'refunk'), (self.unknown.name, 'refunk'),
(self.updated.name, 'updates'), (self.updated.name, 'updates'),
] ]
) )
@ -451,9 +451,9 @@ class RebuildReferenceRelationsTests(TestCase):
self.assertCountEqual( self.assertCountEqual(
self.doc.relateddocument_set.values_list('target__name', 'relationship__slug'), self.doc.relateddocument_set.values_list('target__name', 'relationship__slug'),
[ [
(self.normative.canonical_name(), 'refnorm'), (self.normative.name, 'refnorm'),
(self.informative.canonical_name(), 'refinfo'), (self.informative.name, 'refinfo'),
(self.unknown.canonical_name(), 'refunk'), (self.unknown.name, 'refunk'),
(self.updated.name, 'updates'), (self.updated.name, 'updates'),
] ]
) )

View file

@ -90,7 +90,7 @@ urlpatterns = [
url(r'^all/?$', views_search.index_all_drafts), url(r'^all/?$', views_search.index_all_drafts),
url(r'^active/?$', views_search.index_active_drafts), url(r'^active/?$', views_search.index_active_drafts),
url(r'^recent/?$', views_search.recent_drafts), url(r'^recent/?$', views_search.recent_drafts),
url(r'^select2search/(?P<model_name>(document|docalias))/(?P<doc_type>draft)/$', views_search.ajax_select2_search_docs), url(r'^select2search/(?P<model_name>document)/(?P<doc_type>draft)/$', views_search.ajax_select2_search_docs),
url(r'^ballots/irsg/$', views_ballot.irsg_ballot_status), url(r'^ballots/irsg/$', views_ballot.irsg_ballot_status),
url(r'^ballots/rsab/$', views_ballot.rsab_ballot_status), url(r'^ballots/rsab/$', views_ballot.rsab_ballot_status),

View file

@ -56,7 +56,7 @@ def save_document_in_history(doc):
# copy fields # copy fields
fields = get_model_fields_as_dict(doc) fields = get_model_fields_as_dict(doc)
fields["doc"] = doc fields["doc"] = doc
fields["name"] = doc.canonical_name() fields["name"] = doc.name
dochist = DocHistory(**fields) dochist = DocHistory(**fields)
dochist.save() dochist.save()
@ -775,7 +775,6 @@ def rebuild_reference_relations(doc, filenames):
if not refdoc and re.match(r"^draft-.*-\d{2}$", ref): if not refdoc and re.match(r"^draft-.*-\d{2}$", ref):
refdoc = Document.objects.filter(name=ref[:-3]) refdoc = Document.objects.filter(name=ref[:-3])
count = refdoc.count() count = refdoc.count()
# As of Dec 2021, DocAlias has a unique constraint on the name field, so count > 1 should not occur
if count == 0: if count == 0:
unfound.add( "%s" % ref ) unfound.add( "%s" % ref )
continue continue
@ -933,22 +932,20 @@ def make_rev_history(doc):
if predecessors is None: if predecessors is None:
predecessors = [] predecessors = []
if hasattr(doc, 'relateddocument_set'): if hasattr(doc, 'relateddocument_set'):
for alias in doc.related_that_doc('replaces'): for document in doc.related_that_doc('replaces'):
for document in alias.docs.all(): if document not in predecessors:
if document not in predecessors: predecessors.append(document)
predecessors.append(document) predecessors.extend(get_predecessors(document, predecessors))
predecessors.extend(get_predecessors(document, predecessors))
return predecessors return predecessors
def get_ancestors(doc, ancestors = None): def get_ancestors(doc, ancestors = None):
if ancestors is None: if ancestors is None:
ancestors = [] ancestors = []
if hasattr(doc, 'relateddocument_set'): if hasattr(doc, 'relateddocument_set'):
for alias in doc.related_that('replaces'): for document in doc.related_that('replaces'):
for document in alias.docs.all(): if document not in ancestors:
if document not in ancestors: ancestors.append(document)
ancestors.append(document) ancestors.extend(get_ancestors(document, ancestors))
ancestors.extend(get_ancestors(document, ancestors))
return ancestors return ancestors
def get_replaces_tree(doc): def get_replaces_tree(doc):
@ -981,8 +978,8 @@ def make_rev_history(doc):
if e: if e:
url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=e.doc)) url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=e.doc))
history[url] = { history[url] = {
'name': e.doc.canonical_name(), 'name': e.doc.name,
'rev': e.doc.canonical_name(), 'rev': e.doc.name,
'published': e.time.isoformat(), 'published': e.time.isoformat(),
'url': url 'url': url
} }
@ -1120,12 +1117,15 @@ def generate_idnits2_rfc_status():
# Workarounds for unusual states in the datatracker # Workarounds for unusual states in the datatracker
# Document.get(docalias='rfc6312').rfc_number == 6342 # The explanation for 6312 is from before docalias was removed
# 6312 was published with the wrong rfc number in it # The workaround is still needed, even if the datatracker
# weird workaround in the datatracker - there are two # state no longer matches what's described here:
# DocAliases starting with rfc - the canonical name code # Document.get(docalias='rfc6312').rfc_number == 6342
# searches for the lexically highest alias starting with rfc # 6312 was published with the wrong rfc number in it
# which is getting lucky. # weird workaround in the datatracker - there are two
# DocAliases starting with rfc - the canonical name code
# searches for the lexically highest alias starting with rfc
# which is getting lucky.
blob[6312 - 1] = 'O' blob[6312 - 1] = 'O'
# RFC200 is an old RFC List by Number # RFC200 is an old RFC List by Number
@ -1177,12 +1177,12 @@ def fuzzy_find_documents(name, rev=None):
sought_type = "draft" sought_type = "draft"
# see if we can find a document using this name # see if we can find a document using this name
docs = Document.objects.filter(docalias__name=name, type_id=sought_type) docs = Document.objects.filter(name=name, type_id=sought_type)
if rev and not docs.exists(): if rev and not docs.exists():
# No document found, see if the name/rev split has been misidentified. # No document found, see if the name/rev split has been misidentified.
# Handles some special cases, like draft-ietf-tsvwg-ieee-802-11. # Handles some special cases, like draft-ietf-tsvwg-ieee-802-11.
name = '%s-%s' % (name, rev) name = '%s-%s' % (name, rev)
docs = Document.objects.filter(docalias__name=name, type_id='draft') docs = Document.objects.filter(name=name, type_id='draft')
if docs.exists(): if docs.exists():
rev = None # found a doc by name with rev = None, so update that rev = None # found a doc by name with rev = None, so update that

View file

@ -9,7 +9,7 @@ from zoneinfo import ZoneInfo
from django.conf import settings from django.conf import settings
from ietf.doc.models import Document, DocAlias, RelatedDocument, DocEvent, TelechatDocEvent, BallotDocEvent from ietf.doc.models import Document, RelatedDocument, DocEvent, TelechatDocEvent, BallotDocEvent
from ietf.doc.expire import expirable_drafts from ietf.doc.expire import expirable_drafts
from ietf.doc.utils import augment_docs_and_user_with_user_info from ietf.doc.utils import augment_docs_and_user_with_user_info
from ietf.meeting.models import SessionPresentation, Meeting, Session from ietf.meeting.models import SessionPresentation, Meeting, Session
@ -54,12 +54,13 @@ def fill_in_document_sessions(docs, doc_dict, doc_ids):
def fill_in_document_table_attributes(docs, have_telechat_date=False): def fill_in_document_table_attributes(docs, have_telechat_date=False):
# fill in some attributes for the document table results to save # fill in some attributes for the document table results to save
# some hairy template code and avoid repeated SQL queries # some hairy template code and avoid repeated SQL queries
# TODO - this function evolved from something that assumed it was handling only drafts. It still has places where it assumes all docs are drafts where that is not a correct assumption # TODO - this function evolved from something that assumed it was handling only drafts.
# It still has places where it assumes all docs are drafts where that is not a correct assumption
doc_dict = dict((d.pk, d) for d in docs) doc_dict = dict((d.pk, d) for d in docs)
doc_ids = list(doc_dict.keys()) doc_ids = list(doc_dict.keys())
rfc_aliases = dict([ (a.document.id, a.name) for a in DocAlias.objects.filter(name__startswith="rfc", docs__id__in=doc_ids) ]) rfcs = dict((d.pk, d.name) for d in docs if d.type_id == "rfc")
# latest event cache # latest event cache
event_types = ("published_rfc", event_types = ("published_rfc",
@ -90,8 +91,6 @@ def fill_in_document_table_attributes(docs, have_telechat_date=False):
# misc # misc
expirable_pks = expirable_drafts(Document.objects.filter(pk__in=doc_ids)).values_list('pk', flat=True) expirable_pks = expirable_drafts(Document.objects.filter(pk__in=doc_ids)).values_list('pk', flat=True)
for d in docs: for d in docs:
# emulate canonical name which is used by a lot of the utils
# d.canonical_name = wrap_value(rfc_aliases[d.pk] if d.pk in rfc_aliases else d.name)
if d.type_id == "rfc" and d.latest_event_cache["published_rfc"]: if d.type_id == "rfc" and d.latest_event_cache["published_rfc"]:
d.latest_revision_date = d.latest_event_cache["published_rfc"].time d.latest_revision_date = d.latest_event_cache["published_rfc"].time
@ -128,29 +127,30 @@ def fill_in_document_table_attributes(docs, have_telechat_date=False):
# RFCs # RFCs
# errata # errata
erratas = set(Document.objects.filter(tags="errata", id__in=list(rfc_aliases.keys())).distinct().values_list("name", flat=True)) erratas = set(Document.objects.filter(tags="errata", id__in=list(rfcs.keys())).distinct().values_list("name", flat=True))
verified_erratas = set(Document.objects.filter(tags="verified-errata", id__in=list(rfc_aliases.keys())).distinct().values_list("name", flat=True)) verified_erratas = set(Document.objects.filter(tags="verified-errata", id__in=list(rfcs.keys())).distinct().values_list("name", flat=True))
for d in docs: for d in docs:
d.has_errata = d.name in erratas d.has_errata = d.name in erratas
d.has_verified_errata = d.name in verified_erratas d.has_verified_errata = d.name in verified_erratas
# obsoleted/updated by # obsoleted/updated by
for a in rfc_aliases: for rfc in rfcs:
d = doc_dict[a] d = doc_dict[rfc]
d.obsoleted_by_list = [] d.obsoleted_by_list = []
d.updated_by_list = [] d.updated_by_list = []
# Revisit this block after RFCs become first-class Document objects # Revisit this block after RFCs become first-class Document objects
xed_by = list( xed_by = list(
RelatedDocument.objects.filter( RelatedDocument.objects.filter(
target__name__in=list(rfc_aliases.values()), target__name__in=list(rfcs.values()),
relationship__in=("obs", "updates"), relationship__in=("obs", "updates"),
).select_related("target") ).select_related("target")
) )
rel_rfc_aliases = { # TODO - this likely reduces to something even simpler
rel_rfcs = {
a.document.id: re.sub(r"rfc(\d+)", r"RFC \1", a.name, flags=re.IGNORECASE) a.document.id: re.sub(r"rfc(\d+)", r"RFC \1", a.name, flags=re.IGNORECASE)
for a in DocAlias.objects.filter( for a in Document.objects.filter(
name__startswith="rfc", docs__id__in=[rel.source_id for rel in xed_by] type_id="rfc", id__in=[rel.source_id for rel in xed_by]
) )
} }
xed_by.sort( xed_by.sort(
@ -158,7 +158,7 @@ def fill_in_document_table_attributes(docs, have_telechat_date=False):
re.sub( re.sub(
r"rfc\s*(\d+)", r"rfc\s*(\d+)",
r"\1", r"\1",
rel_rfc_aliases[rel.source_id], rel_rfcs[rel.source_id],
flags=re.IGNORECASE, flags=re.IGNORECASE,
) )
) )
@ -192,7 +192,7 @@ def prepare_document_table(request, docs, query=None, max_results=200):
# the number of queries # the number of queries
docs = docs.select_related("ad", "std_level", "intended_std_level", "group", "stream", "shepherd", ) docs = docs.select_related("ad", "std_level", "intended_std_level", "group", "stream", "shepherd", )
docs = docs.prefetch_related("states__type", "tags", "groupmilestone_set__group", "reviewrequest_set__team", docs = docs.prefetch_related("states__type", "tags", "groupmilestone_set__group", "reviewrequest_set__team",
"ad__email_set", "docalias__iprdocrel_set") "ad__email_set", "iprdocrel_set")
docs = docs[:max_results] # <- that is still a queryset, but with a LIMIT now docs = docs[:max_results] # <- that is still a queryset, but with a LIMIT now
docs = list(docs) docs = list(docs)
else: else:
@ -249,7 +249,7 @@ def prepare_document_table(request, docs, query=None, max_results=200):
if rfc_num is not None: if rfc_num is not None:
res.append(rfc_num) res.append(rfc_num)
else: else:
res.append(d.canonical_name()) res.append(d.name)
return res return res

View file

@ -179,7 +179,7 @@ def save_position(form, doc, ballot, balloter, login=None, send_email=False):
@role_required("Area Director", "Secretariat", "IRSG Member", "RSAB Member") @role_required("Area Director", "Secretariat", "IRSG Member", "RSAB Member")
def edit_position(request, name, ballot_id): def edit_position(request, name, ballot_id):
"""Vote and edit discuss and comment on document""" """Vote and edit discuss and comment on document"""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
ballot = get_object_or_404(BallotDocEvent, type="created_ballot", pk=ballot_id, doc=doc) ballot = get_object_or_404(BallotDocEvent, type="created_ballot", pk=ballot_id, doc=doc)
balloter = login = request.user.person balloter = login = request.user.person
@ -256,7 +256,7 @@ def api_set_position(request):
if not name: if not name:
return err(400, "Missing document name") return err(400, "Missing document name")
try: try:
doc = Document.objects.get(docalias__name=name) doc = Document.objects.get(name=name)
except Document.DoesNotExist: except Document.DoesNotExist:
return err(400, "Document not found") return err(400, "Document not found")
position_names = BallotPositionName.objects.values_list('slug', flat=True) position_names = BallotPositionName.objects.values_list('slug', flat=True)
@ -323,7 +323,7 @@ def build_position_email(balloter, doc, pos):
@role_required('Area Director','Secretariat','IRSG Member', 'RSAB Member') @role_required('Area Director','Secretariat','IRSG Member', 'RSAB Member')
def send_ballot_comment(request, name, ballot_id): def send_ballot_comment(request, name, ballot_id):
"""Email document ballot position discuss/comment for Area Director.""" """Email document ballot position discuss/comment for Area Director."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
ballot = get_object_or_404(BallotDocEvent, type="created_ballot", pk=ballot_id, doc=doc) ballot = get_object_or_404(BallotDocEvent, type="created_ballot", pk=ballot_id, doc=doc)
if not has_role(request.user, 'Secretariat'): if not has_role(request.user, 'Secretariat'):
@ -413,7 +413,7 @@ def clear_ballot(request, name, ballot_type_slug):
@role_required('Area Director','Secretariat') @role_required('Area Director','Secretariat')
def defer_ballot(request, name): def defer_ballot(request, name):
"""Signal post-pone of ballot, notifying relevant parties.""" """Signal post-pone of ballot, notifying relevant parties."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if doc.type_id not in ('draft','conflrev','statchg'): if doc.type_id not in ('draft','conflrev','statchg'):
raise Http404 raise Http404
interesting_state = dict(draft='draft-iesg',conflrev='conflrev',statchg='statchg') interesting_state = dict(draft='draft-iesg',conflrev='conflrev',statchg='statchg')
@ -467,7 +467,7 @@ def defer_ballot(request, name):
@role_required('Area Director','Secretariat') @role_required('Area Director','Secretariat')
def undefer_ballot(request, name): def undefer_ballot(request, name):
"""undo deferral of ballot ballot.""" """undo deferral of ballot ballot."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if doc.type_id not in ('draft','conflrev','statchg'): if doc.type_id not in ('draft','conflrev','statchg'):
raise Http404 raise Http404
if doc.type_id == 'draft' and not doc.get_state("draft-iesg"): if doc.type_id == 'draft' and not doc.get_state("draft-iesg"):
@ -503,7 +503,7 @@ class LastCallTextForm(forms.Form):
@role_required('Area Director','Secretariat') @role_required('Area Director','Secretariat')
def lastcalltext(request, name): def lastcalltext(request, name):
"""Editing of the last call text""" """Editing of the last call text"""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if not doc.get_state("draft-iesg"): if not doc.get_state("draft-iesg"):
raise Http404 raise Http404
@ -589,7 +589,7 @@ class BallotWriteupForm(forms.Form):
@role_required('Area Director','Secretariat') @role_required('Area Director','Secretariat')
def ballot_writeupnotes(request, name): def ballot_writeupnotes(request, name):
"""Editing of ballot write-up and notes""" """Editing of ballot write-up and notes"""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
prev_state = doc.get_state("draft-iesg") prev_state = doc.get_state("draft-iesg")
login = request.user.person login = request.user.person
@ -700,7 +700,7 @@ class BallotRfcEditorNoteForm(forms.Form):
@role_required('Area Director','Secretariat','IAB Chair','IRTF Chair','ISE') @role_required('Area Director','Secretariat','IAB Chair','IRTF Chair','ISE')
def ballot_rfceditornote(request, name): def ballot_rfceditornote(request, name):
"""Editing of RFC Editor Note""" """Editing of RFC Editor Note"""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if not is_authorized_in_doc_stream(request.user, doc): if not is_authorized_in_doc_stream(request.user, doc):
permission_denied(request, "You do not have the necessary permissions to change the RFC Editor Note for this document") permission_denied(request, "You do not have the necessary permissions to change the RFC Editor Note for this document")
@ -765,7 +765,7 @@ class ApprovalTextForm(forms.Form):
@role_required('Area Director','Secretariat') @role_required('Area Director','Secretariat')
def ballot_approvaltext(request, name): def ballot_approvaltext(request, name):
"""Editing of approval text""" """Editing of approval text"""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if not doc.get_state("draft-iesg"): if not doc.get_state("draft-iesg"):
raise Http404 raise Http404
@ -816,7 +816,7 @@ def ballot_approvaltext(request, name):
@role_required('Secretariat') @role_required('Secretariat')
def approve_ballot(request, name): def approve_ballot(request, name):
"""Approve ballot, sending out announcement, changing state.""" """Approve ballot, sending out announcement, changing state."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if not doc.get_state("draft-iesg"): if not doc.get_state("draft-iesg"):
raise Http404 raise Http404
@ -947,7 +947,7 @@ class ApproveDownrefsForm(forms.Form):
@role_required('Secretariat') @role_required('Secretariat')
def approve_downrefs(request, name): def approve_downrefs(request, name):
"""Document ballot was just approved; add the checked downwared references to the downref registry.""" """Document ballot was just approved; add the checked downwared references to the downref registry."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if not doc.get_state("draft-iesg"): if not doc.get_state("draft-iesg"):
raise Http404 raise Http404
@ -1001,7 +1001,7 @@ class MakeLastCallForm(forms.Form):
@role_required('Secretariat') @role_required('Secretariat')
def make_last_call(request, name): def make_last_call(request, name):
"""Make last call for Internet-Draft, sending out announcement.""" """Make last call for Internet-Draft, sending out announcement."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if not (doc.get_state("draft-iesg") or doc.get_state("statchg")): if not (doc.get_state("draft-iesg") or doc.get_state("statchg")):
raise Http404 raise Http404
@ -1109,7 +1109,7 @@ def make_last_call(request, name):
@role_required('Secretariat', 'IRTF Chair') @role_required('Secretariat', 'IRTF Chair')
def issue_irsg_ballot(request, name): def issue_irsg_ballot(request, name):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if doc.stream.slug != "irtf" or doc.type != DocTypeName.objects.get(slug="draft"): if doc.stream.slug != "irtf" or doc.type != DocTypeName.objects.get(slug="draft"):
raise Http404 raise Http404
@ -1164,7 +1164,7 @@ def issue_irsg_ballot(request, name):
@role_required('Secretariat', 'IRTF Chair') @role_required('Secretariat', 'IRTF Chair')
def close_irsg_ballot(request, name): def close_irsg_ballot(request, name):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if doc.stream.slug != "irtf" or doc.type != DocTypeName.objects.get(slug="draft"): if doc.stream.slug != "irtf" or doc.type != DocTypeName.objects.get(slug="draft"):
raise Http404 raise Http404
@ -1205,7 +1205,7 @@ def irsg_ballot_status(request):
@role_required('Secretariat', 'RSAB Chair') @role_required('Secretariat', 'RSAB Chair')
def issue_rsab_ballot(request, name): def issue_rsab_ballot(request, name):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if doc.stream.slug != "editorial" or doc.type != DocTypeName.objects.get(slug="draft"): if doc.stream.slug != "editorial" or doc.type != DocTypeName.objects.get(slug="draft"):
raise Http404 raise Http404
@ -1254,7 +1254,7 @@ def issue_rsab_ballot(request, name):
@role_required('Secretariat', 'RSAB Chair') @role_required('Secretariat', 'RSAB Chair')
def close_rsab_ballot(request, name): def close_rsab_ballot(request, name):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if doc.stream.slug != "editorial" or doc.type_id != "draft": if doc.stream.slug != "editorial" or doc.type_id != "draft":
raise Http404 raise Http404

View file

@ -15,7 +15,7 @@ from django.utils.html import escape
from ietf.doc.mails import (email_bofreq_title_changed, email_bofreq_editors_changed, from ietf.doc.mails import (email_bofreq_title_changed, email_bofreq_editors_changed,
email_bofreq_new_revision, email_bofreq_responsible_changed) email_bofreq_new_revision, email_bofreq_responsible_changed)
from ietf.doc.models import (Document, DocAlias, DocEvent, NewRevisionDocEvent, from ietf.doc.models import (Document, DocEvent, NewRevisionDocEvent,
BofreqEditorDocEvent, BofreqResponsibleDocEvent, State) BofreqEditorDocEvent, BofreqResponsibleDocEvent, State)
from ietf.doc.utils import add_state_change_event from ietf.doc.utils import add_state_change_event
from ietf.doc.utils_bofreq import bofreq_editors, bofreq_responsible from ietf.doc.utils_bofreq import bofreq_editors, bofreq_responsible
@ -168,8 +168,6 @@ def new_bof_request(request):
) )
e2.editors.set([request.user.person]) e2.editors.set([request.user.person])
bofreq.save_with_history([e1,e2]) bofreq.save_with_history([e1,e2])
alias = DocAlias.objects.create(name=name)
alias.docs.set([bofreq])
bofreq_submission = form.cleaned_data['bofreq_submission'] bofreq_submission = form.cleaned_data['bofreq_submission']
if bofreq_submission == "upload": if bofreq_submission == "upload":
content = get_cleaned_text_file_content(form.cleaned_data["bofreq_file"]) content = get_cleaned_text_file_content(form.cleaned_data["bofreq_file"])

View file

@ -22,7 +22,7 @@ from django.utils.html import escape
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import ( Document, DocAlias, DocHistory, State, DocEvent, from ietf.doc.models import ( Document, DocHistory, State, DocEvent,
BallotDocEvent, BallotPositionDocEvent, InitialReviewDocEvent, NewRevisionDocEvent, BallotDocEvent, BallotPositionDocEvent, InitialReviewDocEvent, NewRevisionDocEvent,
WriteupDocEvent, TelechatDocEvent ) WriteupDocEvent, TelechatDocEvent )
from ietf.doc.utils import ( add_state_change_event, close_open_ballots, from ietf.doc.utils import ( add_state_change_event, close_open_ballots,
@ -412,7 +412,6 @@ def submit(request, name, option=None):
abstract=group.name, abstract=group.name,
rev=next_rev, rev=next_rev,
) )
DocAlias.objects.create(name=name).docs.add(charter)
charter.set_state( charter.set_state(
State.objects.get(used=True, type="charter", slug="notrev") State.objects.get(used=True, type="charter", slug="notrev")

View file

@ -16,7 +16,7 @@ from django.utils.html import escape
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import ( BallotDocEvent, BallotPositionDocEvent, DocAlias, DocEvent, from ietf.doc.models import ( BallotDocEvent, BallotPositionDocEvent, DocEvent,
Document, NewRevisionDocEvent, State ) Document, NewRevisionDocEvent, State )
from ietf.doc.utils import ( add_state_change_event, close_open_ballots, from ietf.doc.utils import ( add_state_change_event, close_open_ballots,
create_ballot_if_not_open, update_telechat ) create_ballot_if_not_open, update_telechat )
@ -171,7 +171,7 @@ class UploadForm(forms.Form):
return get_cleaned_text_file_content(self.cleaned_data["txt"]) return get_cleaned_text_file_content(self.cleaned_data["txt"])
def save(self, review): def save(self, review):
filename = os.path.join(settings.CONFLICT_REVIEW_PATH, '%s-%s.txt' % (review.canonical_name(), review.rev)) filename = os.path.join(settings.CONFLICT_REVIEW_PATH, '%s-%s.txt' % (review.name, review.rev))
with io.open(filename, 'w', encoding='utf-8') as destination: with io.open(filename, 'w', encoding='utf-8') as destination:
if self.cleaned_data['txt']: if self.cleaned_data['txt']:
destination.write(self.cleaned_data['txt']) destination.write(self.cleaned_data['txt'])
@ -185,7 +185,7 @@ def submit(request, name):
login = request.user.person login = request.user.person
path = os.path.join(settings.CONFLICT_REVIEW_PATH, '%s-%s.txt' % (review.canonical_name(), review.rev)) path = os.path.join(settings.CONFLICT_REVIEW_PATH, '%s-%s.txt' % (review.name, review.rev))
not_uploaded_yet = review.rev == "00" and not os.path.exists(path) not_uploaded_yet = review.rev == "00" and not os.path.exists(path)
if not_uploaded_yet: if not_uploaded_yet:
@ -202,7 +202,7 @@ def submit(request, name):
events = [] events = []
e = NewRevisionDocEvent(doc=review, by=login, type="new_revision") e = NewRevisionDocEvent(doc=review, by=login, type="new_revision")
e.desc = "New version available: <b>%s-%s.txt</b>" % (review.canonical_name(), review.rev) e.desc = "New version available: <b>%s-%s.txt</b>" % (review.name, review.rev)
e.rev = review.rev e.rev = review.rev
e.save() e.save()
events.append(e) events.append(e)
@ -234,7 +234,7 @@ def submit(request, name):
dict(), dict(),
)) ))
else: else:
filename = os.path.join(settings.CONFLICT_REVIEW_PATH, '%s-%s.txt' % (review.canonical_name(), review.rev)) filename = os.path.join(settings.CONFLICT_REVIEW_PATH, '%s-%s.txt' % (review.name, review.rev))
try: try:
with io.open(filename, 'r') as f: with io.open(filename, 'r') as f:
init["content"] = f.read() init["content"] = f.read()
@ -276,7 +276,7 @@ def edit_ad(request, name):
conflictdoc = review.relateddocument_set.get(relationship__slug='conflrev').target conflictdoc = review.relateddocument_set.get(relationship__slug='conflrev').target
titletext = 'the conflict review of %s-%s' % (conflictdoc.canonical_name(),conflictdoc.rev) titletext = 'the conflict review of %s-%s' % (conflictdoc.name,conflictdoc.rev)
return render(request, 'doc/change_ad.html', return render(request, 'doc/change_ad.html',
{'form': form, {'form': form,
'doc': review, 'doc': review,
@ -448,9 +448,6 @@ def build_conflict_review_document(login, doc_to_review, ad, notify, create_in_s
group=iesg_group, group=iesg_group,
) )
conflict_review.set_state(create_in_state) conflict_review.set_state(create_in_state)
DocAlias.objects.create( name=review_name).docs.add( conflict_review )
conflict_review.relateddocument_set.create(target=doc_to_review, relationship_id='conflrev') conflict_review.relateddocument_set.create(target=doc_to_review, relationship_id='conflrev')

View file

@ -193,7 +193,7 @@ def document_main(request, name, rev=None, document_html=False):
if name.startswith("rfc") and rev is not None: if name.startswith("rfc") and rev is not None:
raise Http404() raise Http404()
doc = get_object_or_404(Document.objects.select_related(), docalias__name=name) doc = get_object_or_404(Document.objects.select_related(), name=name)
# take care of possible redirections # take care of possible redirections
if document_html is False and rev is None: if document_html is False and rev is None:
@ -328,9 +328,9 @@ def document_main(request, name, rev=None, document_html=False):
if html: if html:
css += Path(finders.find("ietf/css/document_html_txt.css")).read_text() css += Path(finders.find("ietf/css/document_html_txt.css")).read_text()
draft_that_became_rfc = None draft_that_became_rfc = None
became_rfc_alias = next(iter(doc.related_that("became_rfc")), None) became_rfc = next(iter(doc.related_that("became_rfc")), None)
if became_rfc_alias: if became_rfc:
draft_that_became_rfc = became_rfc_alias.document draft_that_became_rfc = became_rfc
# submission # submission
submission = "" submission = ""
if group is None: if group is None:
@ -796,7 +796,7 @@ def document_main(request, name, rev=None, document_html=False):
)) ))
elif doc.type_id == "conflrev": elif doc.type_id == "conflrev":
filename = "%s-%s.txt" % (doc.canonical_name(), doc.rev) filename = "%s-%s.txt" % (doc.name, doc.rev)
pathname = os.path.join(settings.CONFLICT_REVIEW_PATH,filename) pathname = os.path.join(settings.CONFLICT_REVIEW_PATH,filename)
if doc.rev == "00" and not os.path.isfile(pathname): if doc.rev == "00" and not os.path.isfile(pathname):
@ -826,7 +826,7 @@ def document_main(request, name, rev=None, document_html=False):
)) ))
elif doc.type_id == "statchg": elif doc.type_id == "statchg":
filename = "%s-%s.txt" % (doc.canonical_name(), doc.rev) filename = "%s-%s.txt" % (doc.name, doc.rev)
pathname = os.path.join(settings.STATUS_CHANGE_PATH,filename) pathname = os.path.join(settings.STATUS_CHANGE_PATH,filename)
if doc.rev == "00" and not os.path.isfile(pathname): if doc.rev == "00" and not os.path.isfile(pathname):
@ -866,7 +866,7 @@ def document_main(request, name, rev=None, document_html=False):
# we need to remove the extension for the globbing below to work # we need to remove the extension for the globbing below to work
basename = os.path.splitext(doc.uploaded_filename)[0] basename = os.path.splitext(doc.uploaded_filename)[0]
else: else:
basename = "%s-%s" % (doc.canonical_name(), doc.rev) basename = "%s-%s" % (doc.name, doc.rev)
pathname = os.path.join(doc.get_file_path(), basename) pathname = os.path.join(doc.get_file_path(), basename)
@ -1051,7 +1051,7 @@ def document_html(request, name, rev=None):
if not requested_rev and doc.type_id == "rfc": # Someone asked for /doc/html/8989 if not requested_rev and doc.type_id == "rfc": # Someone asked for /doc/html/8989
if not name.startswith('rfc'): if not name.startswith('rfc'):
return redirect('ietf.doc.views_doc.document_html', name=doc.canonical_name()) return redirect('ietf.doc.views_doc.document_html', name=doc.name)
if rev: if rev:
doc = doc.history_set.filter(rev=rev).first() or doc.fake_history_obj(rev) doc = doc.history_set.filter(rev=rev).first() or doc.fake_history_obj(rev)
@ -1061,7 +1061,7 @@ def document_html(request, name, rev=None):
return document_main( return document_main(
request, request,
name=doc.name if requested_rev else doc.canonical_name(), name=doc.name if requested_rev else doc.name,
rev=doc.rev if requested_rev or doc.type_id != "rfc" else None, rev=doc.rev if requested_rev or doc.type_id != "rfc" else None,
document_html=True, document_html=True,
) )
@ -1124,7 +1124,7 @@ def get_doc_email_aliases(name):
return aliases return aliases
def document_email(request,name): def document_email(request,name):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
top = render_document_top(request, doc, "email", name) top = render_document_top(request, doc, "email", name)
aliases = get_doc_email_aliases(name) if doc.type_id=='draft' else None aliases = get_doc_email_aliases(name) if doc.type_id=='draft' else None
@ -1168,12 +1168,15 @@ def get_diff_revisions(request, name, doc):
relateddocument__relationship="replaces", relateddocument__relationship="replaces",
) )
) )
diff_documents.extend(
Document.objects.filter(
relateddocument__target=doc,
relateddocument__relationship="became_rfc"
)
)
if doc.get_state_slug() == "rfc": if doc.type_id == "rfc":
e = doc.latest_event(type="published_rfc") e = doc.latest_event(type="published_rfc")
aliases = doc.docalias.filter(name__startswith="rfc")
if aliases:
name = aliases[0].name
diff_revisions.append((name, "", e.time if e else doc.time, name)) diff_revisions.append((name, "", e.time if e else doc.time, name))
seen = set() seen = set()
@ -1209,7 +1212,7 @@ def get_diff_revisions(request, name, doc):
def document_history(request, name): def document_history(request, name):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
top = render_document_top(request, doc, "history", name) top = render_document_top(request, doc, "history", name)
diff_revisions = get_diff_revisions(request, name, doc) diff_revisions = get_diff_revisions(request, name, doc)
@ -1276,7 +1279,7 @@ def document_bibtex(request, name, rev=None):
name = name+"-"+rev name = name+"-"+rev
rev = None rev = None
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
doi = None doi = None
draft_became_rfc = None draft_became_rfc = None
@ -1285,7 +1288,7 @@ def document_bibtex(request, name, rev=None):
if doc.type_id == "draft": if doc.type_id == "draft":
latest_revision = doc.latest_event(NewRevisionDocEvent, type="new_revision") latest_revision = doc.latest_event(NewRevisionDocEvent, type="new_revision")
replaced_by = [d.name for d in doc.related_that("replaces")] replaced_by = [d.name for d in doc.related_that("replaces")]
draft_became_rfc_alias = next(iter(doc.related_that_doc("became_rfc")), None) draft_became_rfc = next(iter(doc.related_that_doc("became_rfc")), None)
if rev != None and rev != doc.rev: if rev != None and rev != doc.rev:
# find the entry in the history # find the entry in the history
@ -1293,14 +1296,10 @@ def document_bibtex(request, name, rev=None):
if rev == h.rev: if rev == h.rev:
doc = h doc = h
break break
if draft_became_rfc_alias:
draft_became_rfc = draft_became_rfc_alias.document
elif doc.type_id == "rfc": elif doc.type_id == "rfc":
# This needs to be replaced with a lookup, as the mapping may change # This needs to be replaced with a lookup, as the mapping may change
# over time. Probably by updating ietf/sync/rfceditor.py to add the # over time.
# as a DocAlias, and use a method on Document to retrieve it.
doi = f"10.17487/RFC{doc.rfc_number:04d}" doi = f"10.17487/RFC{doc.rfc_number:04d}"
if doc.is_dochistory(): if doc.is_dochistory():
@ -1348,7 +1347,7 @@ def document_bibxml(request, name, rev=None):
def document_writeup(request, name): def document_writeup(request, name):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
top = render_document_top(request, doc, "writeup", name) top = render_document_top(request, doc, "writeup", name)
def text_from_writeup(event_type): def text_from_writeup(event_type):
@ -1412,7 +1411,7 @@ def document_writeup(request, name):
)) ))
def document_shepherd_writeup(request, name): def document_shepherd_writeup(request, name):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
lastwriteup = doc.latest_event(WriteupDocEvent,type="changed_protocol_writeup") lastwriteup = doc.latest_event(WriteupDocEvent,type="changed_protocol_writeup")
if lastwriteup: if lastwriteup:
writeup_text = lastwriteup.text writeup_text = lastwriteup.text
@ -1449,12 +1448,12 @@ def document_shepherd_writeup_template(request, type):
def document_references(request, name): def document_references(request, name):
doc = get_object_or_404(Document,docalias__name=name) doc = get_object_or_404(Document,name=name)
refs = doc.references() refs = doc.references()
return render(request, "doc/document_references.html",dict(doc=doc,refs=sorted(refs,key=lambda x:x.target.name),)) return render(request, "doc/document_references.html",dict(doc=doc,refs=sorted(refs,key=lambda x:x.target.name),))
def document_referenced_by(request, name): def document_referenced_by(request, name):
doc = get_object_or_404(Document,docalias__name=name) doc = get_object_or_404(Document,name=name)
refs = doc.referenced_by() refs = doc.referenced_by()
full = ( request.GET.get('full') != None ) full = ( request.GET.get('full') != None )
numdocs = refs.count() numdocs = refs.count()
@ -1462,9 +1461,9 @@ def document_referenced_by(request, name):
refs=refs[:250] refs=refs[:250]
else: else:
numdocs=None numdocs=None
refs=sorted(refs,key=lambda x:(['refnorm','refinfo','refunk','refold'].index(x.relationship.slug),x.source.canonical_name())) refs=sorted(refs,key=lambda x:(['refnorm','refinfo','refunk','refold'].index(x.relationship.slug),x.source.name))
return render(request, "doc/document_referenced_by.html", return render(request, "doc/document_referenced_by.html",
dict(alias_name=name, dict(name=name,
doc=doc, doc=doc,
numdocs=numdocs, numdocs=numdocs,
refs=refs, refs=refs,
@ -1538,7 +1537,7 @@ def document_ballot_content(request, doc, ballot_id, editable=True):
request=request) request=request)
def document_ballot(request, name, ballot_id=None): def document_ballot(request, name, ballot_id=None):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
all_ballots = list(BallotDocEvent.objects.filter(doc=doc, type="created_ballot").order_by("time")) all_ballots = list(BallotDocEvent.objects.filter(doc=doc, type="created_ballot").order_by("time"))
if not ballot_id: if not ballot_id:
if all_ballots: if all_ballots:
@ -1574,7 +1573,7 @@ def document_ballot(request, name, ballot_id=None):
)) ))
def document_irsg_ballot(request, name, ballot_id=None): def document_irsg_ballot(request, name, ballot_id=None):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
top = render_document_top(request, doc, "irsgballot", name) top = render_document_top(request, doc, "irsgballot", name)
if not ballot_id: if not ballot_id:
ballot = doc.latest_event(BallotDocEvent, type="created_ballot", ballot_type__slug='irsg-approve') ballot = doc.latest_event(BallotDocEvent, type="created_ballot", ballot_type__slug='irsg-approve')
@ -1593,7 +1592,7 @@ def document_irsg_ballot(request, name, ballot_id=None):
)) ))
def document_rsab_ballot(request, name, ballot_id=None): def document_rsab_ballot(request, name, ballot_id=None):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
top = render_document_top(request, doc, "rsabballot", name) top = render_document_top(request, doc, "rsabballot", name)
if not ballot_id: if not ballot_id:
ballot = doc.latest_event(BallotDocEvent, type="created_ballot", ballot_type__slug='rsab-approve') ballot = doc.latest_event(BallotDocEvent, type="created_ballot", ballot_type__slug='rsab-approve')
@ -1615,7 +1614,7 @@ def document_rsab_ballot(request, name, ballot_id=None):
) )
def ballot_popup(request, name, ballot_id): def ballot_popup(request, name, ballot_id):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
c = document_ballot_content(request, doc, ballot_id=ballot_id, editable=False) c = document_ballot_content(request, doc, ballot_id=ballot_id, editable=False)
ballot = get_object_or_404(BallotDocEvent,id=ballot_id) ballot = get_object_or_404(BallotDocEvent,id=ballot_id)
return render(request, "doc/ballot_popup.html", return render(request, "doc/ballot_popup.html",
@ -1628,7 +1627,7 @@ def ballot_popup(request, name, ballot_id):
def document_json(request, name, rev=None): def document_json(request, name, rev=None):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
def extract_name(s): def extract_name(s):
return s.name if s else None return s.name if s else None
@ -1648,7 +1647,8 @@ def document_json(request, name, rev=None):
data["expires"] = doc.expires.strftime("%Y-%m-%d %H:%M:%S") if doc.expires else None data["expires"] = doc.expires.strftime("%Y-%m-%d %H:%M:%S") if doc.expires else None
data["title"] = doc.title data["title"] = doc.title
data["abstract"] = doc.abstract data["abstract"] = doc.abstract
data["aliases"] = list(doc.docalias.values_list("name", flat=True)) # Preserve aliases in this api? What about showing rfc_number directly?
data["aliases"] = list(doc.name)
data["state"] = extract_name(doc.get_state()) data["state"] = extract_name(doc.get_state())
data["intended_std_level"] = extract_name(doc.intended_std_level) data["intended_std_level"] = extract_name(doc.intended_std_level)
data["std_level"] = extract_name(doc.std_level) data["std_level"] = extract_name(doc.std_level)
@ -1683,7 +1683,7 @@ class AddCommentForm(forms.Form):
@role_required('Area Director', 'Secretariat', 'IRTF Chair', 'WG Chair', 'RG Chair', 'WG Secretary', 'RG Secretary', 'IANA', 'RFC Editor') @role_required('Area Director', 'Secretariat', 'IRTF Chair', 'WG Chair', 'RG Chair', 'WG Secretary', 'RG Secretary', 'IANA', 'RFC Editor')
def add_comment(request, name): def add_comment(request, name):
"""Add comment to history of document.""" """Add comment to history of document."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
login = request.user.person login = request.user.person
@ -1768,8 +1768,8 @@ def telechat_date(request, name):
def doc_titletext(doc): def doc_titletext(doc):
if doc.type.slug=='conflrev': if doc.type.slug=='conflrev':
conflictdoc = doc.relateddocument_set.get(relationship__slug='conflrev').target conflictdoc = doc.relateddocument_set.get(relationship__slug='conflrev').target
return 'the conflict review of %s' % conflictdoc.canonical_name() return 'the conflict review of %s' % conflictdoc.name
return doc.canonical_name() return doc.name
def edit_notify(request, name): def edit_notify(request, name):
@ -2008,7 +2008,7 @@ def remind_action_holders(request, name):
form = ReminderEmailForm(request.POST) form = ReminderEmailForm(request.POST)
if form.is_valid(): if form.is_valid():
email_remind_action_holders(request, doc, form.cleaned_data['note']) email_remind_action_holders(request, doc, form.cleaned_data['note'])
return redirect('ietf.doc.views_doc.document_main', name=doc.canonical_name()) return redirect('ietf.doc.views_doc.document_main', name=doc.name)
form = ReminderEmailForm() form = ReminderEmailForm()
return render( return render(
@ -2173,14 +2173,13 @@ def idnits2_rfc_status(request):
def idnits2_state(request, name, rev=None): def idnits2_state(request, name, rev=None):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if doc.type_id not in ["draft", "rfc"]: if doc.type_id not in ["draft", "rfc"]:
raise Http404 raise Http404
zero_revision = None zero_revision = None
if doc.type_id == "rfc": if doc.type_id == "rfc":
draft_alias = next(iter(doc.related_that('became_rfc')), None) draft = next(iter(doc.related_that('became_rfc')), None)
if draft_alias: if draft:
draft = draft_alias.document
zero_revision = NewRevisionDocEvent.objects.filter(doc=draft,rev='00').first() zero_revision = NewRevisionDocEvent.objects.filter(doc=draft,rev='00').first()
else: else:
zero_revision = NewRevisionDocEvent.objects.filter(doc=doc,rev='00').first() zero_revision = NewRevisionDocEvent.objects.filter(doc=doc,rev='00').first()

View file

@ -66,7 +66,7 @@ class ChangeStateForm(forms.Form):
state = self.cleaned_data.get('state', '(None)') state = self.cleaned_data.get('state', '(None)')
tag = self.cleaned_data.get('substate','') tag = self.cleaned_data.get('substate','')
comment = self.cleaned_data['comment'].strip() # pyflakes:ignore comment = self.cleaned_data['comment'].strip() # pyflakes:ignore
doc = get_object_or_404(Document, docalias__name=self.docname) doc = get_object_or_404(Document, name=self.docname)
prev = doc.get_state("draft-iesg") prev = doc.get_state("draft-iesg")
# tag handling is a bit awkward since the UI still works # tag handling is a bit awkward since the UI still works
@ -86,7 +86,7 @@ class ChangeStateForm(forms.Form):
def change_state(request, name): def change_state(request, name):
"""Change IESG state of Internet-Draft, notifying parties as necessary """Change IESG state of Internet-Draft, notifying parties as necessary
and logging the change as a comment.""" and logging the change as a comment."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if (not doc.latest_event(type="started_iesg_process")) or doc.get_state_slug() == "expired": if (not doc.latest_event(type="started_iesg_process")) or doc.get_state_slug() == "expired":
raise Http404 raise Http404
@ -205,7 +205,7 @@ class AddIanaExpertsCommentForm(forms.Form):
@role_required('Secretariat', 'IANA') @role_required('Secretariat', 'IANA')
def add_iana_experts_comment(request, name): def add_iana_experts_comment(request, name):
doc = get_object_or_404(Document, docalias__name = name) doc = get_object_or_404(Document, name = name)
if request.method == 'POST': if request.method == 'POST':
form = AddIanaExpertsCommentForm(request.POST) form = AddIanaExpertsCommentForm(request.POST)
if form.is_valid(): if form.is_valid():
@ -231,7 +231,7 @@ class ChangeIanaStateForm(forms.Form):
def change_iana_state(request, name, state_type): def change_iana_state(request, name, state_type):
"""Change IANA review state of Internet-Draft. Normally, this is done via """Change IANA review state of Internet-Draft. Normally, this is done via
automatic sync, but this form allows one to set it manually.""" automatic sync, but this form allows one to set it manually."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
state_type = doc.type_id + "-" + state_type state_type = doc.type_id + "-" + state_type
@ -271,7 +271,7 @@ class ChangeStreamForm(forms.Form):
def change_stream(request, name): def change_stream(request, name):
"""Change the stream of a Document of type 'draft', notifying parties as necessary """Change the stream of a Document of type 'draft', notifying parties as necessary
and logging the change as a comment.""" and logging the change as a comment."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if not doc.type_id=='draft': if not doc.type_id=='draft':
raise Http404 raise Http404
@ -352,7 +352,7 @@ class ReplacesForm(forms.Form):
def replaces(request, name): def replaces(request, name):
"""Change 'replaces' set of a Document of type 'draft' , notifying parties """Change 'replaces' set of a Document of type 'draft' , notifying parties
as necessary and logging the change as a comment.""" as necessary and logging the change as a comment."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if doc.type_id != 'draft': if doc.type_id != 'draft':
raise Http404 raise Http404
if not (has_role(request.user, ("Secretariat", "Area Director", "WG Chair", "RG Chair", "WG Secretary", "RG Secretary")) if not (has_role(request.user, ("Secretariat", "Area Director", "WG Chair", "RG Chair", "WG Secretary", "RG Secretary"))
@ -396,7 +396,7 @@ class SuggestedReplacesForm(forms.Form):
self.fields["replaces"].choices = [(d.pk, d.name) for d in suggested] self.fields["replaces"].choices = [(d.pk, d.name) for d in suggested]
def review_possibly_replaces(request, name): def review_possibly_replaces(request, name):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if doc.type_id != 'draft': if doc.type_id != 'draft':
raise Http404 raise Http404
if not (has_role(request.user, ("Secretariat", "Area Director")) if not (has_role(request.user, ("Secretariat", "Area Director"))
@ -451,7 +451,7 @@ class ChangeIntentionForm(forms.Form):
def change_intention(request, name): def change_intention(request, name):
"""Change the intended publication status of a Document of type 'draft' , notifying parties """Change the intended publication status of a Document of type 'draft' , notifying parties
as necessary and logging the change as a comment.""" as necessary and logging the change as a comment."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if doc.type_id != 'draft': if doc.type_id != 'draft':
raise Http404 raise Http404
@ -520,7 +520,7 @@ class EditInfoForm(forms.Form):
def to_iesg(request,name): def to_iesg(request,name):
""" Submit an IETF stream document to the IESG for publication """ """ Submit an IETF stream document to the IESG for publication """
doc = get_object_or_404(Document, docalias__name=name, stream='ietf') doc = get_object_or_404(Document, name=name, stream='ietf')
if doc.get_state_slug('draft') == "expired" or doc.get_state_slug('draft-iesg') == 'pub-req' : if doc.get_state_slug('draft') == "expired" or doc.get_state_slug('draft-iesg') == 'pub-req' :
raise Http404 raise Http404
@ -633,7 +633,7 @@ def to_iesg(request,name):
def edit_info(request, name): def edit_info(request, name):
"""Edit various Internet-Draft attributes, notifying parties as """Edit various Internet-Draft attributes, notifying parties as
necessary and logging changes as document events.""" necessary and logging changes as document events."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if doc.get_state_slug() == "expired": if doc.get_state_slug() == "expired":
raise Http404 raise Http404
@ -791,7 +791,7 @@ def edit_info(request, name):
@role_required('Area Director','Secretariat') @role_required('Area Director','Secretariat')
def request_resurrect(request, name): def request_resurrect(request, name):
"""Request resurrect of expired Internet-Draft.""" """Request resurrect of expired Internet-Draft."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if doc.get_state_slug() != "expired": if doc.get_state_slug() != "expired":
raise Http404 raise Http404
@ -814,7 +814,7 @@ def request_resurrect(request, name):
@role_required('Secretariat') @role_required('Secretariat')
def resurrect(request, name): def resurrect(request, name):
"""Resurrect expired Internet-Draft.""" """Resurrect expired Internet-Draft."""
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if doc.get_state_slug() != "expired": if doc.get_state_slug() != "expired":
raise Http404 raise Http404

View file

@ -16,7 +16,7 @@ from django.urls import reverse as urlreverse
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import Document, DocAlias, DocTypeName, DocEvent, State from ietf.doc.models import Document, DocTypeName, DocEvent, State
from ietf.doc.models import NewRevisionDocEvent from ietf.doc.models import NewRevisionDocEvent
from ietf.doc.utils import add_state_change_event, check_common_doc_name_rules from ietf.doc.utils import add_state_change_event, check_common_doc_name_rules
from ietf.group.models import Group from ietf.group.models import Group
@ -156,10 +156,6 @@ def edit_material(request, name=None, acronym=None, action=None, doc_type=None):
for chunk in f.chunks(): for chunk in f.chunks():
dest.write(chunk) dest.write(chunk)
if action == "new":
alias, __ = DocAlias.objects.get_or_create(name=doc.name)
alias.docs.add(doc)
if prev_rev != doc.rev: if prev_rev != doc.rev:
e = NewRevisionDocEvent(type="new_revision", doc=doc, rev=doc.rev) e = NewRevisionDocEvent(type="new_revision", doc=doc, rev=doc.rev)
e.by = request.user.person e.by = request.user.person

View file

@ -28,7 +28,7 @@ from django.core.exceptions import ValidationError
from django.template.loader import render_to_string, TemplateDoesNotExist from django.template.loader import render_to_string, TemplateDoesNotExist
from django.urls import reverse as urlreverse from django.urls import reverse as urlreverse
from ietf.doc.models import (Document, NewRevisionDocEvent, State, DocAlias, from ietf.doc.models import (Document, NewRevisionDocEvent, State,
LastCallDocEvent, ReviewRequestDocEvent, ReviewAssignmentDocEvent, DocumentAuthor) LastCallDocEvent, ReviewRequestDocEvent, ReviewAssignmentDocEvent, DocumentAuthor)
from ietf.name.models import (ReviewRequestStateName, ReviewAssignmentStateName, ReviewResultName, from ietf.name.models import (ReviewRequestStateName, ReviewAssignmentStateName, ReviewResultName,
ReviewTypeName) ReviewTypeName)
@ -715,9 +715,7 @@ def complete_review(request, name, assignment_id=None, acronym=None):
name=review_name, name=review_name,
defaults={'type_id': 'review', 'group': team}, defaults={'type_id': 'review', 'group': team},
) )
if created: if not created:
DocAlias.objects.create(name=review_name).docs.add(review)
else:
messages.warning(request, message='Attempt to save review failed: review document already exists. This most likely occurred because the review was submitted twice in quick succession. If you intended to submit a new review, rather than update an existing one, things are probably OK. Please verify that the shown review is what you expected.') messages.warning(request, message='Attempt to save review failed: review document already exists. This most likely occurred because the review was submitted twice in quick succession. If you intended to submit a new review, rather than update an existing one, things are probably OK. Please verify that the shown review is what you expected.')
return redirect("ietf.doc.views_doc.document_main", name=review_name) return redirect("ietf.doc.views_doc.document_main", name=review_name)
@ -1055,7 +1053,7 @@ class ReviewWishAddForm(forms.Form):
@login_required @login_required
def review_wish_add(request, name): def review_wish_add(request, name):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if request.method == "POST": if request.method == "POST":
form = ReviewWishAddForm(request.user, doc, request.POST) form = ReviewWishAddForm(request.user, doc, request.POST)
@ -1072,7 +1070,7 @@ def review_wish_add(request, name):
@login_required @login_required
def review_wishes_remove(request, name): def review_wishes_remove(request, name):
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
person = get_object_or_404(Person, user=request.user) person = get_object_or_404(Person, user=request.user)
if request.method == "POST": if request.method == "POST":

View file

@ -53,7 +53,7 @@ from django.utils.cache import _generate_cache_key # type: ignore
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import ( Document, DocHistory, DocAlias, State, from ietf.doc.models import ( Document, DocHistory, State,
LastCallDocEvent, NewRevisionDocEvent, IESG_SUBSTATE_TAGS, LastCallDocEvent, NewRevisionDocEvent, IESG_SUBSTATE_TAGS,
IESG_BALLOT_ACTIVE_STATES, IESG_STATCHG_CONFLREV_ACTIVE_STATES, IESG_BALLOT_ACTIVE_STATES, IESG_STATCHG_CONFLREV_ACTIVE_STATES,
IESG_CHARTER_ACTIVE_STATES ) IESG_CHARTER_ACTIVE_STATES )
@ -166,7 +166,7 @@ def retrieve_search_results(form, all_types=False):
# name # name
if query["name"]: if query["name"]:
docs = docs.filter(Q(docalias__name__icontains=query["name"]) | docs = docs.filter(Q(name__icontains=query["name"]) |
Q(title__icontains=query["name"])).distinct() Q(title__icontains=query["name"])).distinct()
# rfc/active/old check buttons # rfc/active/old check buttons
@ -248,17 +248,17 @@ def frontpage(request):
def search_for_name(request, name): def search_for_name(request, name):
def find_unique(n): def find_unique(n):
exact = DocAlias.objects.filter(name__iexact=n).first() exact = Document.objects.filter(name__iexact=n).first()
if exact: if exact:
return exact.name return exact.name
aliases = DocAlias.objects.filter(name__istartswith=n)[:2] startswith = Document.objects.filter(name__istartswith=n)[:2]
if len(aliases) == 1: if len(startswith) == 1:
return aliases[0].name return startswith[0].name
aliases = DocAlias.objects.filter(name__icontains=n)[:2] contains = Document.objects.filter(name__icontains=n)[:2]
if len(aliases) == 1: if len(contains) == 1:
return aliases[0].name return contains[0].name
return None return None
@ -291,7 +291,7 @@ def search_for_name(request, name):
if redirect_to: if redirect_to:
rev = rev_split.group(2) rev = rev_split.group(2)
# check if we can redirect directly to the rev if it's draft, if rfc - always redirect to main page # check if we can redirect directly to the rev if it's draft, if rfc - always redirect to main page
if not redirect_to.startswith('rfc') and DocHistory.objects.filter(doc__docalias__name=redirect_to, rev=rev).exists(): if not redirect_to.startswith('rfc') and DocHistory.objects.filter(doc__name=redirect_to, rev=rev).exists():
return cached_redirect(cache_key, urlreverse("ietf.doc.views_doc.document_main", kwargs={ "name": redirect_to, "rev": rev })) return cached_redirect(cache_key, urlreverse("ietf.doc.views_doc.document_main", kwargs={ "name": redirect_to, "rev": rev }))
else: else:
return cached_redirect(cache_key, urlreverse("ietf.doc.views_doc.document_main", kwargs={ "name": redirect_to })) return cached_redirect(cache_key, urlreverse("ietf.doc.views_doc.document_main", kwargs={ "name": redirect_to }))
@ -818,23 +818,12 @@ def index_all_drafts(request): # Should we rename this
else: else:
heading = "%s Internet-Drafts" % state.name heading = "%s Internet-Drafts" % state.name
draft_names = DocAlias.objects.filter(docs__type_id="draft", docs__states=state).values_list("name", "docs__name") drafts = Document.objects.filter(type_id="draft", states=state).order_by("name")
names = [] names = [
names_to_skip = set() f'<a href=\"{urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=doc.name))}\">{doc.name}</a>'
for name, doc in draft_names: for doc in drafts
sort_key = name ]
if name != doc:
if not name.startswith("rfc"):
name, doc = doc, name
names_to_skip.add(doc) # this is filtering out subseries docaliases (which we will delete, so TODO clean this out after doing so)
names.append((name, sort_key))
names.sort(key=lambda t: t[1])
names = [f'<a href=\"{urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=n))}\">{n}</a>'
for n, __ in names if n not in names_to_skip]
categories.append((state, categories.append((state,
heading, heading,
@ -843,24 +832,11 @@ def index_all_drafts(request): # Should we rename this
)) ))
# gather RFCs # gather RFCs
rfc_names = DocAlias.objects.filter(docs__type_id="rfc").values_list("name", "docs__name") rfcs = Document.objects.filter(type_id="rfc").order_by('-rfc_number')
names = [] names = [
names_to_skip = set() f'<a href=\"{urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=rfc.name))}\">{rfc.name.upper()}</a>'
for name, doc in rfc_names: for rfc in rfcs
sort_key = name ]
if name != doc: # There are some std docalias that pointed to rfc names pre-migration.
if not name.startswith("rfc"):
name, doc = doc, name
names_to_skip.add(doc) # this is filtering out those std docaliases (which we will delete, so TODO clean this out after doing so)
name = name.upper()
sort_key = '%09d' % (100000000-int(name[3:]))
names.append((name, sort_key))
names.sort(key=lambda t: t[1])
names = [f'<a href=\"{urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=n))}\">{n}</a>'
for n, __ in names if n not in names_to_skip]
state = State.objects.get(type_id="rfc", slug="published") state = State.objects.get(type_id="rfc", slug="published")
@ -884,23 +860,15 @@ def index_active_drafts(request):
slowcache.set(cache_key, groups, 15*60) slowcache.set(cache_key, groups, 15*60)
return render(request, "doc/index_active_drafts.html", { 'groups': groups }) return render(request, "doc/index_active_drafts.html", { 'groups': groups })
def ajax_select2_search_docs(request, model_name, doc_type): def ajax_select2_search_docs(request, model_name, doc_type): # TODO - remove model_name argument...
if model_name == "docalias": model = Document # Earlier versions allowed searching over DocAlias which no longer exists
model = DocAlias
else:
model = Document
q = [w.strip() for w in request.GET.get('q', '').split() if w.strip()] q = [w.strip() for w in request.GET.get('q', '').split() if w.strip()]
if not q: if not q:
objs = model.objects.none() objs = model.objects.none()
else: else:
qs = model.objects.all() qs = model.objects.filter(type=doc_type)
if model == Document:
qs = qs.filter(type=doc_type)
elif model == DocAlias:
qs = qs.filter(docs__type=doc_type)
for t in q: for t in q:
qs = qs.filter(name__icontains=t) qs = qs.filter(name__icontains=t)

View file

@ -13,7 +13,7 @@ from django.template.loader import render_to_string
from ietf.utils import markdown from ietf.utils import markdown
from django.utils.html import escape from django.utils.html import escape
from ietf.doc.models import Document, DocAlias, DocEvent, NewRevisionDocEvent, State from ietf.doc.models import Document, DocEvent, NewRevisionDocEvent, State
from ietf.group.models import Group from ietf.group.models import Group
from ietf.ietfauth.utils import role_required from ietf.ietfauth.utils import role_required
from ietf.utils.text import xslugify from ietf.utils.text import xslugify
@ -241,8 +241,6 @@ def new_statement(request):
desc="Statement published", desc="Statement published",
) )
statement.save_with_history([e1, e2]) statement.save_with_history([e1, e2])
alias = DocAlias.objects.create(name=name)
alias.docs.set([statement])
markdown_content = "" markdown_content = ""
if statement_submission == "upload": if statement_submission == "upload":
if not writing_pdf: if not writing_pdf:

View file

@ -21,7 +21,7 @@ from django.utils.html import escape
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.mails import email_ad_approved_status_change from ietf.doc.mails import email_ad_approved_status_change
from ietf.doc.models import ( Document, DocAlias, State, DocEvent, BallotDocEvent, from ietf.doc.models import ( Document, State, DocEvent, BallotDocEvent,
BallotPositionDocEvent, NewRevisionDocEvent, WriteupDocEvent, STATUSCHANGE_RELATIONS ) BallotPositionDocEvent, NewRevisionDocEvent, WriteupDocEvent, STATUSCHANGE_RELATIONS )
from ietf.doc.forms import AdForm from ietf.doc.forms import AdForm
from ietf.doc.lastcall import request_last_call from ietf.doc.lastcall import request_last_call
@ -99,7 +99,7 @@ def change_state(request, name, option=None):
) )
related_doc_info = [ related_doc_info = [
dict(title=rel_doc.target.title, dict(title=rel_doc.target.title,
canonical_name=rel_doc.target.canonical_name(), name=rel_doc.target.name,
newstatus=newstatus(rel_doc)) newstatus=newstatus(rel_doc))
for rel_doc in related_docs for rel_doc in related_docs
] ]
@ -148,7 +148,7 @@ class UploadForm(forms.Form):
return get_cleaned_text_file_content(self.cleaned_data["txt"]) return get_cleaned_text_file_content(self.cleaned_data["txt"])
def save(self, doc): def save(self, doc):
filename = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev)) filename = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.name, doc.rev))
with io.open(filename, 'w', encoding='utf-8') as destination: with io.open(filename, 'w', encoding='utf-8') as destination:
if self.cleaned_data['txt']: if self.cleaned_data['txt']:
destination.write(self.cleaned_data['txt']) destination.write(self.cleaned_data['txt'])
@ -162,7 +162,7 @@ def submit(request, name):
login = request.user.person login = request.user.person
path = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev)) path = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.name, doc.rev))
not_uploaded_yet = doc.rev == "00" and not os.path.exists(path) not_uploaded_yet = doc.rev == "00" and not os.path.exists(path)
if not_uploaded_yet: if not_uploaded_yet:
@ -179,7 +179,7 @@ def submit(request, name):
events = [] events = []
e = NewRevisionDocEvent(doc=doc, by=login, type="new_revision") e = NewRevisionDocEvent(doc=doc, by=login, type="new_revision")
e.desc = "New version available: <b>%s-%s.txt</b>" % (doc.canonical_name(), doc.rev) e.desc = "New version available: <b>%s-%s.txt</b>" % (doc.name, doc.rev)
e.rev = doc.rev e.rev = doc.rev
e.save() e.save()
events.append(e) events.append(e)
@ -211,7 +211,7 @@ def submit(request, name):
dict(), dict(),
) )
else: else:
filename = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev)) filename = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.name, doc.rev))
try: try:
with io.open(filename, 'r') as f: with io.open(filename, 'r') as f:
init["content"] = f.read() init["content"] = f.read()
@ -253,7 +253,7 @@ def edit_title(request, name):
init = { "title" : status_change.title } init = { "title" : status_change.title }
form = ChangeTitleForm(initial=init) form = ChangeTitleForm(initial=init)
titletext = '%s-%s.txt' % (status_change.canonical_name(),status_change.rev) titletext = '%s-%s.txt' % (status_change.name,status_change.rev)
return render(request, 'doc/change_title.html', return render(request, 'doc/change_title.html',
{'form': form, {'form': form,
'doc': status_change, 'doc': status_change,
@ -284,7 +284,7 @@ def edit_ad(request, name):
init = { "ad" : status_change.ad_id } init = { "ad" : status_change.ad_id }
form = AdForm(initial=init) form = AdForm(initial=init)
titletext = '%s-%s.txt' % (status_change.canonical_name(),status_change.rev) titletext = '%s-%s.txt' % (status_change.name,status_change.rev)
return render(request, 'doc/change_ad.html', return render(request, 'doc/change_ad.html',
{'form': form, {'form': form,
'doc': status_change, 'doc': status_change,
@ -399,7 +399,7 @@ def approve(request, name):
init = [] init = []
for rel in status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS): for rel in status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS):
init.append({"announcement_text" : escape(default_approval_text(status_change,rel)), init.append({"announcement_text" : escape(default_approval_text(status_change,rel)),
"label": "Announcement text for %s to %s"%(rel.target.canonical_name(),newstatus(rel)), "label": "Announcement text for %s to %s"%(rel.target.name,newstatus(rel)),
}) })
formset = AnnouncementFormSet(initial=init) formset = AnnouncementFormSet(initial=init)
for form in formset.forms: for form in formset.forms:
@ -537,7 +537,7 @@ def start_rfc_status_change(request, name=None):
if name: if name:
if not re.match("(?i)rfc[0-9]{1,4}",name): if not re.match("(?i)rfc[0-9]{1,4}",name):
raise Http404 raise Http404
seed_rfc = get_object_or_404(Document, type="draft", docalias__name=name) seed_rfc = get_object_or_404(Document, type="rfc", name=name)
login = request.user.person login = request.user.person
@ -560,8 +560,6 @@ def start_rfc_status_change(request, name=None):
group=iesg_group, group=iesg_group,
) )
status_change.set_state(form.cleaned_data['create_in_state']) status_change.set_state(form.cleaned_data['create_in_state'])
DocAlias.objects.create( name= 'status-change-'+form.cleaned_data['document_name']).docs.add(status_change)
for key in form.cleaned_data['relations']: for key in form.cleaned_data['relations']:
status_change.relateddocument_set.create(target=Document.objects.get(name=key), status_change.relateddocument_set.create(target=Document.objects.get(name=key),
@ -576,9 +574,9 @@ def start_rfc_status_change(request, name=None):
init = {} init = {}
if name: if name:
init['title'] = "%s to CHANGETHIS" % seed_rfc.title init['title'] = "%s to CHANGETHIS" % seed_rfc.title
init['document_name'] = "%s-to-CHANGETHIS" % seed_rfc.canonical_name() init['document_name'] = "%s-to-CHANGETHIS" % seed_rfc.name
relations={} relations={}
relations[seed_rfc.canonical_name()]=None relations[seed_rfc.name]=None
init['relations'] = relations init['relations'] = relations
form = StartStatusChangeForm(initial=init) form = StartStatusChangeForm(initial=init)
@ -604,7 +602,7 @@ def edit_relations(request, name):
old_relations={} old_relations={}
for rel in status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS): for rel in status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS):
old_relations[rel.target.canonical_name()]=rel.relationship.slug old_relations[rel.target.name]=rel.relationship.slug
new_relations=form.cleaned_data['relations'] new_relations=form.cleaned_data['relations']
status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS).delete() status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS).delete()
for key in new_relations: for key in new_relations:
@ -625,7 +623,7 @@ def edit_relations(request, name):
else: else:
relations={} relations={}
for rel in status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS): for rel in status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS):
relations[rel.target.canonical_name()]=rel.relationship.slug relations[rel.target.name]=rel.relationship.slug
init = { "relations":relations, init = { "relations":relations,
} }
form = EditStatusChangeForm(initial=init) form = EditStatusChangeForm(initial=init)

View file

@ -27,7 +27,7 @@ from django.utils.html import escape
from ietf.community.models import CommunityList from ietf.community.models import CommunityList
from ietf.community.utils import reset_name_contains_index_for_rule from ietf.community.utils import reset_name_contains_index_for_rule
from ietf.doc.factories import WgDraftFactory, IndividualDraftFactory, CharterFactory, BallotDocEventFactory from ietf.doc.factories import WgDraftFactory, IndividualDraftFactory, CharterFactory, BallotDocEventFactory
from ietf.doc.models import Document, DocAlias, DocEvent, State from ietf.doc.models import Document, DocEvent, State
from ietf.doc.utils_charter import charter_name_for_group from ietf.doc.utils_charter import charter_name_for_group
from ietf.group.admin import GroupForm as AdminGroupForm from ietf.group.admin import GroupForm as AdminGroupForm
from ietf.group.factories import (GroupFactory, RoleFactory, GroupEventFactory, from ietf.group.factories import (GroupFactory, RoleFactory, GroupEventFactory,
@ -387,7 +387,6 @@ class GroupPagesTests(TestCase):
type_id="slides", type_id="slides",
) )
doc.set_state(State.objects.get(type="slides", slug="active")) doc.set_state(State.objects.get(type="slides", slug="active"))
DocAlias.objects.create(name=doc.name).docs.add(doc)
for url in group_urlreverse_list(group, 'ietf.group.views.materials'): for url in group_urlreverse_list(group, 'ietf.group.views.materials'):
r = self.client.get(url) r = self.client.get(url)

View file

@ -61,7 +61,7 @@ import debug # pyflakes:ignore
from ietf.community.models import CommunityList, EmailSubscription from ietf.community.models import CommunityList, EmailSubscription
from ietf.community.utils import docs_tracked_by_community_list from ietf.community.utils import docs_tracked_by_community_list
from ietf.doc.models import DocTagName, State, DocAlias, RelatedDocument, Document, DocEvent from ietf.doc.models import DocTagName, State, RelatedDocument, Document, DocEvent
from ietf.doc.templatetags.ietf_filters import clean_whitespace from ietf.doc.templatetags.ietf_filters import clean_whitespace
from ietf.doc.utils import get_chartering_type, get_tags_for_stream_id from ietf.doc.utils import get_chartering_type, get_tags_for_stream_id
from ietf.doc.utils_charter import charter_name_for_group, replace_charter_of_replaced_group from ietf.doc.utils_charter import charter_name_for_group, replace_charter_of_replaced_group
@ -186,17 +186,12 @@ def fill_in_wg_roles(group):
group.secretaries = get_roles("secr", []) group.secretaries = get_roles("secr", [])
def fill_in_wg_drafts(group): def fill_in_wg_drafts(group):
aliases = DocAlias.objects.filter(docs__type="draft", docs__group=group).prefetch_related('docs').order_by("name") group.drafts = Document.objects.filter(type_id="draft", group=group).order_by("name")
group.drafts = [] group.rfcs = Document.objects.filter(type_id="rfc", group=group).order_by("rfc_number")
group.rfcs = [] for rfc in group.rfcs:
for a in aliases: # TODO: remote_field?
if a.name.startswith("draft"): rfc.remote_field = RelatedDocument.objects.filter(source=rfc,relationship_id__in=['obs','updates']).distinct()
group.drafts.append(a) rfc.invrel = RelatedDocument.objects.filter(target=rfc,relationship_id__in=['obs','updates']).distinct()
else:
group.rfcs.append(a)
a.remote_field = RelatedDocument.objects.filter(source=a.document,relationship_id__in=['obs','updates']).distinct()
a.invrel = RelatedDocument.objects.filter(target=a,relationship_id__in=['obs','updates']).distinct()
def check_group_email_aliases(): def check_group_email_aliases():
pattern = re.compile(r'expand-(.*?)(-\w+)@.*? +(.*)$') pattern = re.compile(r'expand-(.*?)(-\w+)@.*? +(.*)$')
@ -775,7 +770,7 @@ def dependencies(request, acronym, group_type=None):
graph = { graph = {
"nodes": [ "nodes": [
{ {
"id": x.canonical_name(), "id": x.name,
"rfc": x.get_state("draft").slug == "rfc", "rfc": x.get_state("draft").slug == "rfc",
"post-wg": not x.get_state("draft-iesg").slug "post-wg": not x.get_state("draft-iesg").slug
in ["idexists", "watching", "dead"], in ["idexists", "watching", "dead"],
@ -793,8 +788,8 @@ def dependencies(request, acronym, group_type=None):
], ],
"links": [ "links": [
{ {
"source": x.source.canonical_name(), "source": x.source.name,
"target": x.target.canonical_name(), "target": x.target.name,
"rel": "downref" if x.is_downref() else x.relationship.slug, "rel": "downref" if x.is_downref() else x.relationship.slug,
} }
for x in links for x in links

View file

@ -14,7 +14,7 @@ from django.utils import timezone
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import Document, DocEvent, DocumentAuthor, RelatedDocument, DocAlias, State from ietf.doc.models import Document, DocEvent, DocumentAuthor, RelatedDocument, State
from ietf.doc.models import LastCallDocEvent, NewRevisionDocEvent from ietf.doc.models import LastCallDocEvent, NewRevisionDocEvent
from ietf.doc.models import IESG_SUBSTATE_TAGS from ietf.doc.models import IESG_SUBSTATE_TAGS
from ietf.doc.templatetags.ietf_filters import clean_whitespace from ietf.doc.templatetags.ietf_filters import clean_whitespace
@ -31,15 +31,18 @@ def all_id_txt():
t = revision_time.get(name) t = revision_time.get(name)
return t.strftime("%Y-%m-%d") if t else "" return t.strftime("%Y-%m-%d") if t else ""
rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", rfcs = dict()
docs__states=State.objects.get(type="draft", slug="rfc")).values_list("docs__name", "name")) for rfc in Document.objects.filter(type_id="rfc"):
draft = next(iter(rfc.related_that("became_rfc")), None)
if draft is not None:
rfcs[draft.name] = rfc.name
replacements = dict(RelatedDocument.objects.filter(target__states=State.objects.get(type="draft", slug="repl"), replacements = dict(RelatedDocument.objects.filter(target__states=State.objects.get(type="draft", slug="repl"),
relationship="replaces").values_list("target__name", "source__name")) relationship="replaces").values_list("target__name", "source__name"))
# we need a distinct to prevent the queries below from multiplying the result # we need a distinct to prevent the queries below from multiplying the result
all_ids = Document.objects.filter(type="draft").order_by('name').exclude(name__startswith="rfc").distinct() all_ids = Document.objects.filter(type="draft").order_by('name').distinct()
res = ["\nInternet-Drafts Status Summary\n"] res = ["\nInternet-Drafts Status Summary\n"]
@ -77,9 +80,9 @@ def all_id_txt():
last_field = "" last_field = ""
if s.slug == "rfc": if s.slug == "rfc":
a = rfc_aliases.get(name) rfc = rfcs.get(name)
if a: if rfc:
last_field = a[3:] last_field = rfc[3:] # Rework this to take advantage of having the number at hand already.
elif s.slug == "repl": elif s.slug == "repl":
state += " replaced by " + replacements.get(name, "0") state += " replaced by " + replacements.get(name, "0")
@ -108,12 +111,15 @@ def file_types_for_drafts():
def all_id2_txt(): def all_id2_txt():
# this returns a lot of data so try to be efficient # this returns a lot of data so try to be efficient
drafts = Document.objects.filter(type="draft").exclude(name__startswith="rfc").order_by('name') drafts = Document.objects.filter(type="draft").order_by('name')
drafts = drafts.select_related('group', 'group__parent', 'ad', 'intended_std_level', 'shepherd', ) drafts = drafts.select_related('group', 'group__parent', 'ad', 'intended_std_level', 'shepherd', )
drafts = drafts.prefetch_related("states") drafts = drafts.prefetch_related("states")
rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", rfcs = dict()
docs__states=State.objects.get(type="draft", slug="rfc")).values_list("docs__name", "name")) for rfc in Document.objects.filter(type_id="rfc"):
draft = next(iter(rfc.related_that("became_rfc")), None)
if draft is not None:
rfcs[draft.name] = rfc.name
replacements = dict(RelatedDocument.objects.filter(target__states=State.objects.get(type="draft", slug="repl"), replacements = dict(RelatedDocument.objects.filter(target__states=State.objects.get(type="draft", slug="repl"),
relationship="replaces").values_list("target__name", "source__name")) relationship="replaces").values_list("target__name", "source__name"))
@ -164,9 +170,9 @@ def all_id2_txt():
# 4 # 4
rfc_number = "" rfc_number = ""
if state == "rfc": if state == "rfc":
a = rfc_aliases.get(d.name) rfc = rfcs.get(d.name)
if a: if rfc:
rfc_number = a[3:] rfc_number = rfc[3:]
fields.append(rfc_number) fields.append(rfc_number)
# 5 # 5
repl = "" repl = ""

View file

@ -11,8 +11,8 @@ from django.utils import timezone
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.factories import WgDraftFactory from ietf.doc.factories import WgDraftFactory, RfcFactory
from ietf.doc.models import Document, DocAlias, RelatedDocument, State, LastCallDocEvent, NewRevisionDocEvent from ietf.doc.models import Document, RelatedDocument, State, LastCallDocEvent, NewRevisionDocEvent
from ietf.group.factories import GroupFactory from ietf.group.factories import GroupFactory
from ietf.name.models import DocRelationshipName from ietf.name.models import DocRelationshipName
from ietf.idindex.index import all_id_txt, all_id2_txt, id_index_txt from ietf.idindex.index import all_id_txt, all_id2_txt, id_index_txt
@ -41,7 +41,8 @@ class IndexTests(TestCase):
# published # published
draft.set_state(State.objects.get(type="draft", slug="rfc")) draft.set_state(State.objects.get(type="draft", slug="rfc"))
DocAlias.objects.create(name="rfc1234").docs.add(draft) rfc = RfcFactory(rfc_number=1234)
draft.relateddocument_set.create(relationship_id="became_rfc", target=rfc)
txt = all_id_txt() txt = all_id_txt()
self.assertTrue(draft.name + "-" + draft.rev in txt) self.assertTrue(draft.name + "-" + draft.rev in txt)
@ -108,7 +109,8 @@ class IndexTests(TestCase):
# test RFC # test RFC
draft.set_state(State.objects.get(type="draft", slug="rfc")) draft.set_state(State.objects.get(type="draft", slug="rfc"))
DocAlias.objects.create(name="rfc1234").docs.add(draft) rfc = RfcFactory(rfc_number=1234)
draft.relateddocument_set.create(relationship_id="became_rfc", target=rfc)
t = get_fields(all_id2_txt()) t = get_fields(all_id2_txt())
self.assertEqual(t[4], "1234") self.assertEqual(t[4], "1234")

View file

@ -122,7 +122,7 @@ def agenda_json(request, date=None):
for doc in docs: for doc in docs:
wginfo = { wginfo = {
'docname': doc.canonical_name(), 'docname': doc.name,
'rev': doc.rev, 'rev': doc.rev,
'wgname': doc.group.name, 'wgname': doc.group.name,
'acronym': doc.group.acronym, 'acronym': doc.group.acronym,
@ -137,7 +137,7 @@ def agenda_json(request, date=None):
for doc in docs: for doc in docs:
docinfo = { docinfo = {
'docname':doc.canonical_name(), 'docname':doc.name,
'title':doc.title, 'title':doc.title,
'ad':doc.ad.name if doc.ad else None, 'ad':doc.ad.name if doc.ad else None,
} }
@ -173,7 +173,7 @@ def agenda_json(request, date=None):
elif doc.type_id == 'conflrev': elif doc.type_id == 'conflrev':
docinfo['rev'] = doc.rev docinfo['rev'] = doc.rev
td = doc.relateddocument_set.get(relationship__slug='conflrev').target td = doc.relateddocument_set.get(relationship__slug='conflrev').target
docinfo['target-docname'] = td.canonical_name() docinfo['target-docname'] = td.name
docinfo['target-title'] = td.title docinfo['target-title'] = td.title
docinfo['target-rev'] = td.rev docinfo['target-rev'] = td.rev
docinfo['intended-std-level'] = str(td.intended_std_level) docinfo['intended-std-level'] = str(td.intended_std_level)

View file

@ -41,7 +41,7 @@ class IprDisclosureBaseFactory(factory.django.DjangoModelFactory):
return return
if extracted: if extracted:
for doc in extracted: for doc in extracted:
IprDocRel.objects.create(disclosure=self,document=doc.docalias.first()) IprDocRel.objects.create(disclosure=self,document=doc)
@factory.post_generation @factory.post_generation
def updates(self, create, extracted, **kwargs): def updates(self, create, extracted, **kwargs):

View file

@ -14,7 +14,7 @@ from django.utils.encoding import force_str
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.group.models import Group from ietf.group.models import Group
from ietf.doc.fields import SearchableDocAliasField from ietf.doc.fields import SearchableDocumentField
from ietf.ipr.mail import utc_from_string from ietf.ipr.mail import utc_from_string
from ietf.ipr.fields import SearchableIprDisclosuresField from ietf.ipr.fields import SearchableIprDisclosuresField
from ietf.ipr.models import (IprDocRel, IprDisclosureBase, HolderIprDisclosure, from ietf.ipr.models import (IprDocRel, IprDisclosureBase, HolderIprDisclosure,
@ -95,7 +95,7 @@ class AddEmailForm(forms.Form):
return self.cleaned_data return self.cleaned_data
class DraftForm(forms.ModelForm): class DraftForm(forms.ModelForm):
document = SearchableDocAliasField(label="I-D name/RFC number", required=True, doc_type="draft") document = SearchableDocumentField(label="I-D name/RFC number", required=True, doc_type="draft") # TODO - this needs to be an or, or the form needs modification
class Meta: class Meta:
model = IprDocRel model = IprDocRel

View file

@ -0,0 +1,78 @@
# Generated by Django 4.2.2 on 2023-06-16 13:40
from django.db import migrations
import django.db.models.deletion
from django.db.models import F, Subquery, OuterRef
import ietf.utils.models
def forward(apps, schema_editor):
IprDocRel = apps.get_model("ipr", "IprDocRel")
DocAlias = apps.get_model("doc", "DocAlias")
subquery = Subquery(DocAlias.objects.filter(pk=OuterRef("deprecated_document")).values("docs")[:1])
IprDocRel.objects.annotate(firstdoc=subquery).update(document=F("firstdoc"))
# This might not be right - we may need here (and in the relateddocument migrations) to pay attention to
# whether the name being pointed to is and rfc name or a draft name and point to the right object instead...
def reverse(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
("ipr", "0001_initial"),
("doc", "0014_relate_hist_no_aliases")
]
operations = [
migrations.AlterField(
model_name='iprdocrel',
name='document',
field=ietf.utils.models.ForeignKey(
db_index=False,
on_delete=django.db.models.deletion.CASCADE,
to='doc.docalias',
),
),
migrations.RenameField(
model_name="iprdocrel",
old_name="document",
new_name="deprecated_document"
),
migrations.AlterField(
model_name='iprdocrel',
name='deprecated_document',
field=ietf.utils.models.ForeignKey(
db_index=True,
on_delete=django.db.models.deletion.CASCADE,
to='doc.docalias',
),
),
migrations.AddField(
model_name="iprdocrel",
name="document",
field=ietf.utils.models.ForeignKey(
default=1, # A lie, but a convenient one - no iprdocrel objects point here.
on_delete=django.db.models.deletion.CASCADE,
to="doc.document",
db_index=False,
),
preserve_default=False,
),
migrations.RunPython(forward, reverse),
migrations.AlterField(
model_name="iprdocrel",
name="document",
field=ietf.utils.models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="doc.document",
db_index=True,
),
),
migrations.RemoveField(
model_name="iprdocrel",
name="deprecated_document",
field=ietf.utils.models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to='doc.DocAlias',
),
),
]

View file

@ -0,0 +1,18 @@
# Copyright The IETF Trust 2023, All Rights Reserved
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("doc", "0015_delete_docalias"),
("ipr", "0002_iprdocrel_no_aliases"),
]
operations = [
migrations.AlterField(
model_name="iprdisclosurebase",
name="docs",
field=models.ManyToManyField(through="ipr.IprDocRel", to="doc.document"),
),
]

View file

@ -7,7 +7,7 @@ from django.db import models
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from ietf.doc.models import DocAlias, DocEvent from ietf.doc.models import Document, DocEvent
from ietf.name.models import DocRelationshipName,IprDisclosureStateName,IprLicenseTypeName,IprEventTypeName from ietf.name.models import DocRelationshipName,IprDisclosureStateName,IprLicenseTypeName,IprEventTypeName
from ietf.person.models import Person from ietf.person.models import Person
from ietf.message.models import Message from ietf.message.models import Message
@ -16,7 +16,7 @@ from ietf.utils.models import ForeignKey
class IprDisclosureBase(models.Model): class IprDisclosureBase(models.Model):
by = ForeignKey(Person) # who was logged in, or System if nobody was logged in by = ForeignKey(Person) # who was logged in, or System if nobody was logged in
compliant = models.BooleanField("Complies to RFC3979", default=True) compliant = models.BooleanField("Complies to RFC3979", default=True)
docs = models.ManyToManyField(DocAlias, through='IprDocRel') docs = models.ManyToManyField(Document, through='IprDocRel')
holder_legal_name = models.CharField(max_length=255) holder_legal_name = models.CharField(max_length=255)
notes = models.TextField("Additional notes", blank=True) notes = models.TextField("Additional notes", blank=True)
other_designations = models.CharField("Designations for other contributions", blank=True, max_length=255) other_designations = models.CharField("Designations for other contributions", blank=True, max_length=255)
@ -160,7 +160,7 @@ class GenericIprDisclosure(IprDisclosureBase):
class IprDocRel(models.Model): class IprDocRel(models.Model):
disclosure = ForeignKey(IprDisclosureBase) disclosure = ForeignKey(IprDisclosureBase)
document = ForeignKey(DocAlias) document = ForeignKey(Document)
sections = models.TextField(blank=True) sections = models.TextField(blank=True)
revisions = models.CharField(max_length=16,blank=True) # allows strings like 01-07 revisions = models.CharField(max_length=16,blank=True) # allows strings like 01-07
@ -233,10 +233,7 @@ class IprEvent(models.Model):
'removed': 'removed_related_ipr', 'removed': 'removed_related_ipr',
} }
if self.type_id in event_type_map: if self.type_id in event_type_map:
related_docs = set() # related docs, no duplicates for doc in self.disclosure.docs.distinct():
for alias in self.disclosure.docs.all():
related_docs.update(alias.docs.all())
for doc in related_docs:
DocEvent.objects.create( DocEvent.objects.create(
type=event_type_map[self.type_id], type=event_type_map[self.type_id],
time=self.time, time=self.time,

View file

@ -16,11 +16,11 @@ from ietf.ipr.models import ( IprDisclosureBase, IprDocRel, HolderIprDisclosure,
from ietf.person.resources import PersonResource from ietf.person.resources import PersonResource
from ietf.name.resources import IprDisclosureStateNameResource from ietf.name.resources import IprDisclosureStateNameResource
from ietf.doc.resources import DocAliasResource from ietf.doc.resources import DocumentResource
class IprDisclosureBaseResource(ModelResource): class IprDisclosureBaseResource(ModelResource):
by = ToOneField(PersonResource, 'by') by = ToOneField(PersonResource, 'by')
state = ToOneField(IprDisclosureStateNameResource, 'state') state = ToOneField(IprDisclosureStateNameResource, 'state')
docs = ToManyField(DocAliasResource, 'docs', null=True) docs = ToManyField(DocumentResource, 'docs', null=True)
rel = ToManyField('ietf.ipr.resources.IprDisclosureBaseResource', 'rel', null=True) rel = ToManyField('ietf.ipr.resources.IprDisclosureBaseResource', 'rel', null=True)
class Meta: class Meta:
queryset = IprDisclosureBase.objects.all() queryset = IprDisclosureBase.objects.all()
@ -45,10 +45,9 @@ class IprDisclosureBaseResource(ModelResource):
} }
api.ipr.register(IprDisclosureBaseResource()) api.ipr.register(IprDisclosureBaseResource())
from ietf.doc.resources import DocAliasResource
class IprDocRelResource(ModelResource): class IprDocRelResource(ModelResource):
disclosure = ToOneField(IprDisclosureBaseResource, 'disclosure') disclosure = ToOneField(IprDisclosureBaseResource, 'disclosure')
document = ToOneField(DocAliasResource, 'document') document = ToOneField(DocumentResource, 'document')
class Meta: class Meta:
cache = SimpleCache() cache = SimpleCache()
queryset = IprDocRel.objects.all() queryset = IprDocRel.objects.all()
@ -66,13 +65,12 @@ api.ipr.register(IprDocRelResource())
from ietf.person.resources import PersonResource from ietf.person.resources import PersonResource
from ietf.name.resources import IprDisclosureStateNameResource, IprLicenseTypeNameResource from ietf.name.resources import IprDisclosureStateNameResource, IprLicenseTypeNameResource
from ietf.doc.resources import DocAliasResource
class HolderIprDisclosureResource(ModelResource): class HolderIprDisclosureResource(ModelResource):
by = ToOneField(PersonResource, 'by') by = ToOneField(PersonResource, 'by')
state = ToOneField(IprDisclosureStateNameResource, 'state') state = ToOneField(IprDisclosureStateNameResource, 'state')
iprdisclosurebase_ptr = ToOneField(IprDisclosureBaseResource, 'iprdisclosurebase_ptr') iprdisclosurebase_ptr = ToOneField(IprDisclosureBaseResource, 'iprdisclosurebase_ptr')
licensing = ToOneField(IprLicenseTypeNameResource, 'licensing') licensing = ToOneField(IprLicenseTypeNameResource, 'licensing')
docs = ToManyField(DocAliasResource, 'docs', null=True) docs = ToManyField(DocumentResource, 'docs', null=True)
rel = ToManyField(IprDisclosureBaseResource, 'rel', null=True) rel = ToManyField(IprDisclosureBaseResource, 'rel', null=True)
class Meta: class Meta:
cache = SimpleCache() cache = SimpleCache()
@ -111,12 +109,11 @@ api.ipr.register(HolderIprDisclosureResource())
from ietf.person.resources import PersonResource from ietf.person.resources import PersonResource
from ietf.name.resources import IprDisclosureStateNameResource from ietf.name.resources import IprDisclosureStateNameResource
from ietf.doc.resources import DocAliasResource
class ThirdPartyIprDisclosureResource(ModelResource): class ThirdPartyIprDisclosureResource(ModelResource):
by = ToOneField(PersonResource, 'by') by = ToOneField(PersonResource, 'by')
state = ToOneField(IprDisclosureStateNameResource, 'state') state = ToOneField(IprDisclosureStateNameResource, 'state')
iprdisclosurebase_ptr = ToOneField(IprDisclosureBaseResource, 'iprdisclosurebase_ptr') iprdisclosurebase_ptr = ToOneField(IprDisclosureBaseResource, 'iprdisclosurebase_ptr')
docs = ToManyField(DocAliasResource, 'docs', null=True) docs = ToManyField(DocumentResource, 'docs', null=True)
rel = ToManyField(IprDisclosureBaseResource, 'rel', null=True) rel = ToManyField(IprDisclosureBaseResource, 'rel', null=True)
class Meta: class Meta:
cache = SimpleCache() cache = SimpleCache()
@ -168,12 +165,11 @@ api.ipr.register(RelatedIprResource())
from ietf.person.resources import PersonResource from ietf.person.resources import PersonResource
from ietf.name.resources import IprDisclosureStateNameResource from ietf.name.resources import IprDisclosureStateNameResource
from ietf.doc.resources import DocAliasResource
class NonDocSpecificIprDisclosureResource(ModelResource): class NonDocSpecificIprDisclosureResource(ModelResource):
by = ToOneField(PersonResource, 'by') by = ToOneField(PersonResource, 'by')
state = ToOneField(IprDisclosureStateNameResource, 'state') state = ToOneField(IprDisclosureStateNameResource, 'state')
iprdisclosurebase_ptr = ToOneField(IprDisclosureBaseResource, 'iprdisclosurebase_ptr') iprdisclosurebase_ptr = ToOneField(IprDisclosureBaseResource, 'iprdisclosurebase_ptr')
docs = ToManyField(DocAliasResource, 'docs', null=True) docs = ToManyField(DocumentResource, 'docs', null=True)
rel = ToManyField(IprDisclosureBaseResource, 'rel', null=True) rel = ToManyField(IprDisclosureBaseResource, 'rel', null=True)
class Meta: class Meta:
cache = SimpleCache() cache = SimpleCache()
@ -207,12 +203,11 @@ api.ipr.register(NonDocSpecificIprDisclosureResource())
from ietf.person.resources import PersonResource from ietf.person.resources import PersonResource
from ietf.name.resources import IprDisclosureStateNameResource from ietf.name.resources import IprDisclosureStateNameResource
from ietf.doc.resources import DocAliasResource
class GenericIprDisclosureResource(ModelResource): class GenericIprDisclosureResource(ModelResource):
by = ToOneField(PersonResource, 'by') by = ToOneField(PersonResource, 'by')
state = ToOneField(IprDisclosureStateNameResource, 'state') state = ToOneField(IprDisclosureStateNameResource, 'state')
iprdisclosurebase_ptr = ToOneField(IprDisclosureBaseResource, 'iprdisclosurebase_ptr') iprdisclosurebase_ptr = ToOneField(IprDisclosureBaseResource, 'iprdisclosurebase_ptr')
docs = ToManyField(DocAliasResource, 'docs', null=True) docs = ToManyField(DocumentResource, 'docs', null=True)
rel = ToManyField(IprDisclosureBaseResource, 'rel', null=True) rel = ToManyField(IprDisclosureBaseResource, 'rel', null=True)
class Meta: class Meta:
cache = SimpleCache() cache = SimpleCache()

View file

@ -15,8 +15,7 @@ from django.utils import timezone
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import DocAlias from ietf.doc.factories import DocumentFactory, WgDraftFactory, WgRfcFactory, RfcFactory
from ietf.doc.factories import DocumentFactory, WgDraftFactory, WgRfcFactory
from ietf.group.factories import RoleFactory from ietf.group.factories import RoleFactory
from ietf.ipr.factories import HolderIprDisclosureFactory, GenericIprDisclosureFactory, IprEventFactory from ietf.ipr.factories import HolderIprDisclosureFactory, GenericIprDisclosureFactory, IprEventFactory
from ietf.ipr.mail import (process_response_email, get_reply_to, get_update_submitter_emails, from ietf.ipr.mail import (process_response_email, get_reply_to, get_update_submitter_emails,
@ -164,7 +163,8 @@ class IprTests(TestCase):
self.assertContains(r, draft.name) self.assertContains(r, draft.name)
self.assertNotContains(r, ipr.title) self.assertNotContains(r, ipr.title)
DocAlias.objects.create(name="rfc321").docs.add(draft) rfc = RfcFactory(rfc_number=321)
draft.relateddocument_set.create(relationship_id="became_rfc",target=rfc)
# find RFC # find RFC
r = self.client.get(url + "?submit=rfc&rfc=321") r = self.client.get(url + "?submit=rfc&rfc=321")
@ -251,7 +251,7 @@ class IprTests(TestCase):
"""Add a new specific disclosure. Note: submitter does not need to be logged in. """Add a new specific disclosure. Note: submitter does not need to be logged in.
""" """
draft = WgDraftFactory() draft = WgDraftFactory()
WgRfcFactory() rfc = WgRfcFactory()
url = urlreverse("ietf.ipr.views.new", kwargs={ "type": "specific" }) url = urlreverse("ietf.ipr.views.new", kwargs={ "type": "specific" })
# successful post # successful post
@ -265,9 +265,9 @@ class IprTests(TestCase):
"ietfer_contact_info": "555-555-0101", "ietfer_contact_info": "555-555-0101",
"iprdocrel_set-TOTAL_FORMS": 2, "iprdocrel_set-TOTAL_FORMS": 2,
"iprdocrel_set-INITIAL_FORMS": 0, "iprdocrel_set-INITIAL_FORMS": 0,
"iprdocrel_set-0-document": draft.docalias.first().pk, "iprdocrel_set-0-document": draft.pk,
"iprdocrel_set-0-revisions": '00', "iprdocrel_set-0-revisions": '00',
"iprdocrel_set-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk, "iprdocrel_set-1-document": rfc.pk,
"patent_number": "SE12345678901", "patent_number": "SE12345678901",
"patent_inventor": "A. Nonymous", "patent_inventor": "A. Nonymous",
"patent_title": "A method of transferring bits", "patent_title": "A method of transferring bits",
@ -309,7 +309,7 @@ class IprTests(TestCase):
"""Add a new third-party disclosure. Note: submitter does not need to be logged in. """Add a new third-party disclosure. Note: submitter does not need to be logged in.
""" """
draft = WgDraftFactory() draft = WgDraftFactory()
WgRfcFactory() rfc = WgRfcFactory()
url = urlreverse("ietf.ipr.views.new", kwargs={ "type": "third-party" }) url = urlreverse("ietf.ipr.views.new", kwargs={ "type": "third-party" })
# successful post # successful post
@ -321,9 +321,9 @@ class IprTests(TestCase):
"ietfer_contact_info": "555-555-0101", "ietfer_contact_info": "555-555-0101",
"iprdocrel_set-TOTAL_FORMS": 2, "iprdocrel_set-TOTAL_FORMS": 2,
"iprdocrel_set-INITIAL_FORMS": 0, "iprdocrel_set-INITIAL_FORMS": 0,
"iprdocrel_set-0-document": draft.docalias.first().pk, "iprdocrel_set-0-document": draft.pk,
"iprdocrel_set-0-revisions": '00', "iprdocrel_set-0-revisions": '00',
"iprdocrel_set-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk, "iprdocrel_set-1-document": rfc.pk,
"patent_number": "SE12345678901", "patent_number": "SE12345678901",
"patent_inventor": "A. Nonymous", "patent_inventor": "A. Nonymous",
"patent_title": "A method of transferring bits", "patent_title": "A method of transferring bits",
@ -368,7 +368,7 @@ class IprTests(TestCase):
"holder_legal_name": "Test Legal", "holder_legal_name": "Test Legal",
"ietfer_contact_info": "555-555-0101", "ietfer_contact_info": "555-555-0101",
"ietfer_name": "Test Participant", "ietfer_name": "Test Participant",
"iprdocrel_set-0-document": draft.docalias.first().pk, "iprdocrel_set-0-document": draft.pk,
"iprdocrel_set-0-revisions": '00', "iprdocrel_set-0-revisions": '00',
"iprdocrel_set-INITIAL_FORMS": 0, "iprdocrel_set-INITIAL_FORMS": 0,
"iprdocrel_set-TOTAL_FORMS": 1, "iprdocrel_set-TOTAL_FORMS": 1,
@ -396,7 +396,7 @@ class IprTests(TestCase):
def test_update(self): def test_update(self):
draft = WgDraftFactory() draft = WgDraftFactory()
WgRfcFactory() rfc = WgRfcFactory()
original_ipr = HolderIprDisclosureFactory(docs=[draft,]) original_ipr = HolderIprDisclosureFactory(docs=[draft,])
# get # get
@ -417,9 +417,9 @@ class IprTests(TestCase):
"ietfer_contact_info": "555-555-0101", "ietfer_contact_info": "555-555-0101",
"iprdocrel_set-TOTAL_FORMS": 2, "iprdocrel_set-TOTAL_FORMS": 2,
"iprdocrel_set-INITIAL_FORMS": 0, "iprdocrel_set-INITIAL_FORMS": 0,
"iprdocrel_set-0-document": draft.docalias.first().pk, "iprdocrel_set-0-document": draft.pk,
"iprdocrel_set-0-revisions": '00', "iprdocrel_set-0-revisions": '00',
"iprdocrel_set-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk, "iprdocrel_set-1-document": rfc.pk,
"patent_number": "SE12345678901", "patent_number": "SE12345678901",
"patent_inventor": "A. Nonymous", "patent_inventor": "A. Nonymous",
"patent_title": "A method of transferring bits", "patent_title": "A method of transferring bits",
@ -454,7 +454,7 @@ class IprTests(TestCase):
"holder_contact_email": "test@holder.com", "holder_contact_email": "test@holder.com",
"iprdocrel_set-TOTAL_FORMS": 1, "iprdocrel_set-TOTAL_FORMS": 1,
"iprdocrel_set-INITIAL_FORMS": 0, "iprdocrel_set-INITIAL_FORMS": 0,
"iprdocrel_set-0-document": draft.docalias.first().pk, "iprdocrel_set-0-document": draft.pk,
"iprdocrel_set-0-revisions": '00', "iprdocrel_set-0-revisions": '00',
"patent_number": "SE12345678901", "patent_number": "SE12345678901",
"patent_inventor": "A. Nonymous", "patent_inventor": "A. Nonymous",
@ -720,7 +720,7 @@ Subject: test
'iprdocrel_set-INITIAL_FORMS' : 0, 'iprdocrel_set-INITIAL_FORMS' : 0,
'iprdocrel_set-0-id': '', 'iprdocrel_set-0-id': '',
"iprdocrel_set-0-document": disclosure.docs.first().pk, "iprdocrel_set-0-document": disclosure.docs.first().pk,
"iprdocrel_set-0-revisions": disclosure.docs.first().document.rev, "iprdocrel_set-0-revisions": disclosure.docs.first().rev,
'holder_legal_name': disclosure.holder_legal_name, 'holder_legal_name': disclosure.holder_legal_name,
'patent_number': patent_dict['Number'], 'patent_number': patent_dict['Number'],
'patent_title': patent_dict['Title'], 'patent_title': patent_dict['Title'],

View file

@ -32,27 +32,32 @@ def get_ipr_summary(disclosure):
return summary if len(summary) <= 128 else summary[:125]+'...' return summary if len(summary) <= 128 else summary[:125]+'...'
def iprs_from_docs(aliases,**kwargs): def iprs_from_docs(docs,**kwargs):
"""Returns a list of IPRs related to doc aliases""" """Returns a list of IPRs related to docs"""
iprdocrels = [] iprdocrels = []
for alias in aliases: for document in docs:
for document in alias.docs.all(): if document.ipr(**kwargs):
if document.ipr(**kwargs): iprdocrels += document.ipr(**kwargs)
iprdocrels += document.ipr(**kwargs)
return list(set([i.disclosure for i in iprdocrels])) return list(set([i.disclosure for i in iprdocrels]))
def related_docs(doc, relationship=('replaces', 'obs')): def related_docs(doc, relationship=('replaces', 'obs'), reverse_relationship=("became_rfc",)):
"""Returns list of related documents""" """Returns list of related documents"""
results = [doc] results = [doc]
rels = list(doc.document.all_relations_that_doc(relationship)) rels = doc.all_relations_that_doc(relationship)
for rel in rels: for rel in rels:
rel.target.related = rel rel.target.related = rel
rel.target.relation = rel.relationship.revname rel.target.relation = rel.relationship.revname
results += [x.target for x in rels] results += [x.target for x in rels]
rev_rels = doc.all_relations_that(reverse_relationship)
for rel in rev_rels:
rel.source.related = rel
rel.source.relation = rel.relationship.name
results += [x.source for x in rev_rels]
return list(set(results)) return list(set(results))
@ -60,17 +65,16 @@ def generate_draft_recursive_txt():
docipr = {} docipr = {}
for o in IprDocRel.objects.filter(disclosure__state='posted').select_related('document'): for o in IprDocRel.objects.filter(disclosure__state='posted').select_related('document'):
alias = o.document doc = o.document
name = alias.name name = doc.name
for document in alias.docs.all(): related_set = set(doc) | set(doc.all_related_that_doc(('obs', 'replaces')))
related = set(document.docalias.all()) | set(document.all_related_that_doc(('obs', 'replaces'))) for related in related_set:
for alias in related: name = related.name
name = alias.name if name.startswith("rfc"):
if name.startswith("rfc"): name = name.upper()
name = name.upper() if not name in docipr:
if not name in docipr: docipr[name] = []
docipr[name] = [] docipr[name].append(o.disclosure_id)
docipr[name].append(o.disclosure_id)
lines = [ "# Machine-readable list of IPR disclosures by Internet-Draft name" ] lines = [ "# Machine-readable list of IPR disclosures by Internet-Draft name" ]
for name, iprs in docipr.items(): for name, iprs in docipr.items():

View file

@ -18,7 +18,7 @@ from django.utils.html import escape
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import DocAlias from ietf.doc.models import Document
from ietf.group.models import Role, Group from ietf.group.models import Role, Group
from ietf.ietfauth.utils import role_required, has_role from ietf.ietfauth.utils import role_required, has_role
from ietf.ipr.mail import (message_from_message, get_reply_to, get_update_submitter_emails) from ietf.ipr.mail import (message_from_message, get_reply_to, get_update_submitter_emails)
@ -38,7 +38,7 @@ from ietf.message.models import Message
from ietf.message.utils import infer_message from ietf.message.utils import infer_message
from ietf.name.models import IprLicenseTypeName from ietf.name.models import IprLicenseTypeName
from ietf.person.models import Person from ietf.person.models import Person
from ietf.secr.utils.document import get_rfc_num, is_draft from ietf.utils import log
from ietf.utils.draft_search import normalize_draftname from ietf.utils.draft_search import normalize_draftname
from ietf.utils.mail import send_mail, send_mail_message from ietf.utils.mail import send_mail, send_mail_message
from ietf.utils.response import permission_denied from ietf.utils.response import permission_denied
@ -69,12 +69,15 @@ def get_document_emails(ipr):
has been posted""" has been posted"""
messages = [] messages = []
for rel in ipr.iprdocrel_set.all(): for rel in ipr.iprdocrel_set.all():
doc = rel.document.document doc = rel.document
if is_draft(doc): if doc.type_id=="draft":
doc_info = 'Internet-Draft entitled "{}" ({})'.format(doc.title,doc.name) doc_info = 'Internet-Draft entitled "{}" ({})'.format(doc.title,doc.name)
elif doc.type_id=="rfc":
doc_info = 'RFC entitled "{}" (RFC{})'.format(doc.title, doc.rfc_number)
else: else:
doc_info = 'RFC entitled "{}" (RFC{})'.format(doc.title,get_rfc_num(doc)) log.unreachable("2023-08-15")
return ""
addrs = gather_address_lists('ipr_posted_on_doc',doc=doc).as_strings(compact=False) addrs = gather_address_lists('ipr_posted_on_doc',doc=doc).as_strings(compact=False)
@ -663,18 +666,18 @@ def search(request):
doc = q doc = q
if docid: if docid:
start = DocAlias.objects.filter(name__iexact=docid) start = Document.objects.filter(name__iexact=docid)
else: else:
if search_type == "draft": if search_type == "draft":
q = normalize_draftname(q) q = normalize_draftname(q)
start = DocAlias.objects.filter(name__icontains=q, name__startswith="draft") start = Document.objects.filter(name__icontains=q, name__startswith="draft")
elif search_type == "rfc": elif search_type == "rfc":
start = DocAlias.objects.filter(name="rfc%s" % q.lstrip("0")) start = Document.objects.filter(name="rfc%s" % q.lstrip("0"))
# one match # one match
if len(start) == 1: if len(start) == 1:
first = start[0] first = start[0]
doc = first.document doc = first
docs = related_docs(first) docs = related_docs(first)
iprs = iprs_from_docs(docs,states=states) iprs = iprs_from_docs(docs,states=states)
template = "ipr/search_doc_result.html" template = "ipr/search_doc_result.html"
@ -706,27 +709,27 @@ def search(request):
# Search by wg acronym # Search by wg acronym
# Document list with IPRs # Document list with IPRs
elif search_type == "group": elif search_type == "group":
docs = list(DocAlias.objects.filter(docs__group=q)) docs = list(Document.objects.filter(group=q))
related = [] related = []
for doc in docs: for doc in docs:
doc.product_of_this_wg = True doc.product_of_this_wg = True
related += related_docs(doc) related += related_docs(doc)
iprs = iprs_from_docs(list(set(docs+related)),states=states) iprs = iprs_from_docs(list(set(docs+related)),states=states)
docs = [ doc for doc in docs if doc.document.ipr() ] docs = [ doc for doc in docs if doc.ipr() ]
docs = sorted(docs, key=lambda x: max([ipr.disclosure.time for ipr in x.document.ipr()]), reverse=True) docs = sorted(docs, key=lambda x: max([ipr.disclosure.time for ipr in x.ipr()]), reverse=True)
template = "ipr/search_wg_result.html" template = "ipr/search_wg_result.html"
q = Group.objects.get(id=q).acronym # make acronym for use in template q = Group.objects.get(id=q).acronym # make acronym for use in template
# Search by rfc and id title # Search by rfc and id title
# Document list with IPRs # Document list with IPRs
elif search_type == "doctitle": elif search_type == "doctitle":
docs = list(DocAlias.objects.filter(docs__title__icontains=q)) docs = list(Document.objects.filter(title__icontains=q))
related = [] related = []
for doc in docs: for doc in docs:
related += related_docs(doc) related += related_docs(doc)
iprs = iprs_from_docs(list(set(docs+related)),states=states) iprs = iprs_from_docs(list(set(docs+related)),states=states)
docs = [ doc for doc in docs if doc.document.ipr() ] docs = [ doc for doc in docs if doc.ipr() ]
docs = sorted(docs, key=lambda x: max([ipr.disclosure.time for ipr in x.document.ipr()]), reverse=True) docs = sorted(docs, key=lambda x: max([ipr.disclosure.time for ipr in x.ipr()]), reverse=True)
template = "ipr/search_doctitle_result.html" template = "ipr/search_doctitle_result.html"
# Search by title of IPR disclosure # Search by title of IPR disclosure

View file

@ -31,7 +31,7 @@ from ietf.liaisons.fields import SearchableLiaisonStatementsField
from ietf.group.models import Group from ietf.group.models import Group
from ietf.person.models import Email from ietf.person.models import Email
from ietf.person.fields import SearchableEmailField from ietf.person.fields import SearchableEmailField
from ietf.doc.models import Document, DocAlias from ietf.doc.models import Document
from ietf.utils.fields import DatepickerDateField from ietf.utils.fields import DatepickerDateField
from ietf.utils.timezone import date_today, datetime_from_date, DEADLINE_TZINFO from ietf.utils.timezone import date_today, datetime_from_date, DEADLINE_TZINFO
from functools import reduce from functools import reduce
@ -375,8 +375,6 @@ class LiaisonModelForm(forms.ModelForm):
uploaded_filename = name + extension, uploaded_filename = name + extension,
) )
) )
if created:
DocAlias.objects.create(name=attach.name).docs.add(attach)
LiaisonStatementAttachment.objects.create(statement=self.instance,document=attach) LiaisonStatementAttachment.objects.create(statement=self.instance,document=attach)
attach_file = io.open(os.path.join(settings.LIAISON_ATTACH_PATH, attach.name + extension), 'wb') attach_file = io.open(os.path.join(settings.LIAISON_ATTACH_PATH, attach.name + extension), 'wb')
attach_file.write(attached_file.read()) attach_file.write(attached_file.read())

View file

@ -19,7 +19,7 @@ from django.utils.functional import cached_property
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import Document, DocAlias, State, NewRevisionDocEvent from ietf.doc.models import Document, State, NewRevisionDocEvent
from ietf.group.models import Group from ietf.group.models import Group
from ietf.group.utils import groups_managed_by from ietf.group.utils import groups_managed_by
from ietf.meeting.models import Session, Meeting, Schedule, countries, timezones, TimeSlot, Room from ietf.meeting.models import Session, Meeting, Schedule, countries, timezones, TimeSlot, Room
@ -341,7 +341,6 @@ class InterimSessionModelForm(forms.ModelForm):
# FIXME: What about agendas in html or markdown format? # FIXME: What about agendas in html or markdown format?
uploaded_filename='{}-00.txt'.format(filename)) uploaded_filename='{}-00.txt'.format(filename))
doc.set_state(State.objects.get(type__slug=doc.type.slug, slug='active')) doc.set_state(State.objects.get(type__slug=doc.type.slug, slug='active'))
DocAlias.objects.create(name=doc.name).docs.add(doc)
self.instance.sessionpresentation_set.create(document=doc, rev=doc.rev) self.instance.sessionpresentation_set.create(document=doc, rev=doc.rev)
NewRevisionDocEvent.objects.create( NewRevisionDocEvent.objects.create(
type='new_revision', type='new_revision',

View file

@ -550,7 +550,7 @@ class MeetingTests(BaseMeetingTestCase):
if material.type_id == 'draft': if material.type_id == 'draft':
expected_url = urlreverse( expected_url = urlreverse(
'ietf.doc.views_doc.document_main', 'ietf.doc.views_doc.document_main',
kwargs={'name': material.canonical_name()}, kwargs={'name': material.name},
) )
else: else:
expected_url = material.get_href(meeting) expected_url = material.get_href(meeting)
@ -561,7 +561,7 @@ class MeetingTests(BaseMeetingTestCase):
if material.type_id == 'draft': if material.type_id == 'draft':
expected_url = urlreverse( expected_url = urlreverse(
'ietf.doc.views_doc.document_main', 'ietf.doc.views_doc.document_main',
kwargs={'name': material.canonical_name()}, kwargs={'name': material.name},
) )
else: else:
expected_url = material.get_href(meeting) expected_url = material.get_href(meeting)
@ -7773,7 +7773,7 @@ class ProceedingsTests(BaseMeetingTestCase):
if material.type_id == 'draft': if material.type_id == 'draft':
expected_url = urlreverse( expected_url = urlreverse(
'ietf.doc.views_doc.document_main', 'ietf.doc.views_doc.document_main',
kwargs={'name': material.canonical_name()}, kwargs={'name': material.name},
) )
else: else:
expected_url = material.get_href(meeting) expected_url = material.get_href(meeting)
@ -7784,7 +7784,7 @@ class ProceedingsTests(BaseMeetingTestCase):
if material.type_id == 'draft': if material.type_id == 'draft':
expected_url = urlreverse( expected_url = urlreverse(
'ietf.doc.views_doc.document_main', 'ietf.doc.views_doc.document_main',
kwargs={'name': material.canonical_name()}, kwargs={'name': material.name},
) )
else: else:
expected_url = material.get_href(meeting) expected_url = material.get_href(meeting)

View file

@ -22,7 +22,7 @@ import debug # pyflakes:ignore
from ietf.dbtemplate.models import DBTemplate from ietf.dbtemplate.models import DBTemplate
from ietf.meeting.models import (Session, SchedulingEvent, TimeSlot, from ietf.meeting.models import (Session, SchedulingEvent, TimeSlot,
Constraint, SchedTimeSessAssignment, SessionPresentation) Constraint, SchedTimeSessAssignment, SessionPresentation)
from ietf.doc.models import Document, DocAlias, State, NewRevisionDocEvent from ietf.doc.models import Document, State, NewRevisionDocEvent
from ietf.doc.models import DocEvent from ietf.doc.models import DocEvent
from ietf.group.models import Group from ietf.group.models import Group
from ietf.group.utils import can_manage_materials from ietf.group.utils import can_manage_materials
@ -622,7 +622,6 @@ def save_session_minutes_revision(session, file, ext, request, encoding=None, ap
group = session.group, group = session.group,
rev = '00', rev = '00',
) )
DocAlias.objects.create(name=doc.name).docs.add(doc)
doc.states.add(State.objects.get(type_id='minutes',slug='active')) doc.states.add(State.objects.get(type_id='minutes',slug='active'))
if session.sessionpresentation_set.filter(document=doc).exists(): if session.sessionpresentation_set.filter(document=doc).exists():
sp = session.sessionpresentation_set.get(document=doc) sp = session.sessionpresentation_set.get(document=doc)
@ -746,7 +745,6 @@ def new_doc_for_session(type_id, session):
rev = '00', rev = '00',
) )
doc.states.add(State.objects.get(type_id=type_id, slug='active')) doc.states.add(State.objects.get(type_id=type_id, slug='active'))
DocAlias.objects.create(name=doc.name).docs.add(doc)
session.sessionpresentation_set.create(document=doc,rev='00') session.sessionpresentation_set.create(document=doc,rev='00')
return doc return doc
@ -779,8 +777,6 @@ def create_recording(session, url, title=None, user=None):
rev='00', rev='00',
type_id='recording') type_id='recording')
doc.set_state(State.objects.get(type='recording', slug='active')) doc.set_state(State.objects.get(type='recording', slug='active'))
DocAlias.objects.create(name=doc.name).docs.add(doc)
# create DocEvent # create DocEvent
NewRevisionDocEvent.objects.create(type='new_revision', NewRevisionDocEvent.objects.create(type='new_revision',
@ -799,11 +795,11 @@ def get_next_sequence(group, meeting, type):
Returns the next sequence number to use for a document of type = type. Returns the next sequence number to use for a document of type = type.
Takes a group=Group object, meeting=Meeting object, type = string Takes a group=Group object, meeting=Meeting object, type = string
''' '''
aliases = DocAlias.objects.filter(name__startswith='{}-{}-{}-'.format(type, meeting.number, group.acronym)) docs = Document.objects.filter(name__startswith='{}-{}-{}-'.format(type, meeting.number, group.acronym))
if not aliases: if not docs:
return 1 return 1
aliases = aliases.order_by('name') docs = docs.order_by('name')
sequence = int(aliases.last().name.split('-')[-1]) + 1 sequence = int(docs.last().name.split('-')[-1]) + 1
return sequence return sequence
def get_activity_stats(sdate, edate): def get_activity_stats(sdate, edate):

View file

@ -47,7 +47,7 @@ from django.views.generic import RedirectView
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.fields import SearchableDocumentsField from ietf.doc.fields import SearchableDocumentsField
from ietf.doc.models import Document, State, DocEvent, NewRevisionDocEvent, DocAlias from ietf.doc.models import Document, State, DocEvent, NewRevisionDocEvent
from ietf.group.models import Group from ietf.group.models import Group
from ietf.group.utils import can_manage_session_materials, can_manage_some_groups, can_manage_group from ietf.group.utils import can_manage_session_materials, can_manage_some_groups, can_manage_group
from ietf.person.models import Person, User from ietf.person.models import Person, User
@ -245,7 +245,6 @@ def _get_materials_doc(meeting, name):
def materials_document(request, document, num=None, ext=None): def materials_document(request, document, num=None, ext=None):
meeting=get_meeting(num,type_in=['ietf','interim']) meeting=get_meeting(num,type_in=['ietf','interim'])
num = meeting.number num = meeting.number
# This view does not allow the use of DocAliases. Right now we are probably only creating one (identity) alias, but that may not hold in the future.
try: try:
doc, rev = _get_materials_doc(meeting=meeting, name=document) doc, rev = _get_materials_doc(meeting=meeting, name=document)
except Document.DoesNotExist: except Document.DoesNotExist:
@ -2585,7 +2584,6 @@ def save_bluesheet(request, session, file, encoding='utf-8'):
rev = '00', rev = '00',
) )
doc.states.add(State.objects.get(type_id='bluesheets',slug='active')) doc.states.add(State.objects.get(type_id='bluesheets',slug='active'))
DocAlias.objects.create(name=doc.name).docs.add(doc)
session.sessionpresentation_set.create(document=doc,rev='00') session.sessionpresentation_set.create(document=doc,rev='00')
filename = '%s-%s%s'% ( doc.name, doc.rev, ext) filename = '%s-%s%s'% ( doc.name, doc.rev, ext)
doc.uploaded_filename = filename doc.uploaded_filename = filename
@ -2714,7 +2712,6 @@ def upload_session_agenda(request, session_id, num):
group = session.group, group = session.group,
rev = '00', rev = '00',
) )
DocAlias.objects.create(name=doc.name).docs.add(doc)
doc.states.add(State.objects.get(type_id='agenda',slug='active')) doc.states.add(State.objects.get(type_id='agenda',slug='active'))
if session.sessionpresentation_set.filter(document=doc).exists(): if session.sessionpresentation_set.filter(document=doc).exists():
sp = session.sessionpresentation_set.get(document=doc) sp = session.sessionpresentation_set.get(document=doc)
@ -2807,7 +2804,6 @@ def upload_session_slides(request, session_id, num, name=None):
group = session.group, group = session.group,
rev = '00', rev = '00',
) )
DocAlias.objects.create(name=doc.name).docs.add(doc)
doc.states.add(State.objects.get(type_id='slides',slug='active')) doc.states.add(State.objects.get(type_id='slides',slug='active'))
doc.states.add(State.objects.get(type_id='reuse_policy',slug='single')) doc.states.add(State.objects.get(type_id='reuse_policy',slug='single'))
if session.sessionpresentation_set.filter(document=doc).exists(): if session.sessionpresentation_set.filter(document=doc).exists():
@ -4525,7 +4521,6 @@ def approve_proposed_slides(request, slidesubmission_id, num):
group = submission.session.group, group = submission.session.group,
rev = '00', rev = '00',
) )
DocAlias.objects.create(name=doc.name).docs.add(doc)
doc.states.add(State.objects.get(type_id='slides',slug='active')) doc.states.add(State.objects.get(type_id='slides',slug='active'))
doc.states.add(State.objects.get(type_id='reuse_policy',slug='single')) doc.states.add(State.objects.get(type_id='reuse_policy',slug='single'))
if submission.session.sessionpresentation_set.filter(document=doc).exists(): if submission.session.sessionpresentation_set.filter(document=doc).exists():

View file

@ -8,7 +8,7 @@ from django.shortcuts import render, redirect, get_object_or_404
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.utils import add_state_change_event from ietf.doc.utils import add_state_change_event
from ietf.doc.models import DocAlias, DocEvent, Document, NewRevisionDocEvent, State from ietf.doc.models import DocEvent, Document, NewRevisionDocEvent, State
from ietf.ietfauth.utils import role_required from ietf.ietfauth.utils import role_required
from ietf.meeting.forms import FileUploadForm from ietf.meeting.forms import FileUploadForm
from ietf.meeting.models import Meeting, MeetingHost from ietf.meeting.models import Meeting, MeetingHost
@ -98,10 +98,6 @@ def save_proceedings_material_doc(meeting, material_type, title, request, file=N
) )
created = True created = True
# do this even if we did not create the document, just to be sure the alias exists
alias, _ = DocAlias.objects.get_or_create(name=doc.name)
alias.docs.add(doc)
if file: if file:
if not created: if not created:
doc.rev = '{:02}'.format(int(doc.rev) + 1) doc.rev = '{:02}'.format(int(doc.rev) + 1)

View file

@ -9956,9 +9956,9 @@
{ {
"fields": { "fields": {
"desc": "", "desc": "",
"name": "Became RFC", "name": "became RFC",
"order": 0, "order": 0,
"revname": "Became RFC as", "revname": "came from draft",
"used": true "used": true
}, },
"model": "name.docrelationshipname", "model": "name.docrelationshipname",
@ -11156,7 +11156,7 @@
"fields": { "fields": {
"desc": "", "desc": "",
"name": "Comment", "name": "Comment",
"order": 0, "order": 1,
"used": true "used": true
}, },
"model": "name.feedbacktypename", "model": "name.feedbacktypename",
@ -11166,7 +11166,7 @@
"fields": { "fields": {
"desc": "", "desc": "",
"name": "Junk", "name": "Junk",
"order": 0, "order": 5,
"used": true "used": true
}, },
"model": "name.feedbacktypename", "model": "name.feedbacktypename",
@ -11176,17 +11176,27 @@
"fields": { "fields": {
"desc": "", "desc": "",
"name": "Nomination", "name": "Nomination",
"order": 0, "order": 2,
"used": true "used": true
}, },
"model": "name.feedbacktypename", "model": "name.feedbacktypename",
"pk": "nomina" "pk": "nomina"
}, },
{
"fields": {
"desc": "",
"name": "Overcome by events",
"order": 4,
"used": true
},
"model": "name.feedbacktypename",
"pk": "obe"
},
{ {
"fields": { "fields": {
"desc": "", "desc": "",
"name": "Questionnaire response", "name": "Questionnaire response",
"order": 0, "order": 3,
"used": true "used": true
}, },
"model": "name.feedbacktypename", "model": "name.feedbacktypename",
@ -11196,7 +11206,7 @@
"fields": { "fields": {
"desc": "", "desc": "",
"name": "Read", "name": "Read",
"order": 0, "order": 6,
"used": true "used": true
}, },
"model": "name.feedbacktypename", "model": "name.feedbacktypename",
@ -11799,13 +11809,24 @@
"model": "name.importantdatename", "model": "name.importantdatename",
"pk": "draftwgagenda" "pk": "draftwgagenda"
}, },
{
"fields": {
"default_offset_days": -12,
"desc": "Early registration and payment cut-off at UTC 23:59",
"name": "Early cutoff",
"order": 0,
"used": true
},
"model": "name.importantdatename",
"pk": "early"
},
{ {
"fields": { "fields": {
"default_offset_days": -47, "default_offset_days": -47,
"desc": "Early Bird registration and payment cut-off at UTC 23:59", "desc": "Early Bird registration and payment cut-off at UTC 23:59",
"name": "Earlybird cutoff", "name": "Earlybird cutoff",
"order": 0, "order": 0,
"used": true "used": false
}, },
"model": "name.importantdatename", "model": "name.importantdatename",
"pk": "earlybird" "pk": "earlybird"
@ -11926,11 +11947,22 @@
"desc": "Standard rate registration and payment cut-off at UTC 23:59.", "desc": "Standard rate registration and payment cut-off at UTC 23:59.",
"name": "Standard rate registration ends", "name": "Standard rate registration ends",
"order": 18, "order": 18,
"used": true "used": false
}, },
"model": "name.importantdatename", "model": "name.importantdatename",
"pk": "stdratecutoff" "pk": "stdratecutoff"
}, },
{
"fields": {
"default_offset_days": -47,
"desc": "Super Early registration cutoff at UTC 23:59",
"name": "Super Early cutoff",
"order": 0,
"used": true
},
"model": "name.importantdatename",
"pk": "superearly"
},
{ {
"fields": { "fields": {
"desc": "", "desc": "",
@ -16481,7 +16513,7 @@
"fields": { "fields": {
"command": "xym", "command": "xym",
"switch": "--version", "switch": "--version",
"time": "2023-07-17T07:09:47.664Z", "time": "2023-08-13T07:09:38.976Z",
"used": true, "used": true,
"version": "xym 0.7.0" "version": "xym 0.7.0"
}, },
@ -16492,7 +16524,7 @@
"fields": { "fields": {
"command": "pyang", "command": "pyang",
"switch": "--version", "switch": "--version",
"time": "2023-07-17T07:09:48.075Z", "time": "2023-08-13T07:09:39.314Z",
"used": true, "used": true,
"version": "pyang 2.5.3" "version": "pyang 2.5.3"
}, },
@ -16503,7 +16535,7 @@
"fields": { "fields": {
"command": "yanglint", "command": "yanglint",
"switch": "--version", "switch": "--version",
"time": "2023-07-17T07:09:48.104Z", "time": "2023-08-13T07:09:39.334Z",
"used": true, "used": true,
"version": "yanglint SO 1.9.2" "version": "yanglint SO 1.9.2"
}, },
@ -16514,9 +16546,9 @@
"fields": { "fields": {
"command": "xml2rfc", "command": "xml2rfc",
"switch": "--version", "switch": "--version",
"time": "2023-07-17T07:09:49.075Z", "time": "2023-08-13T07:09:40.245Z",
"used": true, "used": true,
"version": "xml2rfc 3.17.4" "version": "xml2rfc 3.18.0"
}, },
"model": "utils.versioninfo", "model": "utils.versioninfo",
"pk": 4 "pk": 4

View file

@ -191,7 +191,7 @@ class Person(models.Model):
def rfcs(self): def rfcs(self):
from ietf.doc.models import Document from ietf.doc.models import Document
rfcs = list(Document.objects.filter(documentauthor__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() ) rfcs.sort(key=lambda d: d.name )
return rfcs return rfcs
def active_drafts(self): def active_drafts(self):

View file

@ -7,7 +7,7 @@ from django.db.models.aggregates import Max
from django.utils import timezone from django.utils import timezone
from simple_history.utils import bulk_update_with_history from simple_history.utils import bulk_update_with_history
from ietf.doc.models import DocumentAuthor, DocAlias from ietf.doc.models import DocumentAuthor
from ietf.doc.utils import extract_complete_replaces_ancestor_mapping_for_docs from ietf.doc.utils import extract_complete_replaces_ancestor_mapping_for_docs
from ietf.group.models import Role from ietf.group.models import Role
from ietf.person.models import Person from ietf.person.models import Person
@ -287,8 +287,6 @@ class AssignmentOrderResolver:
def _collect_context(self): def _collect_context(self):
"""Collect all relevant data about this team, document and review request.""" """Collect all relevant data about this team, document and review request."""
self.doc_aliases = DocAlias.objects.filter(docs=self.doc).values_list("name", flat=True)
# This data is collected as a dict, keys being person IDs, values being numbers/objects. # This data is collected as a dict, keys being person IDs, values being numbers/objects.
self.rotation_index = {p.pk: i for i, p in enumerate(self.rotation_list)} self.rotation_index = {p.pk: i for i, p in enumerate(self.rotation_list)}
self.reviewer_settings = self._reviewer_settings_for_person_ids(self.possible_person_ids) self.reviewer_settings = self._reviewer_settings_for_person_ids(self.possible_person_ids)
@ -354,8 +352,7 @@ class AssignmentOrderResolver:
add_boolean_score(+1, email.person_id in self.wish_to_review, "wishes to review document") add_boolean_score(+1, email.person_id in self.wish_to_review, "wishes to review document")
add_boolean_score(-1, email.person_id in self.connections, add_boolean_score(-1, email.person_id in self.connections,
self.connections.get(email.person_id)) # reviewer is somehow connected: bad self.connections.get(email.person_id)) # reviewer is somehow connected: bad
add_boolean_score(-1, settings.filter_re and any( add_boolean_score(-1, settings.filter_re and re.search(settings.filter_re, self.doc.name), "filter regexp matches")
re.search(settings.filter_re, n) for n in self.doc_aliases), "filter regexp matches")
# minimum interval between reviews # minimum interval between reviews
days_needed = self.days_needed_for_reviewers.get(email.person_id, 0) days_needed = self.days_needed_for_reviewers.get(email.person_id, 0)

View file

@ -175,7 +175,7 @@ def doc_detail(request, date, name):
This view displays the ballot information for the document, and lets the user make This view displays the ballot information for the document, and lets the user make
changes to ballot positions and document state. changes to ballot positions and document state.
''' '''
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
if not is_doc_on_telechat(doc, date): if not is_doc_on_telechat(doc, date):
messages.warning(request, 'Dcoument: {name} is not on the Telechat agenda for {date}'.format( messages.warning(request, 'Dcoument: {name} is not on the Telechat agenda for {date}'.format(
name=doc.name, name=doc.name,
@ -342,7 +342,7 @@ def doc_navigate(request, date, name, nav):
nav - [next|previous] which direction the user wants to navigate in the list of docs nav - [next|previous] which direction the user wants to navigate in the list of docs
The view retrieves the appropriate document and redirects to the doc view. The view retrieves the appropriate document and redirects to the doc view.
''' '''
doc = get_object_or_404(Document, docalias__name=name) doc = get_object_or_404(Document, name=name)
agenda = agenda_data(date=date) agenda = agenda_data(date=date)
target = name target = name

View file

@ -85,7 +85,7 @@
{% if downrefs %} {% if downrefs %}
<h2 id="downrefs">Downward References</h2> <h2 id="downrefs">Downward References</h2>
{% for ref in downrefs %} {% for ref in downrefs %}
<p>Add {{ref.target.canonical_name}} <p>Add {{ref.target.name}}
({{ref.target.std_level}} - {{ref.target.stream.desc}}) ({{ref.target.std_level}} - {{ref.target.stream.desc}})
to downref registry.<br> to downref registry.<br>
{% if not ref.target.std_level %} {% if not ref.target.std_level %}

View file

@ -13,15 +13,6 @@ def get_full_path(doc):
return None return None
return os.path.join(doc.get_file_path(), doc.uploaded_filename) return os.path.join(doc.get_file_path(), doc.uploaded_filename)
def get_rfc_num(doc):
qs = doc.docalias.filter(name__startswith='rfc')
return qs[0].name[3:] if qs else None
def is_draft(doc):
if doc.docalias.filter(name__startswith='rfc'):
return False
else:
return True
def get_start_date(doc): def get_start_date(doc):
''' '''

View file

@ -600,7 +600,6 @@ TEST_CODE_COVERAGE_EXCLUDE_FILES = [
"ietf/utils/test_runner.py", "ietf/utils/test_runner.py",
"ietf/name/generate_fixtures.py", "ietf/name/generate_fixtures.py",
"ietf/review/import_from_review_tool.py", "ietf/review/import_from_review_tool.py",
"ietf/stats/backfill_data.py",
"ietf/utils/patch.py", "ietf/utils/patch.py",
"ietf/utils/test_data.py", "ietf/utils/test_data.py",
] ]

View file

@ -1,184 +0,0 @@
#!/usr/bin/env python
# Copyright The IETF Trust 2017-2020, All Rights Reserved
# -*- coding: utf-8 -*-
import io
import sys
import os
import os.path
import argparse
import time
from typing import Set, Optional # pyflakes:ignore
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
sys.path = [ basedir ] + sys.path
os.environ["DJANGO_SETTINGS_MODULE"] = "ietf.settings"
virtualenv_activation = os.path.join(basedir, "env", "bin", "activate_this.py")
if os.path.exists(virtualenv_activation):
exec(compile(io.open(virtualenv_activation, "rb").read(), virtualenv_activation, 'exec'), dict(__file__=virtualenv_activation))
import django
django.setup()
from django.conf import settings
import debug # pyflakes:ignore
from ietf.doc.models import Document
from ietf.name.models import FormalLanguageName
from ietf.utils.draft import PlaintextDraft
parser = argparse.ArgumentParser()
parser.add_argument("--document", help="specific document name")
parser.add_argument("--words", action="store_true", help="fill in word count")
parser.add_argument("--formlang", action="store_true", help="fill in formal languages")
parser.add_argument("--authors", action="store_true", help="fill in author info")
args = parser.parse_args()
formal_language_dict = { l.pk: l for l in FormalLanguageName.objects.all() }
docs_qs = Document.objects.filter(type="draft")
if args.document:
docs_qs = docs_qs.filter(docalias__name=args.document)
ts = time.strftime("%Y-%m-%d_%H:%M%z")
logfile = io.open('backfill-authorstats-%s.log'%ts, 'w')
print("Writing log to %s" % os.path.abspath(logfile.name))
def say(msg):
msg = msg.encode('utf8')
sys.stderr.write(msg)
sys.stderr.write('\n')
logfile.write(msg)
logfile.write('\n')
def unicode(text):
if text is None:
return text
# order matters here:
for encoding in ['ascii', 'utf8', 'latin1', ]:
try:
utext = text.decode(encoding)
# if encoding == 'latin1':
# say("Warning: falling back to latin1 decoding for %s ..." % utext[:216]])
return utext
except UnicodeDecodeError:
pass
start = time.time()
say("Running query for documents to process ...")
for doc in docs_qs.prefetch_related("docalias", "formal_languages", "documentauthor_set", "documentauthor_set__person", "documentauthor_set__person__alias_set"):
canonical_name = doc.name
for n in doc.docalias.all():
if n.name.startswith("rfc"):
canonical_name = n.name
if canonical_name.startswith("rfc"):
path = os.path.join(settings.RFC_PATH, canonical_name + ".txt")
else:
path = os.path.join(settings.INTERNET_ALL_DRAFTS_ARCHIVE_DIR, canonical_name + "-" + doc.rev + ".txt")
if not os.path.exists(path):
say("Skipping %s, no txt file found at %s" % (doc.name, path))
continue
with io.open(path, 'rb') as f:
say("\nProcessing %s" % doc.name)
sys.stdout.flush()
d = PlaintextDraft(unicode(f.read()), path)
updated = False
updates = {}
if args.words:
words = d.get_wordcount()
if words != doc.words:
updates["words"] = words
if args.formlang:
langs = d.get_formal_languages()
new_formal_languages = set(formal_language_dict[l] for l in langs)
old_formal_languages = set(doc.formal_languages.all())
if new_formal_languages != old_formal_languages:
for l in new_formal_languages - old_formal_languages:
doc.formal_languages.add(l)
updated = True
for l in old_formal_languages - new_formal_languages:
doc.formal_languages.remove(l)
updated = True
if args.authors:
old_authors = doc.documentauthor_set.all()
old_authors_by_name = {}
old_authors_by_email = {}
for author in old_authors:
for alias in author.person.alias_set.all():
old_authors_by_name[alias.name] = author
old_authors_by_name[author.person.plain_name()] = author
if author.email_id:
old_authors_by_email[author.email_id] = author
# the draft parser sometimes has a problem when
# affiliation isn't in the second line and it then thinks
# it's an extra author - skip those extra authors
seen = set() # type: Set[Optional[str]]
for full, _, _, _, _, email, country, company in d.get_author_list():
assert full is None or isinstance(full, str)
assert email is None or isinstance(email, str)
assert country is None or isinstance(country, str)
assert isinstance(company, str)
#full, email, country, company = [ unicode(s) for s in [full, email, country, company, ] ]
if email in seen:
continue
seen.add(email)
old_author = None
if email:
old_author = old_authors_by_email.get(email)
if not old_author:
old_author = old_authors_by_name.get(full)
if not old_author:
say("UNKNOWN AUTHOR: %s, %s, %s, %s, %s" % (doc.name, full, email, country, company))
continue
if old_author.affiliation != company:
say("new affiliation: %s [ %s <%s> ] %s -> %s" % (canonical_name, full, email, old_author.affiliation, company))
old_author.affiliation = company
old_author.save(update_fields=["affiliation"])
updated = True
if country is None:
country = ""
if old_author.country != country:
say("new country: %s [ %s <%s> ] %s -> %s" % (canonical_name , full, email, old_author.country, country))
old_author.country = country
old_author.save(update_fields=["country"])
updated = True
if updates:
Document.objects.filter(pk=doc.pk).update(**updates)
updated = True
if updated:
say("updated: %s" % canonical_name)
stop = time.time()
dur = stop-start
sec = dur%60
min = dur//60
say("Processing time %d:%02d" % (min, sec))
print("\n\nWrote log to %s" % os.path.abspath(logfile.name))
logfile.close()

View file

@ -11,6 +11,10 @@ from ietf.name.models import CountryName
from ietf.person.models import Person from ietf.person.models import Person
from ietf.utils.models import ForeignKey from ietf.utils.models import ForeignKey
### NOTE WELL: These models are expected to be removed and the stats app reimplemented.
# A bare python file that should have been a management command was used to populate
# these models when the app was first installed - it has been removed from main, but
# can be seen at https://github.com/ietf-tools/datatracker/blob/f2b716fc052a0152c32b86b428ba6ebfdcdf5cd2/ietf/stats/backfill_data.py
class AffiliationAlias(models.Model): class AffiliationAlias(models.Model):
"""Records that alias should be treated as name for statistical """Records that alias should be treated as name for statistical

View file

@ -20,7 +20,7 @@ import ietf.stats.views
from ietf.submit.models import Submission from ietf.submit.models import Submission
from ietf.doc.factories import WgDraftFactory, WgRfcFactory from ietf.doc.factories import WgDraftFactory, WgRfcFactory
from ietf.doc.models import Document, DocAlias, State, RelatedDocument, NewRevisionDocEvent, DocumentAuthor from ietf.doc.models import Document, State, RelatedDocument, NewRevisionDocEvent, DocumentAuthor
from ietf.group.factories import RoleFactory from ietf.group.factories import RoleFactory
from ietf.meeting.factories import MeetingFactory, AttendedFactory from ietf.meeting.factories import MeetingFactory, AttendedFactory
from ietf.person.factories import PersonFactory from ietf.person.factories import PersonFactory
@ -79,7 +79,6 @@ class StatisticsTests(TestCase):
words=100 words=100
) )
referencing_draft.set_state(State.objects.get(used=True, type="draft", slug="active")) referencing_draft.set_state(State.objects.get(used=True, type="draft", slug="active"))
DocAlias.objects.create(name=referencing_draft.name).docs.add(referencing_draft)
RelatedDocument.objects.create( RelatedDocument.objects.create(
source=referencing_draft, source=referencing_draft,
target=draft, target=draft,

View file

@ -34,7 +34,7 @@ from ietf.group.models import Role, Group
from ietf.person.models import Person from ietf.person.models import Person
from ietf.name.models import ReviewResultName, CountryName, DocRelationshipName, ReviewAssignmentStateName from ietf.name.models import ReviewResultName, CountryName, DocRelationshipName, ReviewAssignmentStateName
from ietf.person.name import plain_name from ietf.person.name import plain_name
from ietf.doc.models import DocAlias, Document, State, DocEvent from ietf.doc.models import Document, State, DocEvent
from ietf.meeting.models import Meeting from ietf.meeting.models import Meeting
from ietf.stats.models import MeetingRegistration, CountryAlias from ietf.stats.models import MeetingRegistration, CountryAlias
from ietf.stats.utils import get_aliased_affiliations, get_aliased_countries, compute_hirsch_index from ietf.stats.utils import get_aliased_affiliations, get_aliased_countries, compute_hirsch_index
@ -214,13 +214,13 @@ def document_stats(request, stats_type=None):
if any(stats_type == t[0] for t in possible_document_stats_types): if any(stats_type == t[0] for t in possible_document_stats_types):
# filter documents # filter documents
docalias_filters = Q(docs__type="draft") document_filters = Q(type__in=["draft","rfc"]) # TODO - review lots of "rfc is a draft" assumptions below
rfc_state = State.objects.get(type="draft", slug="rfc") rfc_state = State.objects.get(type="draft", slug="rfc")
if document_type == "rfc": if document_type == "rfc":
docalias_filters &= Q(docs__states=rfc_state) document_filters &= Q(states=rfc_state)
elif document_type == "draft": elif document_type == "draft":
docalias_filters &= ~Q(docs__states=rfc_state) document_filters &= ~Q(states=rfc_state)
if from_time: if from_time:
# this is actually faster than joining in the database, # this is actually faster than joining in the database,
@ -229,11 +229,11 @@ def document_stats(request, stats_type=None):
type="draft", type="draft",
docevent__time__gte=from_time, docevent__time__gte=from_time,
docevent__type__in=["published_rfc", "new_revision"], docevent__type__in=["published_rfc", "new_revision"],
).values_list("pk")) ).values_list("pk",flat=True))
docalias_filters &= Q(docs__in=docs_within_time_constraint) document_filters &= Q(pk__in=docs_within_time_constraint)
docalias_qs = DocAlias.objects.filter(docalias_filters) document_qs = Document.objects.filter(document_filters)
if document_type == "rfc": if document_type == "rfc":
doc_label = "RFC" doc_label = "RFC"
@ -242,28 +242,15 @@ def document_stats(request, stats_type=None):
else: else:
doc_label = "document" doc_label = "document"
total_docs = docalias_qs.values_list("docs__name").distinct().count() total_docs = document_qs.values_list("name").distinct().count()
def generate_canonical_names(values):
for doc_id, ts in itertools.groupby(values.order_by("docs__name"), lambda a: a[0]):
chosen = None
for t in ts:
if chosen is None:
chosen = t
else:
if t[1].startswith("rfc"):
chosen = t
elif t[1].startswith("draft") and not chosen[1].startswith("rfc"):
chosen = t
yield chosen
if stats_type == "authors": if stats_type == "authors":
stats_title = "Number of authors for each {}".format(doc_label) stats_title = "Number of authors for each {}".format(doc_label)
bins = defaultdict(set) bins = defaultdict(set)
for name, canonical_name, author_count in generate_canonical_names(docalias_qs.values_list("docs__name", "name").annotate(Count("docs__documentauthor"))): for name, author_count in document_qs.values_list("name").annotate(Count("documentauthor")).values_list("name","documentauthor__count"):
bins[author_count or 0].add(canonical_name) bins[author_count or 0].add(name)
series_data = [] series_data = []
for author_count, names in sorted(bins.items(), key=lambda t: t[0]): for author_count, names in sorted(bins.items(), key=lambda t: t[0]):
@ -278,8 +265,8 @@ def document_stats(request, stats_type=None):
bins = defaultdict(set) bins = defaultdict(set)
for name, canonical_name, pages in generate_canonical_names(docalias_qs.values_list("docs__name", "name", "docs__pages")): for name, pages in document_qs.values_list("name", "pages"):
bins[pages or 0].add(canonical_name) bins[pages or 0].add(name)
series_data = [] series_data = []
for pages, names in sorted(bins.items(), key=lambda t: t[0]): for pages, names in sorted(bins.items(), key=lambda t: t[0]):
@ -297,8 +284,8 @@ def document_stats(request, stats_type=None):
bins = defaultdict(set) bins = defaultdict(set)
for name, canonical_name, words in generate_canonical_names(docalias_qs.values_list("docs__name", "name", "docs__words")): for name, words in document_qs.values_list("name", "words"):
bins[put_into_bin(words, bin_size)].add(canonical_name) bins[put_into_bin(words, bin_size)].add(name)
series_data = [] series_data = []
for (value, words), names in sorted(bins.items(), key=lambda t: t[0][0]): for (value, words), names in sorted(bins.items(), key=lambda t: t[0][0]):
@ -322,20 +309,20 @@ def document_stats(request, stats_type=None):
submission_types[doc_name] = file_types submission_types[doc_name] = file_types
doc_names_with_missing_types = {} doc_names_with_missing_types = {}
for doc_name, canonical_name, rev in generate_canonical_names(docalias_qs.values_list("docs__name", "name", "docs__rev")): for doc_name, doc_type, rev in document_qs.values_list("name", "type_id", "rev"):
types = submission_types.get(doc_name) types = submission_types.get(doc_name)
if types: if types:
for dot_ext in types.split(","): for dot_ext in types.split(","):
bins[dot_ext.lstrip(".").upper()].add(canonical_name) bins[dot_ext.lstrip(".").upper()].add(doc_name)
else: else:
if canonical_name.startswith("rfc"): if doc_type == "rfc":
filename = canonical_name filename = doc_name
else: else:
filename = canonical_name + "-" + rev filename = doc_name + "-" + rev
doc_names_with_missing_types[filename] = canonical_name doc_names_with_missing_types[filename] = doc_name
# look up the remaining documents on disk # look up the remaining documents on disk
for filename in itertools.chain(os.listdir(settings.INTERNET_ALL_DRAFTS_ARCHIVE_DIR), os.listdir(settings.RFC_PATH)): for filename in itertools.chain(os.listdir(settings.INTERNET_ALL_DRAFTS_ARCHIVE_DIR), os.listdir(settings.RFC_PATH)):
@ -348,10 +335,10 @@ def document_stats(request, stats_type=None):
if not any(ext==allowlisted_ext for allowlisted_ext in settings.DOCUMENT_FORMAT_ALLOWLIST): if not any(ext==allowlisted_ext for allowlisted_ext in settings.DOCUMENT_FORMAT_ALLOWLIST):
continue continue
canonical_name = doc_names_with_missing_types.get(basename) name = doc_names_with_missing_types.get(basename)
if canonical_name: if name:
bins[ext.upper()].add(canonical_name) bins[ext.upper()].add(name)
series_data = [] series_data = []
for fmt, names in sorted(bins.items(), key=lambda t: t[0]): for fmt, names in sorted(bins.items(), key=lambda t: t[0]):
@ -367,8 +354,8 @@ def document_stats(request, stats_type=None):
bins = defaultdict(set) bins = defaultdict(set)
for name, canonical_name, formal_language_name in generate_canonical_names(docalias_qs.values_list("docs__name", "name", "docs__formal_languages__name")): for name, formal_language_name in document_qs.values_list("name", "formal_languages__name"):
bins[formal_language_name or ""].add(canonical_name) bins[formal_language_name or ""].add(name)
series_data = [] series_data = []
for formal_language, names in sorted(bins.items(), key=lambda t: t[0]): for formal_language, names in sorted(bins.items(), key=lambda t: t[0]):

View file

@ -108,14 +108,14 @@ class Submission(models.Model):
@property @property
def active_wg_drafts_replaced(self): def active_wg_drafts_replaced(self):
return Document.objects.filter( return Document.objects.filter(
docalias__name__in=self.replaces.split(','), name__in=self.replaces.split(','),
group__in=Group.objects.active_wgs() group__in=Group.objects.active_wgs()
) )
@property @property
def closed_wg_drafts_replaced(self): def closed_wg_drafts_replaced(self):
return Document.objects.filter( return Document.objects.filter(
docalias__name__in=self.replaces.split(','), name__in=self.replaces.split(','),
group__in=Group.objects.closed_wgs() group__in=Group.objects.closed_wgs()
) )

View file

@ -34,7 +34,7 @@ from ietf.submit.utils import (expirable_submissions, expire_submission, find_su
process_and_validate_submission) process_and_validate_submission)
from ietf.doc.factories import (DocumentFactory, WgDraftFactory, IndividualDraftFactory, from ietf.doc.factories import (DocumentFactory, WgDraftFactory, IndividualDraftFactory,
ReviewFactory, WgRfcFactory) ReviewFactory, WgRfcFactory)
from ietf.doc.models import ( Document, DocAlias, DocEvent, State, from ietf.doc.models import ( Document, DocEvent, State,
BallotPositionDocEvent, DocumentAuthor, SubmissionDocEvent ) BallotPositionDocEvent, DocumentAuthor, SubmissionDocEvent )
from ietf.doc.utils import create_ballot_if_not_open, can_edit_docextresources, update_action_holders from ietf.doc.utils import create_ballot_if_not_open, can_edit_docextresources, update_action_holders
from ietf.group.factories import GroupFactory, RoleFactory from ietf.group.factories import GroupFactory, RoleFactory
@ -358,8 +358,6 @@ class SubmitTests(BaseSubmitTestCase):
note="", note="",
) )
sug_replaced_draft.set_state(State.objects.get(used=True, type="draft", slug="active")) sug_replaced_draft.set_state(State.objects.get(used=True, type="draft", slug="active"))
sug_replaced_alias = DocAlias.objects.create(name=sug_replaced_draft.name)
sug_replaced_alias.docs.add(sug_replaced_draft)
name = "draft-ietf-mars-testing-tests" name = "draft-ietf-mars-testing-tests"
rev = "00" rev = "00"
@ -400,7 +398,7 @@ class SubmitTests(BaseSubmitTestCase):
r = self.client.post(status_url, dict(action=action)) r = self.client.post(status_url, dict(action=action))
self.assertEqual(r.status_code, 302) self.assertEqual(r.status_code, 302)
draft = Document.objects.get(docalias__name=name) draft = Document.objects.get(name=name)
self.assertEqual(draft.rev, rev) self.assertEqual(draft.rev, rev)
new_revision = draft.latest_event(type="new_revision") new_revision = draft.latest_event(type="new_revision")
self.assertEqual(draft.group.acronym, "mars") self.assertEqual(draft.group.acronym, "mars")
@ -420,7 +418,7 @@ class SubmitTests(BaseSubmitTestCase):
self.assertEqual(draft.relations_that_doc("replaces").count(), 1) self.assertEqual(draft.relations_that_doc("replaces").count(), 1)
self.assertTrue(draft.relations_that_doc("replaces").first().target, draft) self.assertTrue(draft.relations_that_doc("replaces").first().target, draft)
self.assertEqual(draft.relations_that_doc("possibly-replaces").count(), 1) self.assertEqual(draft.relations_that_doc("possibly-replaces").count(), 1)
self.assertTrue(draft.relations_that_doc("possibly-replaces").first().target, sug_replaced_alias) self.assertTrue(draft.relations_that_doc("possibly-replaces").first().target, sug_replaced_draft)
self.assertEqual(len(outbox), mailbox_before + 5) self.assertEqual(len(outbox), mailbox_before + 5)
self.assertIn(("I-D Action: %s" % name), outbox[-4]["Subject"]) self.assertIn(("I-D Action: %s" % name), outbox[-4]["Subject"])
self.assertIn(author.ascii, get_payload_text(outbox[-4])) self.assertIn(author.ascii, get_payload_text(outbox[-4]))
@ -433,7 +431,7 @@ class SubmitTests(BaseSubmitTestCase):
# Check "Review of suggested possible replacements for..." mail # Check "Review of suggested possible replacements for..." mail
self.assertIn("review", outbox[-1]["Subject"].lower()) self.assertIn("review", outbox[-1]["Subject"].lower())
self.assertIn(name, get_payload_text(outbox[-1])) self.assertIn(name, get_payload_text(outbox[-1]))
self.assertIn(sug_replaced_alias.name, get_payload_text(outbox[-1])) self.assertIn(sug_replaced_draft.name, get_payload_text(outbox[-1]))
self.assertIn("ames-chairs@", outbox[-1]["To"].lower()) self.assertIn("ames-chairs@", outbox[-1]["To"].lower())
self.assertIn("mars-chairs@", outbox[-1]["To"].lower()) self.assertIn("mars-chairs@", outbox[-1]["To"].lower())
# Check submission settings # Check submission settings
@ -684,7 +682,7 @@ class SubmitTests(BaseSubmitTestCase):
self.assertTrue('New version approved' in edescs) self.assertTrue('New version approved' in edescs)
self.assertTrue('Uploaded new revision' in edescs) self.assertTrue('Uploaded new revision' in edescs)
draft = Document.objects.get(docalias__name=name) draft = Document.objects.get(name=name)
self.assertEqual(draft.rev, rev) self.assertEqual(draft.rev, rev)
self.assertEqual(draft.group.acronym, name.split("-")[2]) self.assertEqual(draft.group.acronym, name.split("-")[2])
# #
@ -911,7 +909,7 @@ class SubmitTests(BaseSubmitTestCase):
r = self.client.post(confirmation_url, {'action':'confirm'}) r = self.client.post(confirmation_url, {'action':'confirm'})
self.assertEqual(r.status_code, 302) self.assertEqual(r.status_code, 302)
draft = Document.objects.get(docalias__name=name) draft = Document.objects.get(name=name)
self.assertEqual(draft.rev, rev) self.assertEqual(draft.rev, rev)
new_revision = draft.latest_event() new_revision = draft.latest_event()
self.assertEqual(new_revision.type, "new_revision") self.assertEqual(new_revision.type, "new_revision")
@ -951,7 +949,7 @@ class SubmitTests(BaseSubmitTestCase):
action = force_post_button.parents("form").find('input[type=hidden][name="action"]').val() action = force_post_button.parents("form").find('input[type=hidden][name="action"]').val()
r = self.client.post(status_url, dict(action=action)) r = self.client.post(status_url, dict(action=action))
doc = Document.objects.get(docalias__name=name) doc = Document.objects.get(name=name)
self.assertEqual(doc.documentauthor_set.count(), 1) self.assertEqual(doc.documentauthor_set.count(), 1)
docauth = doc.documentauthor_set.first() docauth = doc.documentauthor_set.first()
self.assertEqual(docauth.person, author) self.assertEqual(docauth.person, author)
@ -1084,7 +1082,7 @@ class SubmitTests(BaseSubmitTestCase):
self.assertIn("New Version Notification", notification_email["Subject"]) self.assertIn("New Version Notification", notification_email["Subject"])
self.assertIn(author.email().address.lower(), notification_email["To"]) self.assertIn(author.email().address.lower(), notification_email["To"])
draft = Document.objects.get(docalias__name=name) draft = Document.objects.get(name=name)
self.assertEqual(draft.rev, rev) self.assertEqual(draft.rev, rev)
self.assertEqual(draft.docextresource_set.count(), 0) self.assertEqual(draft.docextresource_set.count(), 0)
new_revision = draft.latest_event() new_revision = draft.latest_event()
@ -1132,7 +1130,7 @@ class SubmitTests(BaseSubmitTestCase):
self._assert_extresources_form_not_present(r) self._assert_extresources_form_not_present(r)
# Check that the draft itself got the resources # Check that the draft itself got the resources
draft = Document.objects.get(docalias__name=name) draft = Document.objects.get(name=name)
self.assertCountEqual( self.assertCountEqual(
[str(r) for r in draft.docextresource_set.all()], [str(r) for r in draft.docextresource_set.all()],
[str(r) for r in resources], [str(r) for r in resources],
@ -1178,7 +1176,7 @@ class SubmitTests(BaseSubmitTestCase):
r = self.client.post(confirmation_url, {'action':'confirm'}) r = self.client.post(confirmation_url, {'action':'confirm'})
self.assertEqual(r.status_code, 302) self.assertEqual(r.status_code, 302)
self.assertEqual(len(outbox), mailbox_before+3) self.assertEqual(len(outbox), mailbox_before+3)
draft = Document.objects.get(docalias__name=name) draft = Document.objects.get(name=name)
self.assertEqual(draft.rev, rev) self.assertEqual(draft.rev, rev)
self.assertEqual(draft.relateddocument_set.filter(relationship_id='replaces').count(), replaces_count) self.assertEqual(draft.relateddocument_set.filter(relationship_id='replaces').count(), replaces_count)
self.assertEqual(draft.docextresource_set.count(), 0) self.assertEqual(draft.docextresource_set.count(), 0)
@ -1296,7 +1294,7 @@ class SubmitTests(BaseSubmitTestCase):
r = self.client.post(confirmation_url, {'action':'cancel'}) r = self.client.post(confirmation_url, {'action':'cancel'})
self.assertEqual(r.status_code, 302) self.assertEqual(r.status_code, 302)
self.assertEqual(len(outbox), mailbox_before) self.assertEqual(len(outbox), mailbox_before)
draft = Document.objects.get(docalias__name=name) draft = Document.objects.get(name=name)
self.assertEqual(draft.rev, old_rev) self.assertEqual(draft.rev, old_rev)
def test_submit_new_wg_with_dash(self): def test_submit_new_wg_with_dash(self):
@ -1453,7 +1451,7 @@ class SubmitTests(BaseSubmitTestCase):
r = self.client.post(status_url, dict(action=action)) r = self.client.post(status_url, dict(action=action))
self.assertEqual(r.status_code, 302) self.assertEqual(r.status_code, 302)
draft = Document.objects.get(docalias__name=name) draft = Document.objects.get(name=name)
self.assertEqual(draft.rev, rev) self.assertEqual(draft.rev, rev)
self.assertEqual(draft.docextresource_set.count(), 0) self.assertEqual(draft.docextresource_set.count(), 0)
self.verify_bibxml_ids_creation(draft) self.verify_bibxml_ids_creation(draft)

View file

@ -25,7 +25,7 @@ from django.utils import timezone
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import ( Document, State, DocAlias, DocEvent, SubmissionDocEvent, from ietf.doc.models import ( Document, State, DocEvent, SubmissionDocEvent,
DocumentAuthor, AddedMessageEvent ) DocumentAuthor, AddedMessageEvent )
from ietf.doc.models import NewRevisionDocEvent from ietf.doc.models import NewRevisionDocEvent
from ietf.doc.models import RelatedDocument, DocRelationshipName, DocExtResource from ietf.doc.models import RelatedDocument, DocRelationshipName, DocExtResource
@ -375,10 +375,6 @@ def post_submission(request, submission, approved_doc_desc, approved_subm_desc):
events.append(e) events.append(e)
log.log(f"{submission.name}: created doc events") log.log(f"{submission.name}: created doc events")
# update related objects
alias, __ = DocAlias.objects.get_or_create(name=submission.name)
alias.docs.add(draft)
draft.set_state(State.objects.get(used=True, type="draft", slug="active")) draft.set_state(State.objects.get(used=True, type="draft", slug="active"))
update_authors(draft, submission) update_authors(draft, submission)
@ -1000,7 +996,7 @@ def accept_submission(submission: Submission, request: Optional[HttpRequest] = N
docevent_from_submission(submission, desc="Uploaded new revision", docevent_from_submission(submission, desc="Uploaded new revision",
who=requester if requester_is_author else None) who=requester if requester_is_author else None)
replaces = DocAlias.objects.filter(name__in=submission.replaces_names) replaces = Document.objects.filter(name__in=submission.replaces_names)
pretty_replaces = '(none)' if not replaces else ( pretty_replaces = '(none)' if not replaces else (
', '.join(prettify_std_name(r.name) for r in replaces) ', '.join(prettify_std_name(r.name) for r in replaces)
) )

View file

@ -22,7 +22,7 @@ from django.views.decorators.csrf import csrf_exempt
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import Document, DocAlias, AddedMessageEvent from ietf.doc.models import Document, AddedMessageEvent
from ietf.doc.forms import ExtResourceForm from ietf.doc.forms import ExtResourceForm
from ietf.group.models import Group from ietf.group.models import Group
from ietf.group.utils import group_features_group_filter from ietf.group.utils import group_features_group_filter
@ -410,7 +410,7 @@ def submission_status(request, submission_id, access_token=None):
) )
submitter_form = SubmitterForm(initial=submission.submitter_parsed(), prefix="submitter") submitter_form = SubmitterForm(initial=submission.submitter_parsed(), prefix="submitter")
replaces_form = ReplacesForm(name=submission.name,initial=DocAlias.objects.filter(name__in=submission.replaces.split(","))) replaces_form = ReplacesForm(name=submission.name,initial=Document.objects.filter(name__in=submission.replaces.split(",")))
extresources_form = ExtResourceForm( extresources_form = ExtResourceForm(
initial=dict(resources=[er['res'] for er in external_resources]), initial=dict(resources=[er['res'] for er in external_resources]),
extresource_model=SubmissionExtResource, extresource_model=SubmissionExtResource,
@ -626,7 +626,7 @@ def edit_submission(request, submission_id, access_token=None):
else: else:
edit_form = EditSubmissionForm(instance=submission, prefix="edit") edit_form = EditSubmissionForm(instance=submission, prefix="edit")
submitter_form = SubmitterForm(initial=submission.submitter_parsed(), prefix="submitter") submitter_form = SubmitterForm(initial=submission.submitter_parsed(), prefix="submitter")
replaces_form = ReplacesForm(name=submission.name,initial=DocAlias.objects.filter(name__in=submission.replaces.split(","))) replaces_form = ReplacesForm(name=submission.name, initial=Document.objects.filter(name__in=submission.replaces.split(",")))
author_forms = [ AuthorForm(initial=author, prefix="authors-%s" % i) author_forms = [ AuthorForm(initial=author, prefix="authors-%s" % i)
for i, author in enumerate(submission.authors) ] for i, author in enumerate(submission.authors) ]

View file

@ -45,7 +45,7 @@ def update_rfc_log_from_protocol_page(rfc_names, rfc_must_published_later_than):
updated = [] updated = []
docs = Document.objects.filter(docalias__name__in=rfc_names).exclude( docs = Document.objects.filter(name__in=rfc_names).exclude(
docevent__type="rfc_in_iana_registry").filter( docevent__type="rfc_in_iana_registry").filter(
# only take those that were published after cutoff since we # only take those that were published after cutoff since we
# have a big bunch of old RFCs that we unfortunately don't have data for # have a big bunch of old RFCs that we unfortunately don't have data for
@ -189,7 +189,7 @@ def update_history_with_changes(changes, send_email=True):
state_type=state_type, state=state) state_type=state_type, state=state)
if not e: if not e:
try: try:
doc = Document.objects.get(docalias__name=docname) doc = Document.objects.get(name=docname)
except Document.DoesNotExist: except Document.DoesNotExist:
warnings.append("Document %s not found" % docname) warnings.append("Document %s not found" % docname)
continue continue

View file

@ -17,7 +17,7 @@ from django.utils.encoding import smart_bytes, force_str
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.models import ( Document, DocAlias, State, StateType, DocEvent, DocRelationshipName, from ietf.doc.models import ( Document, State, StateType, DocEvent, DocRelationshipName,
DocTagName, RelatedDocument ) DocTagName, RelatedDocument )
from ietf.doc.expire import move_draft_files_to_archive from ietf.doc.expire import move_draft_files_to_archive
from ietf.doc.utils import add_state_change_event, prettify_std_name, update_action_holders from ietf.doc.utils import add_state_change_event, prettify_std_name, update_action_holders
@ -156,7 +156,7 @@ def update_drafts_from_queue(drafts):
names = [t[0] for t in drafts] names = [t[0] for t in drafts]
drafts_in_db = dict((d.name, d) drafts_in_db = dict((d.name, d)
for d in Document.objects.filter(type="draft", docalias__name__in=names)) for d in Document.objects.filter(type="draft", name__in=names))
changed = set() changed = set()
@ -229,7 +229,7 @@ def update_drafts_from_queue(drafts):
# remove tags and states for those not in the queue anymore # remove tags and states for those not in the queue anymore
for d in Document.objects.exclude(docalias__name__in=names).filter(states__type="draft-rfceditor").distinct(): for d in Document.objects.exclude(name__in=names).filter(states__type="draft-rfceditor").distinct():
d.tags.remove(*list(tag_mapping.values())) d.tags.remove(*list(tag_mapping.values()))
d.unset_state("draft-rfceditor") d.unset_state("draft-rfceditor")
# we do not add a history entry here - most likely we already # we do not add a history entry here - most likely we already
@ -441,10 +441,6 @@ def update_docs_from_rfc_index(
) )
if created_rfc: if created_rfc:
rfc_changes.append(f"created document {prettify_std_name(doc.name)}") rfc_changes.append(f"created document {prettify_std_name(doc.name)}")
# Create DocAlias (for consistency until we drop DocAlias altogether)
alias, _ = DocAlias.objects.get_or_create(name=doc.name)
alias.docs.add(doc)
rfc_changes.append(f"created alias {prettify_std_name(doc.name)}")
doc.set_state(rfc_published_state) doc.set_state(rfc_published_state)
if draft: if draft:
doc.formal_languages.set(draft.formal_languages.all()) doc.formal_languages.set(draft.formal_languages.all())
@ -654,12 +650,15 @@ def update_docs_from_rfc_index(
) )
) )
if also: # This block attempted to alias subseries names to RFCs.
for a in also: # Handle that differently when we add subseries as a document type.
a = a.lower() #
if not DocAlias.objects.filter(name=a): # if also:
DocAlias.objects.create(name=a).docs.add(doc) # for a in also:
rfc_changes.append(f"created alias {prettify_std_name(a)}") # a = a.lower()
# if not DocAlias.objects.filter(name=a):
# DocAlias.objects.create(name=a).docs.add(doc)
# rfc_changes.append(f"created alias {prettify_std_name(a)}")
doc_errata = errata.get(f"RFC{rfc_number}", []) doc_errata = errata.get(f"RFC{rfc_number}", [])
all_rejected = doc_errata and all( all_rejected = doc_errata and all(

View file

@ -16,7 +16,7 @@ from django.utils import timezone
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.factories import WgDraftFactory, RfcFactory from ietf.doc.factories import WgDraftFactory, RfcFactory
from ietf.doc.models import Document, DocAlias, DocEvent, DeletedEvent, DocTagName, RelatedDocument, State, StateDocEvent from ietf.doc.models import Document, DocEvent, DeletedEvent, DocTagName, RelatedDocument, State, StateDocEvent
from ietf.doc.utils import add_state_change_event from ietf.doc.utils import add_state_change_event
from ietf.group.factories import GroupFactory from ietf.group.factories import GroupFactory
from ietf.person.models import Person from ietf.person.models import Person
@ -30,19 +30,20 @@ from ietf.utils.timezone import date_today, RPC_TZINFO
class IANASyncTests(TestCase): class IANASyncTests(TestCase):
def test_protocol_page_sync(self): def test_protocol_page_sync(self):
draft = WgDraftFactory() draft = WgDraftFactory()
DocAlias.objects.create(name="rfc1234").docs.add(draft) rfc = RfcFactory(rfc_number=1234)
DocEvent.objects.create(doc=draft, rev=draft.rev, type="published_rfc", by=Person.objects.get(name="(System)")) draft.relateddocument_set.create(relationship_id="became_rfc", target = rfc)
DocEvent.objects.create(doc=rfc, rev="", type="published_rfc", by=Person.objects.get(name="(System)"))
rfc_names = iana.parse_protocol_page('<html><a href="/go/rfc1234/">RFC 1234</a></html>') rfc_names = iana.parse_protocol_page('<html><a href="/go/rfc1234/">RFC 1234</a></html>')
self.assertEqual(len(rfc_names), 1) self.assertEqual(len(rfc_names), 1)
self.assertEqual(rfc_names[0], "rfc1234") self.assertEqual(rfc_names[0], "rfc1234")
iana.update_rfc_log_from_protocol_page(rfc_names, timezone.now() - datetime.timedelta(days=1)) iana.update_rfc_log_from_protocol_page(rfc_names, timezone.now() - datetime.timedelta(days=1))
self.assertEqual(DocEvent.objects.filter(doc=draft, type="rfc_in_iana_registry").count(), 1) self.assertEqual(DocEvent.objects.filter(doc=rfc, type="rfc_in_iana_registry").count(), 1)
# make sure it doesn't create duplicates # make sure it doesn't create duplicates
iana.update_rfc_log_from_protocol_page(rfc_names, timezone.now() - datetime.timedelta(days=1)) iana.update_rfc_log_from_protocol_page(rfc_names, timezone.now() - datetime.timedelta(days=1))
self.assertEqual(DocEvent.objects.filter(doc=draft, type="rfc_in_iana_registry").count(), 1) self.assertEqual(DocEvent.objects.filter(doc=rfc, type="rfc_in_iana_registry").count(), 1)
def test_changes_sync(self): def test_changes_sync(self):
draft = WgDraftFactory(ad=Person.objects.get(user__username='ad')) draft = WgDraftFactory(ad=Person.objects.get(user__username='ad'))
@ -380,10 +381,11 @@ class RFCSyncTests(TestCase):
tag_slugs = rfc_doc.tags.values_list("slug", flat=True) tag_slugs = rfc_doc.tags.values_list("slug", flat=True)
self.assertTrue("errata" in tag_slugs) self.assertTrue("errata" in tag_slugs)
self.assertFalse("verified-errata" in tag_slugs) self.assertFalse("verified-errata" in tag_slugs)
self.assertTrue(DocAlias.objects.filter(name="rfc1234", docs=rfc_doc)) # TODO: adjust these when we have subseries document types
self.assertTrue(DocAlias.objects.filter(name="bcp1", docs=rfc_doc)) # self.assertTrue(DocAlias.objects.filter(name="rfc1234", docs=rfc_doc))
self.assertTrue(DocAlias.objects.filter(name="fyi1", docs=rfc_doc)) # self.assertTrue(DocAlias.objects.filter(name="bcp1", docs=rfc_doc))
self.assertTrue(DocAlias.objects.filter(name="std1", docs=rfc_doc)) # self.assertTrue(DocAlias.objects.filter(name="fyi1", docs=rfc_doc))
# self.assertTrue(DocAlias.objects.filter(name="std1", docs=rfc_doc))
self.assertTrue(RelatedDocument.objects.filter(source=rfc_doc, target__name="rfc123", relationship="updates").exists()) self.assertTrue(RelatedDocument.objects.filter(source=rfc_doc, target__name="rfc123", relationship="updates").exists())
self.assertTrue(RelatedDocument.objects.filter(source=draft_doc, target=rfc_doc, relationship="became_rfc").exists()) self.assertTrue(RelatedDocument.objects.filter(source=draft_doc, target=rfc_doc, relationship="became_rfc").exists())
self.assertEqual(rfc_doc.title, "A Testing RFC") self.assertEqual(rfc_doc.title, "A Testing RFC")

View file

@ -67,7 +67,7 @@
<label class="d-none d-md-block" aria-label="Document search"> <label class="d-none d-md-block" aria-label="Document search">
<input class="form-control select2-field search-select" <input class="form-control select2-field search-select"
id="navbar-doc-search" id="navbar-doc-search"
data-select2-ajax-url="{% url 'ietf.doc.views_search.ajax_select2_search_docs' model_name='docalias' doc_type='draft' %}" data-select2-ajax-url="{% url 'ietf.doc.views_search.ajax_select2_search_docs' model_name='document' doc_type='draft' %}"
type="text" type="text"
data-placeholder="Document search"> data-placeholder="Document search">
</label> </label>

View file

@ -29,7 +29,7 @@
href="{% url 'ietf.doc.views_ballot.approve_ballot' name=doc.name %}">Approve ballot</a> href="{% url 'ietf.doc.views_ballot.approve_ballot' name=doc.name %}">Approve ballot</a>
{% endif %} {% endif %}
<a class="btn btn-secondary float-end" <a class="btn btn-secondary float-end"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Back Back
</a> </a>
</form> </form>

View file

@ -21,7 +21,7 @@
<button class="btn btn-primary" type="submit">Email RFC Editor (DNP) &amp; close ballot"</button> <button class="btn btn-primary" type="submit">Email RFC Editor (DNP) &amp; close ballot"</button>
{% endif %} {% endif %}
<a class="btn btn-secondary float-end" <a class="btn btn-secondary float-end"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Back Back
</a> </a>
</form> </form>

View file

@ -12,16 +12,16 @@
</h1> </h1>
<p> <p>
The ballot for The ballot for
<a href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}">{{ doc }}</a> <a href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">{{ doc }}</a>
was just approved. was just approved.
</p> </p>
{% if not downrefs_to_rfc %} {% if not downrefs_to_rfc %}
<p> <p>
No downward references for No downward references for
<a href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}">{{ doc }}</a> <a href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">{{ doc }}</a>
</p> </p>
<a class="btn btn-secondary" <a class="btn btn-secondary"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}">Back</a> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">Back</a>
{% else %} {% else %}
<p> <p>
Add downward references to RFCs to the DOWNREF registry, if they were identified in the IETF Last Call and approved by the Sponsoring Area Director. Add downward references to RFCs to the DOWNREF registry, if they were identified in the IETF Last Call and approved by the Sponsoring Area Director.
@ -41,7 +41,7 @@
{% csrf_token %} {% csrf_token %}
{% bootstrap_form approve_downrefs_form %} {% bootstrap_form approve_downrefs_form %}
<a class="btn btn-primary" <a class="btn btn-primary"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Add no DOWNREF entries Add no DOWNREF entries
</a> </a>
<button type="submit" class="btn btn-warning" value="Save checked downrefs">Add checked DOWNREF entries</button> <button type="submit" class="btn btn-warning" value="Save checked downrefs">Add checked DOWNREF entries</button>

View file

@ -11,7 +11,7 @@
</h1> </h1>
<p> <p>
Ballot for Ballot for
<a href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}">{{ doc }}</a> <a href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">{{ doc }}</a>
has been sent out. has been sent out.
</p> </p>
{% if doc.telechat_date %} {% if doc.telechat_date %}
@ -24,5 +24,5 @@
</p> </p>
{% endif %} {% endif %}
<a class="btn btn-secondary" <a class="btn btn-secondary"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}">Back</a> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">Back</a>
{% endblock %} {% endblock %}

View file

@ -14,14 +14,14 @@
{% csrf_token %} {% csrf_token %}
<p class="alert alert-danger my-3"> <p class="alert alert-danger my-3">
<b>Clear the ballot for <b>Clear the ballot for
<a href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}">{{ doc }}</a>? <a href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">{{ doc }}</a>?
</b> </b>
<br> <br>
This will clear all ballot positions and discuss entries. This will clear all ballot positions and discuss entries.
</p> </p>
<button type="submit" class="btn btn-danger">Clear</button> <button type="submit" class="btn btn-danger">Clear</button>
<a class="btn btn-secondary float-end" <a class="btn btn-secondary float-end"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Back Back
</a> </a>
</form> </form>

View file

@ -14,14 +14,14 @@
{% csrf_token %} {% csrf_token %}
<p class="alert alert-danger my-3"> <p class="alert alert-danger my-3">
<b>Defer the ballot for <b>Defer the ballot for
<a href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}">{{ doc }}</a>? <a href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">{{ doc }}</a>?
</b> </b>
<br> <br>
The ballot will then be put on the IESG agenda of {{ telechat_date }}. The ballot will then be put on the IESG agenda of {{ telechat_date }}.
</p> </p>
<button type="submit" class="btn btn-danger">Defer ballot</button> <button type="submit" class="btn btn-danger">Defer ballot</button>
<a class="btn btn-secondary float-end" <a class="btn btn-secondary float-end"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Back Back
</a> </a>
</form> </form>

View file

@ -54,7 +54,7 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
<a class="btn btn-secondary float-end" <a class="btn btn-secondary float-end"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Back Back
</a> </a>
</div> </div>

View file

@ -39,7 +39,7 @@
href="{% url 'ietf.doc.views_ballot.make_last_call' name=doc.name %}">Issue last call</a> href="{% url 'ietf.doc.views_ballot.make_last_call' name=doc.name %}">Issue last call</a>
{% endif %} {% endif %}
<a class="btn btn-secondary float-end" <a class="btn btn-secondary float-end"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Back Back
</a> </a>
</form> </form>

View file

@ -31,7 +31,7 @@
Clear Clear
</button> </button>
<a class="btn btn-secondary float-end" <a class="btn btn-secondary float-end"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Back Back
</a> </a>
</form> </form>

View file

@ -37,7 +37,7 @@
</div> </div>
<button type="submit" class="btn btn-danger">Send</button> <button type="submit" class="btn btn-danger">Send</button>
<a class="btn btn-secondary float-end" <a class="btn btn-secondary float-end"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Back Back
</a> </a>
</form> </form>

View file

@ -19,7 +19,7 @@
</p> </p>
<button class="btn btn-danger" type="submit">Undefer ballot</button> <button class="btn btn-danger" type="submit">Undefer ballot</button>
<a class="btn btn-secondary float-end" <a class="btn btn-secondary float-end"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Back Back
</a> </a>
</form> </form>

View file

@ -32,7 +32,7 @@
Save &amp; {% if ballot_issued %}re-{% endif %}issue ballot Save &amp; {% if ballot_issued %}re-{% endif %}issue ballot
</button> </button>
<a class="btn btn-secondary float-end" <a class="btn btn-secondary float-end"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Back Back
</a> </a>
</form> </form>

View file

@ -16,7 +16,7 @@
{% bootstrap_form form %} {% bootstrap_form form %}
<button type="submit" class="btn btn-primary">Submit</button> <button type="submit" class="btn btn-primary">Submit</button>
<a class="btn btn-secondary float-end" <a class="btn btn-secondary float-end"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Back Back
</a> </a>
</form> </form>

View file

@ -16,7 +16,7 @@
{% bootstrap_form form %} {% bootstrap_form form %}
<button type="submit" class="btn btn-primary">Submit</button> <button type="submit" class="btn btn-primary">Submit</button>
<a class="btn btn-secondary float-end" <a class="btn btn-secondary float-end"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Back Back
</a> </a>
</form> </form>

View file

@ -15,7 +15,7 @@
{% bootstrap_form form %} {% bootstrap_form form %}
<button type="submit" class="btn btn-primary">Submit</button> <button type="submit" class="btn btn-primary">Submit</button>
<a class="btn btn-secondary float-end" <a class="btn btn-secondary float-end"
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}"> href="{% url "ietf.doc.views_doc.document_main" name=doc.name %}">
Back Back
</a> </a>
</form> </form>

Some files were not shown because too many files have changed in this diff Show more