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: |
echo "Running checks..."
./ietf/manage.py check
./ietf/manage.py migrate --fake-initial
echo "Starting datatracker..."
./ietf/manage.py runserver 0.0.0.0:8000 --settings=settings_local &
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
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')
received = self.getJson(dict(name=f'RfC {number}'))
@ -1032,7 +1032,7 @@ class RfcdiffSupportTests(TestCase):
draft = reload_db_objects(draft)
# 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'))
def do_rfc_with_broken_history_test(self, draft_name):
@ -1048,7 +1048,7 @@ class RfcdiffSupportTests(TestCase):
received,
dict(
content_url=rfc.get_href(),
name=rfc.canonical_name(),
name=rfc.name,
previous=f'{draft.name}-10',
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()
condition, document, history, found_rev = find_doc_for_rfcdiff(name, rev)
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':
raise Http404
elif condition in ('historic version', 'current version'):
@ -336,8 +336,7 @@ def rfcdiff_latest_json(request, name, rev=None):
if doc.type_id == "rfc":
response['content_url'] = doc.get_href()
response['name']=doc.name
if draft_alias:
draft = draft_alias.document
if draft:
prev_rev = draft.rev
if doc.rfc_number in HAS_TOMBSTONE and prev_rev != '00':
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))
for rfc in new_rfcs:
rebuild_reference_relations(rfc)
log("Updated references for %s"%rfc.canonical_name())
log("Updated references for %s"%rfc.name)
except:
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]))

View file

@ -60,7 +60,7 @@ def reset_name_contains_index_for_rule(rule):
if not rule.rule_type == "name_contains":
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):
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
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":
clist = lookup_community_list(username, acronym)
@ -153,7 +153,7 @@ def track_document(request, name, username=None, acronym=None):
@login_required
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)
if not can_manage_community_list(request.user, clist):
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 .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,
TelechatDocEvent, BallotPositionDocEvent, ReviewRequestDocEvent, InitialReviewDocEvent,
AddedMessageEvent, SubmissionDocEvent, DeletedEvent, EditedAuthorsDocEvent, DocumentURL,
@ -27,10 +27,6 @@ class StateAdmin(admin.ModelAdmin):
filter_horizontal = ["next_states"]
admin.site.register(State, StateAdmin)
# class DocAliasInline(admin.TabularInline):
# model = DocAlias
# extra = 1
class DocAuthorInline(admin.TabularInline):
model = DocumentAuthor
raw_id_fields = ['person', 'email']
@ -45,7 +41,7 @@ class RelatedDocumentInline(admin.TabularInline):
model = RelatedDocument
fk_name= 'source'
def this(self, instance):
return instance.source.canonical_name()
return instance.source.name
readonly_fields = ['this', ]
fields = ['this', 'relationship', 'target', ]
raw_id_fields = ['target']
@ -71,7 +67,7 @@ class DocumentForm(forms.ModelForm):
class DocumentAuthorAdmin(admin.ModelAdmin):
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"]
admin.site.register(DocumentAuthor, DocumentAuthorAdmin)
@ -109,14 +105,6 @@ class DocHistoryAdmin(admin.ModelAdmin):
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):
list_display = ['id', 'event', '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.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,
DocumentActionHolder, BofreqEditorDocEvent, BofreqResponsibleDocEvent, DocExtResource )
from ietf.group.models import Group
@ -52,15 +52,6 @@ class BaseDocumentFactory(factory.django.DjangoModelFactory):
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
def states(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument
if create and extracted:
@ -128,12 +119,6 @@ class RfcFactory(BaseDocumentFactory):
else:
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):
@ -285,23 +270,6 @@ class ReviewFactory(BaseDocumentFactory):
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')
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 Meta:
model = DocEvent

View file

@ -36,7 +36,7 @@ class DocumentChangesFeed(Feed):
feed_type = Atom1Feed
def get_object(self, request, name):
return Document.objects.get(docalias__name=name)
return Document.objects.get(name=name)
def title(self, obj):
return "Changes for %s" % obj.display_name()
@ -46,7 +46,7 @@ class DocumentChangesFeed(Feed):
raise FeedDoesNotExist
return urlreverse(
"ietf.doc.views_doc.document_history",
kwargs=dict(name=obj.canonical_name()),
kwargs=dict(name=obj.name),
)
def subtitle(self, obj):
@ -86,7 +86,7 @@ class DocumentChangesFeed(Feed):
return (
urlreverse(
"ietf.doc.views_doc.document_history",
kwargs=dict(name=item.doc.canonical_name()),
kwargs=dict(name=item.doc.name),
)
+ "#history-%s" % item.pk
)
@ -208,13 +208,13 @@ class RfcFeed(Feed):
return [doc for doc, time in results]
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):
return item.abstract
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):
return item.publication_time
@ -229,7 +229,7 @@ class RfcFeed(Feed):
for fmt, media_type in [("txt", "text/plain"), ("html", "text/html")]:
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,
"is_format_of": self.item_link(item),
}
@ -237,7 +237,7 @@ class RfcFeed(Feed):
if item.rfc_number not in [571, 587]:
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",
"is_format_of": self.item_link(item),
}
@ -245,7 +245,7 @@ class RfcFeed(Feed):
else:
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",
}
)
@ -256,16 +256,16 @@ class RfcFeed(Feed):
]:
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,
"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({"doi": "10.17487/%s" % item.canonical_name().upper()})
extra.update({"doi": "10.17487/%s" % item.name.upper()})
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)

View file

@ -13,7 +13,7 @@ from django.urls import reverse as urlreverse
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.utils.fields import SearchableField
@ -69,19 +69,3 @@ class SearchableDocumentsField(SearchableField):
class SearchableDocumentField(SearchableDocumentsField):
"""Specialized to only return one Document"""
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.mail import send_mail, send_mail_text
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_bofreq import bofreq_editors, bofreq_responsible
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)
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:
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 ]
@ -670,7 +670,7 @@ def send_review_possibly_replaces_request(request, doc, submitter_info):
to = set(addrs.to)
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:
(other_to, other_cc) = gather_address_lists('doc_replacement_suggested',doc=other_doc)
to.update(other_to)

View file

@ -16,7 +16,7 @@ from pathlib import Path
from django.conf import settings
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
@ -95,7 +95,6 @@ class Command(BaseCommand):
uploaded_filename=filename,
)
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("-")]
e1 = DocEvent.objects.create(
time=datetime.datetime(

View file

@ -8,7 +8,7 @@ def forward(apps, schema_editor):
Document = apps.get_model("doc", "Document")
RelatedDocument = apps.get_model("doc", "RelatedDocument")
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
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.utils import get_active_balloters
from ietf.utils import log
from ietf.utils.admin import admin_link
from ietf.utils.decorators import memoize
from ietf.utils.validators import validate_no_control_chars
from ietf.utils.mail import formataddr
@ -173,7 +172,7 @@ class DocumentInfo(models.Model):
if self.uploaded_filename:
self._cached_base_name = self.uploaded_filename
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':
if self.is_dochistory():
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)
elif self.type_id in ["slides", "agenda", "minutes", "bluesheets", "procmaterials", ] and self.meeting_related():
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':
# 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
@ -189,9 +188,9 @@ class DocumentInfo(models.Model):
self._cached_base_name = "%s-%s.md" % (self.name, self.rev)
else:
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:
self._cached_base_name = "%s.txt" % (self.canonical_name(), )
self._cached_base_name = "%s.txt" % (self.name, )
return self._cached_base_name
def get_file_name(self):
@ -355,7 +354,7 @@ class DocumentInfo(models.Model):
elif state.slug == "repl":
rs = self.related_that("replaces")
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:
return "Replaced"
elif state.slug == "active":
@ -493,10 +492,10 @@ class DocumentInfo(models.Model):
return related
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):
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):
return list(set([x.target for x in self.relations_that_doc(relationship)]))
@ -507,7 +506,7 @@ class DocumentInfo(models.Model):
def replaces(self):
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")])
first = list(s)[0] if s else None
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":
try:
html = Path(
os.path.join(settings.RFC_PATH, self.canonical_name() + ".html")
os.path.join(settings.RFC_PATH, self.name + ".html")
).read_text()
except (IOError, UnicodeDecodeError):
return None
@ -805,7 +804,7 @@ class Document(DocumentInfo):
name = self.name
url = None
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")
elif self.type_id in ('slides','bluesheets','recording'):
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()
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):
name = self.canonical_name()
name = self.name
if name.startswith('rfc'):
name = name.upper()
return name
@ -953,8 +938,9 @@ class Document(DocumentInfo):
def ipr(self,states=('posted','removed')):
"""Returns the IPR disclosures against this document (as a queryset over IprDocRel)."""
from ietf.ipr.models import IprDocRel
return IprDocRel.objects.filter(document__docs=self, disclosure__state__in=states)
# from ietf.ipr.models import IprDocRel
# 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):
"""Returns the IPR disclosures against this document and those documents this
@ -963,8 +949,8 @@ class Document(DocumentInfo):
from ietf.ipr.models import IprDocRel
iprs = (
IprDocRel.objects.filter(
document__in=list(self.docalias.all())
+ [x.docalias.first() for x in self.all_related_that_doc(("obs", "replaces"))] # this really is docalias until IprDocRel changes
document__in=[self]
+ self.all_related_that_doc(("obs", "replaces"))
)
.filter(disclosure__state__in=("posted", "removed"))
.values_list("disclosure", flat=True)
@ -1123,10 +1109,7 @@ class DocHistoryAuthor(DocumentAuthorInfo):
class DocHistory(DocumentInfo):
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)
def __str__(self):
@ -1138,11 +1121,6 @@ class DocHistory(DocumentInfo):
def get_related_proceedings_material(self):
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):
kwargs["time__lte"] = self.time
return self.doc.latest_event(*args, **kwargs)
@ -1157,10 +1135,6 @@ class DocHistory(DocumentInfo):
def groupmilestone_set(self):
return self.doc.groupmilestone_set
@property
def docalias(self):
return self.doc.docalias
def is_dochistory(self):
return True
@ -1178,25 +1152,6 @@ class DocHistory(DocumentInfo):
verbose_name = "document history"
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):
event = ForeignKey('DocEvent')

View file

@ -12,7 +12,7 @@ from tastypie.cache import SimpleCache
from ietf import api
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,
InitialReviewDocEvent, DocHistoryAuthor, BallotDocEvent, RelatedDocument,
RelatedDocHistory, BallotPositionDocEvent, AddedMessageEvent, SubmissionDocEvent,
@ -286,21 +286,6 @@ class ConsensusDocEventResource(ModelResource):
}
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
class TelechatDocEventResource(ModelResource):
by = ToOneField(PersonResource, 'by')
@ -490,7 +475,7 @@ api.doc.register(BallotDocEventResource())
from ietf.name.resources import DocRelationshipNameResource
class RelatedDocumentResource(ModelResource):
source = ToOneField(DocumentResource, 'source')
target = ToOneField(DocAliasResource, 'target')
target = ToOneField(DocumentResource, 'target')
relationship = ToOneField(DocRelationshipNameResource, 'relationship')
class Meta:
cache = SimpleCache()
@ -509,7 +494,7 @@ api.doc.register(RelatedDocumentResource())
from ietf.name.resources import DocRelationshipNameResource
class RelatedDocHistoryResource(ModelResource):
source = ToOneField(DocHistoryResource, 'source')
target = ToOneField(DocAliasResource, 'target')
target = ToOneField(DocumentResource, 'target')
relationship = ToOneField(DocRelationshipNameResource, 'relationship')
class Meta:
cache = SimpleCache()

View file

@ -22,7 +22,7 @@ from django.utils import timezone
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.ietfauth.utils import can_request_rfc_publication as utils_can_request_rfc_publication
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}')
def doc_canonical_name(name):
def doc_name(name):
"""Check whether a given document exists, and return its canonical name"""
def find_unique(n):
key = hash(n)
found = cache.get(key)
if not found:
exact = DocAlias.objects.filter(name=n).first()
exact = Document.objects.filter(name=n).first()
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
return None if found == "_" else found
@ -173,7 +174,7 @@ def doc_canonical_name(name):
def link_charter_doc_match(match):
if not doc_canonical_name(match[0]):
if not doc_name(match[0]):
return match[0]
url = urlreverse(
"ietf.doc.views_doc.document_main",
@ -186,7 +187,7 @@ def link_non_charter_doc_match(match):
name = match[0]
# handle "I-D.*"" reference-style matches
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:
return match[0]
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))
return f'<a href="{url}">{match[0]}</a>'
cname = doc_canonical_name(name)
cname = doc_name(name)
if not cname:
return match[0]
if name == cname:
@ -221,7 +222,7 @@ def link_non_charter_doc_match(match):
def link_other_doc_match(match):
doc = match[2].strip().lower()
rev = match[3]
if not doc_canonical_name(doc + rev):
if not doc_name(doc + rev):
return match[0]
url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=doc + rev))
return f'<a href="{url}">{match[1]}</a>'
@ -255,6 +256,7 @@ def urlize_ietf_docs(string, autoescape=None):
string,
flags=re.IGNORECASE | re.ASCII,
)
return mark_safe(string)
@ -267,7 +269,7 @@ def urlize_related_source_list(related, document_html=False):
names = set()
titles = set()
for rel in related:
name=rel.source.canonical_name()
name=rel.source.name
title = rel.source.title
if name in names and title in titles:
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"""
links = []
for rel in related:
name=rel.target.canonical_name()
name=rel.target.name
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))
name = escape(name)

View file

@ -3,12 +3,12 @@
from django.conf import settings
from ietf.doc.factories import (
WgDraftFactory,
WgRfcFactory,
IndividualDraftFactory,
CharterFactory,
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.person.models import Person
from ietf.utils.test_utils import TestCase
@ -25,23 +25,21 @@ class IetfFiltersTests(TestCase):
self.assertEqual(is_valid_url(url), result)
def test_urlize_ietf_docs(self):
wg_id = WgDraftFactory()
wg_id.set_state(State.objects.get(type="draft", slug="rfc"))
wg_id.std_level_id = "bcp"
wg_id.save_with_history(
rfc = WgRfcFactory(rfc_number=123456,std_level_id="bcp")
rfc.save_with_history(
[
DocEvent.objects.create(
doc=wg_id,
rev=wg_id.rev,
doc=rfc,
rev=rfc.rev,
type="published_rfc",
by=Person.objects.get(name="(System)"),
)
]
)
DocAlias.objects.create(name="rfc123456").docs.add(wg_id)
DocAlias.objects.create(name="bcp123456").docs.add(wg_id)
DocAlias.objects.create(name="std123456").docs.add(wg_id)
DocAlias.objects.create(name="fyi123456").docs.add(wg_id)
# TODO - bring these into existance when subseries are well modeled
# DocAlias.objects.create(name="bcp123456").docs.add(rfc)
# DocAlias.objects.create(name="std123456").docs.add(rfc)
# DocAlias.objects.create(name="fyi123456").docs.add(rfc)
id = IndividualDraftFactory(name="draft-me-rfc123456bis")
id_num = IndividualDraftFactory(name="draft-rosen-rfcefdp-update-2026")
@ -59,15 +57,17 @@ class IetfFiltersTests(TestCase):
cases = [
("no change", "no change"),
("bCp123456", '<a href="/doc/bcp123456/">bCp123456</a>'),
("Std 00123456", '<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>',
),
# TODO: rework subseries when we add them
# ("bCp123456", '<a href="/doc/bcp123456/">bCp123456</a>'),
# ("Std 00123456", '<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>'),
("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'<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
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,
EditedAuthorsDocEvent )
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'))
rfc = IndividualDraftFactory(ad=ad)
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.set_state(State.objects.get(type='conflrev', slug='iesgeval'))
statchg = DocumentFactory(type_id='statchg',ad=ad)
@ -348,7 +347,7 @@ class SearchTests(TestCase):
self.assertEqual(r.status_code, 200)
self.assertContains(r, draft.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, statchg.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'))
self.assertEqual(r.status_code, 200)
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'))
self.assertEqual(r.status_code, 200)
@ -415,19 +414,6 @@ class SearchTests(TestCase):
data = r.json()
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):
# Three drafts to show with various warnings
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':
self.assertContains(r, "Show full document")
self.assertNotContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name())
self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title)
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, "Show full document")
self.assertNotContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name())
self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title)
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.assertNotContains(r, "Show full document")
self.assertContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name())
self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title)
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.assertNotContains(r, "Show full document")
self.assertContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name())
self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title)
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.assertNotContains(r, "Show full document")
self.assertContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name())
self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title)
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, "Show full document")
self.assertNotContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name())
self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title)
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':
self.assertContains(r, "Show full document")
self.assertNotContains(r, "Deimos street")
self.assertContains(r, replaced.canonical_name())
self.assertContains(r, replaced.name)
self.assertContains(r, replaced.title)
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.save_with_history([DocEventFactory(doc=rfc)])
(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)
q = PyQuery(r.content)
self.assertEqual(q('title').text(), f'RFC {rfc.rfc_number} - {rfc.title}')
# 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)))
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}')))
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
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)))
self.assertEqual(r.status_code, 200)
self.assertContains(r, "Replaced Internet-Draft")
self.assertContains(r, replacement.canonical_name())
self.assertContains(r, replacement.name)
self.assertContains(r, replacement.title)
rel.delete()
@ -801,13 +787,13 @@ Man Expires September 22, 2015 [Page 3]
self.assertContains(r, "RFC 123456")
self.assertContains(r, draft.name)
# 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_by.canonical_name())
self.assertContains(r, obsoleted_by.name)
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_by.canonical_name())
self.assertContains(r, updated_by.name)
self.assertContains(r, updated_by.title)
# 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(
urlreverse(
'ietf.doc.views_doc.document_main',
kwargs={'name': draft.canonical_name()},
kwargs={'name': draft.name},
)
)
self.assertEqual(r.status_code, 200)
@ -2712,20 +2698,20 @@ class Idnits2SupportTests(TestCase):
rfc = WgRfcFactory()
draft = WgDraftFactory()
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)
self.assertEqual(r.status_code, 200)
self.assertContains(r,'rfcnum')
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)
self.assertEqual(r.status_code, 200)
self.assertNotContains(r,'rfcnum')
self.assertContains(r,'Unknown')
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)
self.assertEqual(r.status_code, 200)
self.assertContains(r,'Proposed')

View file

@ -18,7 +18,7 @@ from django.utils import timezone
from ietf.group.factories import RoleFactory
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.ietfauth.utils import has_role
from ietf.person.factories import PersonFactory
@ -32,7 +32,7 @@ class BofreqTests(TestCase):
settings_temp_path_overrides = TestCase.settings_temp_path_overrides + ['BOFREQ_PATH']
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:
f.write(f"""# This is a test bofreq.
Version: {bofreq.rev}
@ -366,7 +366,6 @@ This test section has some text.
name = f"bofreq-{xslugify(nobody.last_name())[:64]}-{postdict['title']}".replace(' ','-')
bofreq = Document.objects.filter(name=name,type_id='bofreq').first()
self.assertIsNotNone(bofreq)
self.assertIsNotNone(DocAlias.objects.filter(name=name).first())
self.assertEqual(bofreq.title, postdict['title'])
self.assertEqual(bofreq.rev, '00')
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
# 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.assertFalse(os.path.exists(path))
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
# 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')
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:
f.write('This is the old proposal.')
f.close()
@ -435,7 +435,7 @@ class ConflictReviewSubmitTests(TestCase):
self.assertEqual(r.status_code, 302)
doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
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:
self.assertEqual(f.read(),"This is a new proposal.")
f.close()

View file

@ -19,11 +19,8 @@ class Downref(TestCase):
super().setUp()
PersonFactory(name='Plain Man',user__username='plain')
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.docalias = self.doc.docalias.get(name='draft-ietf-mars-approved-document')
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')
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.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.models import Group
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.set_state(State.objects.get(type="slides", slug="active"))
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='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,
WgRfcFactory, ReviewFactory, DocumentFactory)
from ietf.doc.models import ( Document, DocumentAuthor, RelatedDocument, DocEvent, ReviewRequestDocEvent,
from ietf.doc.models import ( DocumentAuthor, RelatedDocument, DocEvent, ReviewRequestDocEvent,
ReviewAssignmentDocEvent, )
from ietf.group.factories import RoleFactory, ReviewTeamFactory
from ietf.group.models import Group
@ -922,7 +922,8 @@ class ReviewTests(TestCase):
date_today().isoformat(),
]
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={
"result": ReviewResultName.objects.get(reviewteamsettings_review_results_set__group=assignment.review_request.team, slug="ready").pk,
@ -938,8 +939,7 @@ class ReviewTests(TestCase):
})
self.assertEqual(r.status_code, 302)
r2 = self.client.get(r.url)
# FIXME-LARS: this fails when the tests are run with --debug-mode, i.e., DEBUG is set:
if not settings.DEBUG:
self.assertEqual(r2.status_code, 200)
self.assertEqual(len(r2.context['messages']),1)
self.assertIn('Attempt to save review failed', list(r2.context['messages'])[0].message)

View file

@ -41,7 +41,7 @@ class IssueRSABBallotTests(TestCase):
self.client.login(username="rsab-chair", password="rsab-chair+password")
for name in [
doc.canonical_name()
doc.name
for doc in (individual_draft, wg_draft, rg_draft, ed_rfc)
]:
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 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.person.factories import PersonFactory
from ietf.utils.mail import outbox, empty_outbox
@ -241,7 +241,6 @@ This test section has some text.
name=name, type_id="statement"
).first()
self.assertIsNotNone(statement)
self.assertIsNotNone(DocAlias.objects.filter(name=name).first())
self.assertEqual(statement.title, postdict["title"])
self.assertEqual(statement.rev, "00")
self.assertEqual(statement.get_state_slug(), "active")

View file

@ -396,9 +396,9 @@ class StatusChangeTests(TestCase):
self.assertTrue(notification['Subject'].startswith('Approved:'))
notification_text = get_payload_text(notification)
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='rfc9998').canonical_name(), notification_text)
self.assertNotIn(Document.objects.get(name='rfc14').canonical_name(), notification_text)
self.assertIn(Document.objects.get(name='rfc9999').name, notification_text)
self.assertIn(Document.objects.get(name='rfc9998').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
else:
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
# 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.assertFalse(os.path.exists(path))
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
# 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')
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:
f.write('This is the old proposal.')
f.close()
@ -552,7 +552,7 @@ class StatusChangeSubmitTests(TestCase):
self.assertEqual(r.status_code, 302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
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:
self.assertEqual(f.read(),"This is a new proposal.")
f.close()

View file

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

View file

@ -90,7 +90,7 @@ urlpatterns = [
url(r'^all/?$', views_search.index_all_drafts),
url(r'^active/?$', views_search.index_active_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/rsab/$', views_ballot.rsab_ballot_status),

View file

@ -56,7 +56,7 @@ def save_document_in_history(doc):
# copy fields
fields = get_model_fields_as_dict(doc)
fields["doc"] = doc
fields["name"] = doc.canonical_name()
fields["name"] = doc.name
dochist = DocHistory(**fields)
dochist.save()
@ -775,7 +775,6 @@ def rebuild_reference_relations(doc, filenames):
if not refdoc and re.match(r"^draft-.*-\d{2}$", ref):
refdoc = Document.objects.filter(name=ref[:-3])
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:
unfound.add( "%s" % ref )
continue
@ -933,8 +932,7 @@ def make_rev_history(doc):
if predecessors is None:
predecessors = []
if hasattr(doc, 'relateddocument_set'):
for alias in doc.related_that_doc('replaces'):
for document in alias.docs.all():
for document in doc.related_that_doc('replaces'):
if document not in predecessors:
predecessors.append(document)
predecessors.extend(get_predecessors(document, predecessors))
@ -944,8 +942,7 @@ def make_rev_history(doc):
if ancestors is None:
ancestors = []
if hasattr(doc, 'relateddocument_set'):
for alias in doc.related_that('replaces'):
for document in alias.docs.all():
for document in doc.related_that('replaces'):
if document not in ancestors:
ancestors.append(document)
ancestors.extend(get_ancestors(document, ancestors))
@ -981,8 +978,8 @@ def make_rev_history(doc):
if e:
url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=e.doc))
history[url] = {
'name': e.doc.canonical_name(),
'rev': e.doc.canonical_name(),
'name': e.doc.name,
'rev': e.doc.name,
'published': e.time.isoformat(),
'url': url
}
@ -1120,6 +1117,9 @@ def generate_idnits2_rfc_status():
# Workarounds for unusual states in the datatracker
# The explanation for 6312 is from before docalias was removed
# The workaround is still needed, even if the datatracker
# state no longer matches what's described here:
# Document.get(docalias='rfc6312').rfc_number == 6342
# 6312 was published with the wrong rfc number in it
# weird workaround in the datatracker - there are two
@ -1177,12 +1177,12 @@ def fuzzy_find_documents(name, rev=None):
sought_type = "draft"
# 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():
# No document found, see if the name/rev split has been misidentified.
# Handles some special cases, like draft-ietf-tsvwg-ieee-802-11.
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():
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 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.utils import augment_docs_and_user_with_user_info
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):
# fill in some attributes for the document table results to save
# 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_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
event_types = ("published_rfc",
@ -90,8 +91,6 @@ def fill_in_document_table_attributes(docs, have_telechat_date=False):
# misc
expirable_pks = expirable_drafts(Document.objects.filter(pk__in=doc_ids)).values_list('pk', flat=True)
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"]:
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
# errata
erratas = set(Document.objects.filter(tags="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(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(rfcs.keys())).distinct().values_list("name", flat=True))
for d in docs:
d.has_errata = d.name in erratas
d.has_verified_errata = d.name in verified_erratas
# obsoleted/updated by
for a in rfc_aliases:
d = doc_dict[a]
for rfc in rfcs:
d = doc_dict[rfc]
d.obsoleted_by_list = []
d.updated_by_list = []
# Revisit this block after RFCs become first-class Document objects
xed_by = list(
RelatedDocument.objects.filter(
target__name__in=list(rfc_aliases.values()),
target__name__in=list(rfcs.values()),
relationship__in=("obs", "updates"),
).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)
for a in DocAlias.objects.filter(
name__startswith="rfc", docs__id__in=[rel.source_id for rel in xed_by]
for a in Document.objects.filter(
type_id="rfc", id__in=[rel.source_id for rel in xed_by]
)
}
xed_by.sort(
@ -158,7 +158,7 @@ def fill_in_document_table_attributes(docs, have_telechat_date=False):
re.sub(
r"rfc\s*(\d+)",
r"\1",
rel_rfc_aliases[rel.source_id],
rel_rfcs[rel.source_id],
flags=re.IGNORECASE,
)
)
@ -192,7 +192,7 @@ def prepare_document_table(request, docs, query=None, max_results=200):
# the number of queries
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",
"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 = list(docs)
else:
@ -249,7 +249,7 @@ def prepare_document_table(request, docs, query=None, max_results=200):
if rfc_num is not None:
res.append(rfc_num)
else:
res.append(d.canonical_name())
res.append(d.name)
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")
def edit_position(request, name, ballot_id):
"""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)
balloter = login = request.user.person
@ -256,7 +256,7 @@ def api_set_position(request):
if not name:
return err(400, "Missing document name")
try:
doc = Document.objects.get(docalias__name=name)
doc = Document.objects.get(name=name)
except Document.DoesNotExist:
return err(400, "Document not found")
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')
def send_ballot_comment(request, name, ballot_id):
"""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)
if not has_role(request.user, 'Secretariat'):
@ -413,7 +413,7 @@ def clear_ballot(request, name, ballot_type_slug):
@role_required('Area Director','Secretariat')
def defer_ballot(request, name):
"""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'):
raise Http404
interesting_state = dict(draft='draft-iesg',conflrev='conflrev',statchg='statchg')
@ -467,7 +467,7 @@ def defer_ballot(request, name):
@role_required('Area Director','Secretariat')
def undefer_ballot(request, name):
"""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'):
raise Http404
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')
def lastcalltext(request, name):
"""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"):
raise Http404
@ -589,7 +589,7 @@ class BallotWriteupForm(forms.Form):
@role_required('Area Director','Secretariat')
def ballot_writeupnotes(request, name):
"""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")
login = request.user.person
@ -700,7 +700,7 @@ class BallotRfcEditorNoteForm(forms.Form):
@role_required('Area Director','Secretariat','IAB Chair','IRTF Chair','ISE')
def ballot_rfceditornote(request, name):
"""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):
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')
def ballot_approvaltext(request, name):
"""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"):
raise Http404
@ -816,7 +816,7 @@ def ballot_approvaltext(request, name):
@role_required('Secretariat')
def approve_ballot(request, name):
"""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"):
raise Http404
@ -947,7 +947,7 @@ class ApproveDownrefsForm(forms.Form):
@role_required('Secretariat')
def approve_downrefs(request, name):
"""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"):
raise Http404
@ -1001,7 +1001,7 @@ class MakeLastCallForm(forms.Form):
@role_required('Secretariat')
def make_last_call(request, name):
"""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")):
raise Http404
@ -1109,7 +1109,7 @@ def make_last_call(request, name):
@role_required('Secretariat', 'IRTF Chair')
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"):
raise Http404
@ -1164,7 +1164,7 @@ def issue_irsg_ballot(request, name):
@role_required('Secretariat', 'IRTF Chair')
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"):
raise Http404
@ -1205,7 +1205,7 @@ def irsg_ballot_status(request):
@role_required('Secretariat', 'RSAB Chair')
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"):
raise Http404
@ -1254,7 +1254,7 @@ def issue_rsab_ballot(request, name):
@role_required('Secretariat', 'RSAB Chair')
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":
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,
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)
from ietf.doc.utils import add_state_change_event
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])
bofreq.save_with_history([e1,e2])
alias = DocAlias.objects.create(name=name)
alias.docs.set([bofreq])
bofreq_submission = form.cleaned_data['bofreq_submission']
if bofreq_submission == "upload":
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
from ietf.doc.models import ( Document, DocAlias, DocHistory, State, DocEvent,
from ietf.doc.models import ( Document, DocHistory, State, DocEvent,
BallotDocEvent, BallotPositionDocEvent, InitialReviewDocEvent, NewRevisionDocEvent,
WriteupDocEvent, TelechatDocEvent )
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,
rev=next_rev,
)
DocAlias.objects.create(name=name).docs.add(charter)
charter.set_state(
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
from ietf.doc.models import ( BallotDocEvent, BallotPositionDocEvent, DocAlias, DocEvent,
from ietf.doc.models import ( BallotDocEvent, BallotPositionDocEvent, DocEvent,
Document, NewRevisionDocEvent, State )
from ietf.doc.utils import ( add_state_change_event, close_open_ballots,
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"])
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:
if self.cleaned_data['txt']:
destination.write(self.cleaned_data['txt'])
@ -185,7 +185,7 @@ def submit(request, name):
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)
if not_uploaded_yet:
@ -202,7 +202,7 @@ def submit(request, name):
events = []
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.save()
events.append(e)
@ -234,7 +234,7 @@ def submit(request, name):
dict(),
))
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:
with io.open(filename, 'r') as f:
init["content"] = f.read()
@ -276,7 +276,7 @@ def edit_ad(request, name):
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',
{'form': form,
'doc': review,
@ -449,9 +449,6 @@ def build_conflict_review_document(login, doc_to_review, ad, notify, create_in_s
)
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')
c = DocEvent(type="added_comment", doc=conflict_review, rev=conflict_review.rev, by=login)

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:
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
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:
css += Path(finders.find("ietf/css/document_html_txt.css")).read_text()
draft_that_became_rfc = None
became_rfc_alias = next(iter(doc.related_that("became_rfc")), None)
if became_rfc_alias:
draft_that_became_rfc = became_rfc_alias.document
became_rfc = next(iter(doc.related_that("became_rfc")), None)
if became_rfc:
draft_that_became_rfc = became_rfc
# submission
submission = ""
if group is None:
@ -796,7 +796,7 @@ def document_main(request, name, rev=None, document_html=False):
))
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)
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":
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)
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
basename = os.path.splitext(doc.uploaded_filename)[0]
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)
@ -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 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:
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(
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,
document_html=True,
)
@ -1124,7 +1124,7 @@ def get_doc_email_aliases(name):
return aliases
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)
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",
)
)
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")
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))
seen = set()
@ -1209,7 +1212,7 @@ def get_diff_revisions(request, name, doc):
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)
diff_revisions = get_diff_revisions(request, name, doc)
@ -1276,7 +1279,7 @@ def document_bibtex(request, name, rev=None):
name = name+"-"+rev
rev = None
doc = get_object_or_404(Document, docalias__name=name)
doc = get_object_or_404(Document, name=name)
doi = None
draft_became_rfc = None
@ -1285,7 +1288,7 @@ def document_bibtex(request, name, rev=None):
if doc.type_id == "draft":
latest_revision = doc.latest_event(NewRevisionDocEvent, type="new_revision")
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:
# find the entry in the history
@ -1294,13 +1297,9 @@ def document_bibtex(request, name, rev=None):
doc = h
break
if draft_became_rfc_alias:
draft_became_rfc = draft_became_rfc_alias.document
elif doc.type_id == "rfc":
# 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
# as a DocAlias, and use a method on Document to retrieve it.
# over time.
doi = f"10.17487/RFC{doc.rfc_number:04d}"
if doc.is_dochistory():
@ -1348,7 +1347,7 @@ def document_bibxml(request, name, rev=None):
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)
def text_from_writeup(event_type):
@ -1412,7 +1411,7 @@ def document_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")
if lastwriteup:
writeup_text = lastwriteup.text
@ -1449,12 +1448,12 @@ def document_shepherd_writeup_template(request, type):
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()
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):
doc = get_object_or_404(Document,docalias__name=name)
doc = get_object_or_404(Document,name=name)
refs = doc.referenced_by()
full = ( request.GET.get('full') != None )
numdocs = refs.count()
@ -1462,9 +1461,9 @@ def document_referenced_by(request, name):
refs=refs[:250]
else:
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",
dict(alias_name=name,
dict(name=name,
doc=doc,
numdocs=numdocs,
refs=refs,
@ -1538,7 +1537,7 @@ def document_ballot_content(request, doc, ballot_id, editable=True):
request=request)
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"))
if not ballot_id:
if all_ballots:
@ -1574,7 +1573,7 @@ def document_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)
if not ballot_id:
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):
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)
if not ballot_id:
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):
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)
ballot = get_object_or_404(BallotDocEvent,id=ballot_id)
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):
doc = get_object_or_404(Document, docalias__name=name)
doc = get_object_or_404(Document, name=name)
def extract_name(s):
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["title"] = doc.title
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["intended_std_level"] = extract_name(doc.intended_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')
def add_comment(request, name):
"""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
@ -1768,8 +1768,8 @@ def telechat_date(request, name):
def doc_titletext(doc):
if doc.type.slug=='conflrev':
conflictdoc = doc.relateddocument_set.get(relationship__slug='conflrev').target
return 'the conflict review of %s' % conflictdoc.canonical_name()
return doc.canonical_name()
return 'the conflict review of %s' % conflictdoc.name
return doc.name
def edit_notify(request, name):
@ -2008,7 +2008,7 @@ def remind_action_holders(request, name):
form = ReminderEmailForm(request.POST)
if form.is_valid():
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()
return render(
@ -2173,14 +2173,13 @@ def idnits2_rfc_status(request):
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"]:
raise Http404
zero_revision = None
if doc.type_id == "rfc":
draft_alias = next(iter(doc.related_that('became_rfc')), None)
if draft_alias:
draft = draft_alias.document
draft = next(iter(doc.related_that('became_rfc')), None)
if draft:
zero_revision = NewRevisionDocEvent.objects.filter(doc=draft,rev='00').first()
else:
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)')
tag = self.cleaned_data.get('substate','')
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")
# tag handling is a bit awkward since the UI still works
@ -86,7 +86,7 @@ class ChangeStateForm(forms.Form):
def change_state(request, name):
"""Change IESG state of Internet-Draft, notifying parties 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 (not doc.latest_event(type="started_iesg_process")) or doc.get_state_slug() == "expired":
raise Http404
@ -205,7 +205,7 @@ class AddIanaExpertsCommentForm(forms.Form):
@role_required('Secretariat', 'IANA')
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':
form = AddIanaExpertsCommentForm(request.POST)
if form.is_valid():
@ -231,7 +231,7 @@ class ChangeIanaStateForm(forms.Form):
def change_iana_state(request, name, state_type):
"""Change IANA review state of Internet-Draft. Normally, this is done via
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
@ -271,7 +271,7 @@ class ChangeStreamForm(forms.Form):
def change_stream(request, name):
"""Change the stream of a Document of type 'draft', notifying parties 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 not doc.type_id=='draft':
raise Http404
@ -352,7 +352,7 @@ class ReplacesForm(forms.Form):
def replaces(request, name):
"""Change 'replaces' set of a Document of type 'draft' , notifying parties
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':
raise Http404
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]
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':
raise Http404
if not (has_role(request.user, ("Secretariat", "Area Director"))
@ -451,7 +451,7 @@ class ChangeIntentionForm(forms.Form):
def change_intention(request, name):
"""Change the intended publication status of a Document of type 'draft' , notifying parties
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':
raise Http404
@ -520,7 +520,7 @@ class EditInfoForm(forms.Form):
def to_iesg(request,name):
""" 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' :
raise Http404
@ -633,7 +633,7 @@ def to_iesg(request,name):
def edit_info(request, name):
"""Edit various Internet-Draft attributes, notifying parties as
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":
raise Http404
@ -791,7 +791,7 @@ def edit_info(request, name):
@role_required('Area Director','Secretariat')
def request_resurrect(request, name):
"""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":
raise Http404
@ -814,7 +814,7 @@ def request_resurrect(request, name):
@role_required('Secretariat')
def resurrect(request, name):
"""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":
raise Http404

View file

@ -16,7 +16,7 @@ from django.urls import reverse as urlreverse
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.utils import add_state_change_event, check_common_doc_name_rules
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():
dest.write(chunk)
if action == "new":
alias, __ = DocAlias.objects.get_or_create(name=doc.name)
alias.docs.add(doc)
if prev_rev != doc.rev:
e = NewRevisionDocEvent(type="new_revision", doc=doc, rev=doc.rev)
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.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)
from ietf.name.models import (ReviewRequestStateName, ReviewAssignmentStateName, ReviewResultName,
ReviewTypeName)
@ -715,9 +715,7 @@ def complete_review(request, name, assignment_id=None, acronym=None):
name=review_name,
defaults={'type_id': 'review', 'group': team},
)
if created:
DocAlias.objects.create(name=review_name).docs.add(review)
else:
if not created:
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)
@ -1055,7 +1053,7 @@ class ReviewWishAddForm(forms.Form):
@login_required
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":
form = ReviewWishAddForm(request.user, doc, request.POST)
@ -1072,7 +1070,7 @@ def review_wish_add(request, name):
@login_required
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)
if request.method == "POST":

View file

@ -53,7 +53,7 @@ from django.utils.cache import _generate_cache_key # type: 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,
IESG_BALLOT_ACTIVE_STATES, IESG_STATCHG_CONFLREV_ACTIVE_STATES,
IESG_CHARTER_ACTIVE_STATES )
@ -166,7 +166,7 @@ def retrieve_search_results(form, all_types=False):
# 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()
# rfc/active/old check buttons
@ -248,17 +248,17 @@ def frontpage(request):
def search_for_name(request, name):
def find_unique(n):
exact = DocAlias.objects.filter(name__iexact=n).first()
exact = Document.objects.filter(name__iexact=n).first()
if exact:
return exact.name
aliases = DocAlias.objects.filter(name__istartswith=n)[:2]
if len(aliases) == 1:
return aliases[0].name
startswith = Document.objects.filter(name__istartswith=n)[:2]
if len(startswith) == 1:
return startswith[0].name
aliases = DocAlias.objects.filter(name__icontains=n)[:2]
if len(aliases) == 1:
return aliases[0].name
contains = Document.objects.filter(name__icontains=n)[:2]
if len(contains) == 1:
return contains[0].name
return None
@ -291,7 +291,7 @@ def search_for_name(request, name):
if redirect_to:
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
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 }))
else:
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:
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_to_skip = set()
for name, doc in draft_names:
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]
names = [
f'<a href=\"{urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=doc.name))}\">{doc.name}</a>'
for doc in drafts
]
categories.append((state,
heading,
@ -843,24 +832,11 @@ def index_all_drafts(request): # Should we rename this
))
# gather RFCs
rfc_names = DocAlias.objects.filter(docs__type_id="rfc").values_list("name", "docs__name")
names = []
names_to_skip = set()
for name, doc in rfc_names:
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]
rfcs = Document.objects.filter(type_id="rfc").order_by('-rfc_number')
names = [
f'<a href=\"{urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=rfc.name))}\">{rfc.name.upper()}</a>'
for rfc in rfcs
]
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)
return render(request, "doc/index_active_drafts.html", { 'groups': groups })
def ajax_select2_search_docs(request, model_name, doc_type):
if model_name == "docalias":
model = DocAlias
else:
model = Document
def ajax_select2_search_docs(request, model_name, doc_type): # TODO - remove model_name argument...
model = Document # Earlier versions allowed searching over DocAlias which no longer exists
q = [w.strip() for w in request.GET.get('q', '').split() if w.strip()]
if not q:
objs = model.objects.none()
else:
qs = model.objects.all()
if model == Document:
qs = qs.filter(type=doc_type)
elif model == DocAlias:
qs = qs.filter(docs__type=doc_type)
qs = model.objects.filter(type=doc_type)
for t in q:
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 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.ietfauth.utils import role_required
from ietf.utils.text import xslugify
@ -241,8 +241,6 @@ def new_statement(request):
desc="Statement published",
)
statement.save_with_history([e1, e2])
alias = DocAlias.objects.create(name=name)
alias.docs.set([statement])
markdown_content = ""
if statement_submission == "upload":
if not writing_pdf:

View file

@ -21,7 +21,7 @@ from django.utils.html import escape
import debug # pyflakes:ignore
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 )
from ietf.doc.forms import AdForm
from ietf.doc.lastcall import request_last_call
@ -99,7 +99,7 @@ def change_state(request, name, option=None):
)
related_doc_info = [
dict(title=rel_doc.target.title,
canonical_name=rel_doc.target.canonical_name(),
name=rel_doc.target.name,
newstatus=newstatus(rel_doc))
for rel_doc in related_docs
]
@ -148,7 +148,7 @@ class UploadForm(forms.Form):
return get_cleaned_text_file_content(self.cleaned_data["txt"])
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:
if self.cleaned_data['txt']:
destination.write(self.cleaned_data['txt'])
@ -162,7 +162,7 @@ def submit(request, name):
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)
if not_uploaded_yet:
@ -179,7 +179,7 @@ def submit(request, name):
events = []
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.save()
events.append(e)
@ -211,7 +211,7 @@ def submit(request, name):
dict(),
)
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:
with io.open(filename, 'r') as f:
init["content"] = f.read()
@ -253,7 +253,7 @@ def edit_title(request, name):
init = { "title" : status_change.title }
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',
{'form': form,
'doc': status_change,
@ -284,7 +284,7 @@ def edit_ad(request, name):
init = { "ad" : status_change.ad_id }
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',
{'form': form,
'doc': status_change,
@ -399,7 +399,7 @@ def approve(request, name):
init = []
for rel in status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS):
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)
for form in formset.forms:
@ -537,7 +537,7 @@ def start_rfc_status_change(request, name=None):
if name:
if not re.match("(?i)rfc[0-9]{1,4}",name):
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
@ -561,8 +561,6 @@ def start_rfc_status_change(request, name=None):
)
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']:
status_change.relateddocument_set.create(target=Document.objects.get(name=key),
relationship_id=form.cleaned_data['relations'][key])
@ -576,9 +574,9 @@ def start_rfc_status_change(request, name=None):
init = {}
if name:
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[seed_rfc.canonical_name()]=None
relations[seed_rfc.name]=None
init['relations'] = relations
form = StartStatusChangeForm(initial=init)
@ -604,7 +602,7 @@ def edit_relations(request, name):
old_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']
status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS).delete()
for key in new_relations:
@ -625,7 +623,7 @@ def edit_relations(request, name):
else:
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,
}
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.utils import reset_name_contains_index_for_rule
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.group.admin import GroupForm as AdminGroupForm
from ietf.group.factories import (GroupFactory, RoleFactory, GroupEventFactory,
@ -387,7 +387,6 @@ class GroupPagesTests(TestCase):
type_id="slides",
)
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'):
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.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.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
@ -186,17 +186,12 @@ def fill_in_wg_roles(group):
group.secretaries = get_roles("secr", [])
def fill_in_wg_drafts(group):
aliases = DocAlias.objects.filter(docs__type="draft", docs__group=group).prefetch_related('docs').order_by("name")
group.drafts = []
group.rfcs = []
for a in aliases:
if a.name.startswith("draft"):
group.drafts.append(a)
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()
group.drafts = Document.objects.filter(type_id="draft", group=group).order_by("name")
group.rfcs = Document.objects.filter(type_id="rfc", group=group).order_by("rfc_number")
for rfc in group.rfcs:
# TODO: remote_field?
rfc.remote_field = RelatedDocument.objects.filter(source=rfc,relationship_id__in=['obs','updates']).distinct()
rfc.invrel = RelatedDocument.objects.filter(target=rfc,relationship_id__in=['obs','updates']).distinct()
def check_group_email_aliases():
pattern = re.compile(r'expand-(.*?)(-\w+)@.*? +(.*)$')
@ -775,7 +770,7 @@ def dependencies(request, acronym, group_type=None):
graph = {
"nodes": [
{
"id": x.canonical_name(),
"id": x.name,
"rfc": x.get_state("draft").slug == "rfc",
"post-wg": not x.get_state("draft-iesg").slug
in ["idexists", "watching", "dead"],
@ -793,8 +788,8 @@ def dependencies(request, acronym, group_type=None):
],
"links": [
{
"source": x.source.canonical_name(),
"target": x.target.canonical_name(),
"source": x.source.name,
"target": x.target.name,
"rel": "downref" if x.is_downref() else x.relationship.slug,
}
for x in links

View file

@ -14,7 +14,7 @@ from django.utils import timezone
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 IESG_SUBSTATE_TAGS
from ietf.doc.templatetags.ietf_filters import clean_whitespace
@ -31,15 +31,18 @@ def all_id_txt():
t = revision_time.get(name)
return t.strftime("%Y-%m-%d") if t else ""
rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc",
docs__states=State.objects.get(type="draft", slug="rfc")).values_list("docs__name", "name"))
rfcs = dict()
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"),
relationship="replaces").values_list("target__name", "source__name"))
# 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"]
@ -77,9 +80,9 @@ def all_id_txt():
last_field = ""
if s.slug == "rfc":
a = rfc_aliases.get(name)
if a:
last_field = a[3:]
rfc = rfcs.get(name)
if rfc:
last_field = rfc[3:] # Rework this to take advantage of having the number at hand already.
elif s.slug == "repl":
state += " replaced by " + replacements.get(name, "0")
@ -108,12 +111,15 @@ def file_types_for_drafts():
def all_id2_txt():
# 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.prefetch_related("states")
rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc",
docs__states=State.objects.get(type="draft", slug="rfc")).values_list("docs__name", "name"))
rfcs = dict()
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"),
relationship="replaces").values_list("target__name", "source__name"))
@ -164,9 +170,9 @@ def all_id2_txt():
# 4
rfc_number = ""
if state == "rfc":
a = rfc_aliases.get(d.name)
if a:
rfc_number = a[3:]
rfc = rfcs.get(d.name)
if rfc:
rfc_number = rfc[3:]
fields.append(rfc_number)
# 5
repl = ""

View file

@ -11,8 +11,8 @@ from django.utils import timezone
import debug # pyflakes:ignore
from ietf.doc.factories import WgDraftFactory
from ietf.doc.models import Document, DocAlias, RelatedDocument, State, LastCallDocEvent, NewRevisionDocEvent
from ietf.doc.factories import WgDraftFactory, RfcFactory
from ietf.doc.models import Document, RelatedDocument, State, LastCallDocEvent, NewRevisionDocEvent
from ietf.group.factories import GroupFactory
from ietf.name.models import DocRelationshipName
from ietf.idindex.index import all_id_txt, all_id2_txt, id_index_txt
@ -41,7 +41,8 @@ class IndexTests(TestCase):
# published
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()
self.assertTrue(draft.name + "-" + draft.rev in txt)
@ -108,7 +109,8 @@ class IndexTests(TestCase):
# test 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())
self.assertEqual(t[4], "1234")

View file

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

View file

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

View file

@ -14,7 +14,7 @@ from django.utils.encoding import force_str
import debug # pyflakes:ignore
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.fields import SearchableIprDisclosuresField
from ietf.ipr.models import (IprDocRel, IprDisclosureBase, HolderIprDisclosure,
@ -95,7 +95,7 @@ class AddEmailForm(forms.Form):
return self.cleaned_data
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:
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.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.person.models import Person
from ietf.message.models import Message
@ -16,7 +16,7 @@ from ietf.utils.models import ForeignKey
class IprDisclosureBase(models.Model):
by = ForeignKey(Person) # who was logged in, or System if nobody was logged in
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)
notes = models.TextField("Additional notes", blank=True)
other_designations = models.CharField("Designations for other contributions", blank=True, max_length=255)
@ -160,7 +160,7 @@ class GenericIprDisclosure(IprDisclosureBase):
class IprDocRel(models.Model):
disclosure = ForeignKey(IprDisclosureBase)
document = ForeignKey(DocAlias)
document = ForeignKey(Document)
sections = models.TextField(blank=True)
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',
}
if self.type_id in event_type_map:
related_docs = set() # related docs, no duplicates
for alias in self.disclosure.docs.all():
related_docs.update(alias.docs.all())
for doc in related_docs:
for doc in self.disclosure.docs.distinct():
DocEvent.objects.create(
type=event_type_map[self.type_id],
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.name.resources import IprDisclosureStateNameResource
from ietf.doc.resources import DocAliasResource
from ietf.doc.resources import DocumentResource
class IprDisclosureBaseResource(ModelResource):
by = ToOneField(PersonResource, 'by')
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)
class Meta:
queryset = IprDisclosureBase.objects.all()
@ -45,10 +45,9 @@ class IprDisclosureBaseResource(ModelResource):
}
api.ipr.register(IprDisclosureBaseResource())
from ietf.doc.resources import DocAliasResource
class IprDocRelResource(ModelResource):
disclosure = ToOneField(IprDisclosureBaseResource, 'disclosure')
document = ToOneField(DocAliasResource, 'document')
document = ToOneField(DocumentResource, 'document')
class Meta:
cache = SimpleCache()
queryset = IprDocRel.objects.all()
@ -66,13 +65,12 @@ api.ipr.register(IprDocRelResource())
from ietf.person.resources import PersonResource
from ietf.name.resources import IprDisclosureStateNameResource, IprLicenseTypeNameResource
from ietf.doc.resources import DocAliasResource
class HolderIprDisclosureResource(ModelResource):
by = ToOneField(PersonResource, 'by')
state = ToOneField(IprDisclosureStateNameResource, 'state')
iprdisclosurebase_ptr = ToOneField(IprDisclosureBaseResource, 'iprdisclosurebase_ptr')
licensing = ToOneField(IprLicenseTypeNameResource, 'licensing')
docs = ToManyField(DocAliasResource, 'docs', null=True)
docs = ToManyField(DocumentResource, 'docs', null=True)
rel = ToManyField(IprDisclosureBaseResource, 'rel', null=True)
class Meta:
cache = SimpleCache()
@ -111,12 +109,11 @@ api.ipr.register(HolderIprDisclosureResource())
from ietf.person.resources import PersonResource
from ietf.name.resources import IprDisclosureStateNameResource
from ietf.doc.resources import DocAliasResource
class ThirdPartyIprDisclosureResource(ModelResource):
by = ToOneField(PersonResource, 'by')
state = ToOneField(IprDisclosureStateNameResource, 'state')
iprdisclosurebase_ptr = ToOneField(IprDisclosureBaseResource, 'iprdisclosurebase_ptr')
docs = ToManyField(DocAliasResource, 'docs', null=True)
docs = ToManyField(DocumentResource, 'docs', null=True)
rel = ToManyField(IprDisclosureBaseResource, 'rel', null=True)
class Meta:
cache = SimpleCache()
@ -168,12 +165,11 @@ api.ipr.register(RelatedIprResource())
from ietf.person.resources import PersonResource
from ietf.name.resources import IprDisclosureStateNameResource
from ietf.doc.resources import DocAliasResource
class NonDocSpecificIprDisclosureResource(ModelResource):
by = ToOneField(PersonResource, 'by')
state = ToOneField(IprDisclosureStateNameResource, 'state')
iprdisclosurebase_ptr = ToOneField(IprDisclosureBaseResource, 'iprdisclosurebase_ptr')
docs = ToManyField(DocAliasResource, 'docs', null=True)
docs = ToManyField(DocumentResource, 'docs', null=True)
rel = ToManyField(IprDisclosureBaseResource, 'rel', null=True)
class Meta:
cache = SimpleCache()
@ -207,12 +203,11 @@ api.ipr.register(NonDocSpecificIprDisclosureResource())
from ietf.person.resources import PersonResource
from ietf.name.resources import IprDisclosureStateNameResource
from ietf.doc.resources import DocAliasResource
class GenericIprDisclosureResource(ModelResource):
by = ToOneField(PersonResource, 'by')
state = ToOneField(IprDisclosureStateNameResource, 'state')
iprdisclosurebase_ptr = ToOneField(IprDisclosureBaseResource, 'iprdisclosurebase_ptr')
docs = ToManyField(DocAliasResource, 'docs', null=True)
docs = ToManyField(DocumentResource, 'docs', null=True)
rel = ToManyField(IprDisclosureBaseResource, 'rel', null=True)
class Meta:
cache = SimpleCache()

View file

@ -15,8 +15,7 @@ from django.utils import timezone
import debug # pyflakes:ignore
from ietf.doc.models import DocAlias
from ietf.doc.factories import DocumentFactory, WgDraftFactory, WgRfcFactory
from ietf.doc.factories import DocumentFactory, WgDraftFactory, WgRfcFactory, RfcFactory
from ietf.group.factories import RoleFactory
from ietf.ipr.factories import HolderIprDisclosureFactory, GenericIprDisclosureFactory, IprEventFactory
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.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
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.
"""
draft = WgDraftFactory()
WgRfcFactory()
rfc = WgRfcFactory()
url = urlreverse("ietf.ipr.views.new", kwargs={ "type": "specific" })
# successful post
@ -265,9 +265,9 @@ class IprTests(TestCase):
"ietfer_contact_info": "555-555-0101",
"iprdocrel_set-TOTAL_FORMS": 2,
"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-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
"iprdocrel_set-1-document": rfc.pk,
"patent_number": "SE12345678901",
"patent_inventor": "A. Nonymous",
"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.
"""
draft = WgDraftFactory()
WgRfcFactory()
rfc = WgRfcFactory()
url = urlreverse("ietf.ipr.views.new", kwargs={ "type": "third-party" })
# successful post
@ -321,9 +321,9 @@ class IprTests(TestCase):
"ietfer_contact_info": "555-555-0101",
"iprdocrel_set-TOTAL_FORMS": 2,
"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-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
"iprdocrel_set-1-document": rfc.pk,
"patent_number": "SE12345678901",
"patent_inventor": "A. Nonymous",
"patent_title": "A method of transferring bits",
@ -368,7 +368,7 @@ class IprTests(TestCase):
"holder_legal_name": "Test Legal",
"ietfer_contact_info": "555-555-0101",
"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-INITIAL_FORMS": 0,
"iprdocrel_set-TOTAL_FORMS": 1,
@ -396,7 +396,7 @@ class IprTests(TestCase):
def test_update(self):
draft = WgDraftFactory()
WgRfcFactory()
rfc = WgRfcFactory()
original_ipr = HolderIprDisclosureFactory(docs=[draft,])
# get
@ -417,9 +417,9 @@ class IprTests(TestCase):
"ietfer_contact_info": "555-555-0101",
"iprdocrel_set-TOTAL_FORMS": 2,
"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-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
"iprdocrel_set-1-document": rfc.pk,
"patent_number": "SE12345678901",
"patent_inventor": "A. Nonymous",
"patent_title": "A method of transferring bits",
@ -454,7 +454,7 @@ class IprTests(TestCase):
"holder_contact_email": "test@holder.com",
"iprdocrel_set-TOTAL_FORMS": 1,
"iprdocrel_set-INITIAL_FORMS": 0,
"iprdocrel_set-0-document": draft.docalias.first().pk,
"iprdocrel_set-0-document": draft.pk,
"iprdocrel_set-0-revisions": '00',
"patent_number": "SE12345678901",
"patent_inventor": "A. Nonymous",
@ -720,7 +720,7 @@ Subject: test
'iprdocrel_set-INITIAL_FORMS' : 0,
'iprdocrel_set-0-id': '',
"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,
'patent_number': patent_dict['Number'],
'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]+'...'
def iprs_from_docs(aliases,**kwargs):
"""Returns a list of IPRs related to doc aliases"""
def iprs_from_docs(docs,**kwargs):
"""Returns a list of IPRs related to docs"""
iprdocrels = []
for alias in aliases:
for document in alias.docs.all():
for document in docs:
if document.ipr(**kwargs):
iprdocrels += document.ipr(**kwargs)
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"""
results = [doc]
rels = list(doc.document.all_relations_that_doc(relationship))
rels = doc.all_relations_that_doc(relationship)
for rel in rels:
rel.target.related = rel
rel.target.relation = rel.relationship.revname
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))
@ -60,12 +65,11 @@ def generate_draft_recursive_txt():
docipr = {}
for o in IprDocRel.objects.filter(disclosure__state='posted').select_related('document'):
alias = o.document
name = alias.name
for document in alias.docs.all():
related = set(document.docalias.all()) | set(document.all_related_that_doc(('obs', 'replaces')))
for alias in related:
name = alias.name
doc = o.document
name = doc.name
related_set = set(doc) | set(doc.all_related_that_doc(('obs', 'replaces')))
for related in related_set:
name = related.name
if name.startswith("rfc"):
name = name.upper()
if not name in docipr:

View file

@ -18,7 +18,7 @@ from django.utils.html import escape
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.ietfauth.utils import role_required, has_role
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.name.models import IprLicenseTypeName
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.mail import send_mail, send_mail_message
from ietf.utils.response import permission_denied
@ -69,12 +69,15 @@ def get_document_emails(ipr):
has been posted"""
messages = []
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)
elif doc.type_id=="rfc":
doc_info = 'RFC entitled "{}" (RFC{})'.format(doc.title, doc.rfc_number)
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)
@ -663,18 +666,18 @@ def search(request):
doc = q
if docid:
start = DocAlias.objects.filter(name__iexact=docid)
start = Document.objects.filter(name__iexact=docid)
else:
if search_type == "draft":
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":
start = DocAlias.objects.filter(name="rfc%s" % q.lstrip("0"))
start = Document.objects.filter(name="rfc%s" % q.lstrip("0"))
# one match
if len(start) == 1:
first = start[0]
doc = first.document
doc = first
docs = related_docs(first)
iprs = iprs_from_docs(docs,states=states)
template = "ipr/search_doc_result.html"
@ -706,27 +709,27 @@ def search(request):
# Search by wg acronym
# Document list with IPRs
elif search_type == "group":
docs = list(DocAlias.objects.filter(docs__group=q))
docs = list(Document.objects.filter(group=q))
related = []
for doc in docs:
doc.product_of_this_wg = True
related += related_docs(doc)
iprs = iprs_from_docs(list(set(docs+related)),states=states)
docs = [ doc for doc in docs if doc.document.ipr() ]
docs = sorted(docs, key=lambda x: max([ipr.disclosure.time for ipr in x.document.ipr()]), reverse=True)
docs = [ doc for doc in docs if doc.ipr() ]
docs = sorted(docs, key=lambda x: max([ipr.disclosure.time for ipr in x.ipr()]), reverse=True)
template = "ipr/search_wg_result.html"
q = Group.objects.get(id=q).acronym # make acronym for use in template
# Search by rfc and id title
# Document list with IPRs
elif search_type == "doctitle":
docs = list(DocAlias.objects.filter(docs__title__icontains=q))
docs = list(Document.objects.filter(title__icontains=q))
related = []
for doc in docs:
related += related_docs(doc)
iprs = iprs_from_docs(list(set(docs+related)),states=states)
docs = [ doc for doc in docs if doc.document.ipr() ]
docs = sorted(docs, key=lambda x: max([ipr.disclosure.time for ipr in x.document.ipr()]), reverse=True)
docs = [ doc for doc in docs if doc.ipr() ]
docs = sorted(docs, key=lambda x: max([ipr.disclosure.time for ipr in x.ipr()]), reverse=True)
template = "ipr/search_doctitle_result.html"
# 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.person.models import Email
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.timezone import date_today, datetime_from_date, DEADLINE_TZINFO
from functools import reduce
@ -375,8 +375,6 @@ class LiaisonModelForm(forms.ModelForm):
uploaded_filename = name + extension,
)
)
if created:
DocAlias.objects.create(name=attach.name).docs.add(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.write(attached_file.read())

View file

@ -19,7 +19,7 @@ from django.utils.functional import cached_property
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.utils import groups_managed_by
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?
uploaded_filename='{}-00.txt'.format(filename))
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)
NewRevisionDocEvent.objects.create(
type='new_revision',

View file

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

View file

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

View file

@ -47,7 +47,7 @@ from django.views.generic import RedirectView
import debug # pyflakes:ignore
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.utils import can_manage_session_materials, can_manage_some_groups, can_manage_group
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):
meeting=get_meeting(num,type_in=['ietf','interim'])
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:
doc, rev = _get_materials_doc(meeting=meeting, name=document)
except Document.DoesNotExist:
@ -2585,7 +2584,6 @@ def save_bluesheet(request, session, file, encoding='utf-8'):
rev = '00',
)
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')
filename = '%s-%s%s'% ( doc.name, doc.rev, ext)
doc.uploaded_filename = filename
@ -2714,7 +2712,6 @@ def upload_session_agenda(request, session_id, num):
group = session.group,
rev = '00',
)
DocAlias.objects.create(name=doc.name).docs.add(doc)
doc.states.add(State.objects.get(type_id='agenda',slug='active'))
if session.sessionpresentation_set.filter(document=doc).exists():
sp = session.sessionpresentation_set.get(document=doc)
@ -2807,7 +2804,6 @@ def upload_session_slides(request, session_id, num, name=None):
group = session.group,
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='reuse_policy',slug='single'))
if session.sessionpresentation_set.filter(document=doc).exists():
@ -4525,7 +4521,6 @@ def approve_proposed_slides(request, slidesubmission_id, num):
group = submission.session.group,
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='reuse_policy',slug='single'))
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
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.meeting.forms import FileUploadForm
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
# 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 not created:
doc.rev = '{:02}'.format(int(doc.rev) + 1)

View file

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

View file

@ -191,7 +191,7 @@ class Person(models.Model):
def rfcs(self):
from ietf.doc.models import Document
rfcs = list(Document.objects.filter(documentauthor__person=self, type='draft', states__slug='rfc'))
rfcs.sort(key=lambda d: d.canonical_name() )
rfcs.sort(key=lambda d: d.name )
return rfcs
def active_drafts(self):

View file

@ -7,7 +7,7 @@ from django.db.models.aggregates import Max
from django.utils import timezone
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.group.models import Role
from ietf.person.models import Person
@ -287,8 +287,6 @@ class AssignmentOrderResolver:
def _collect_context(self):
"""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.
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)
@ -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.connections,
self.connections.get(email.person_id)) # reviewer is somehow connected: bad
add_boolean_score(-1, settings.filter_re and any(
re.search(settings.filter_re, n) for n in self.doc_aliases), "filter regexp matches")
add_boolean_score(-1, settings.filter_re and re.search(settings.filter_re, self.doc.name), "filter regexp matches")
# minimum interval between reviews
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
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):
messages.warning(request, 'Dcoument: {name} is not on the Telechat agenda for {date}'.format(
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
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)
target = name

View file

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

View file

@ -13,15 +13,6 @@ def get_full_path(doc):
return None
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):
'''

View file

@ -600,7 +600,6 @@ TEST_CODE_COVERAGE_EXCLUDE_FILES = [
"ietf/utils/test_runner.py",
"ietf/name/generate_fixtures.py",
"ietf/review/import_from_review_tool.py",
"ietf/stats/backfill_data.py",
"ietf/utils/patch.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.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):
"""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.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.meeting.factories import MeetingFactory, AttendedFactory
from ietf.person.factories import PersonFactory
@ -79,7 +79,6 @@ class StatisticsTests(TestCase):
words=100
)
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(
source=referencing_draft,
target=draft,

View file

@ -34,7 +34,7 @@ from ietf.group.models import Role, Group
from ietf.person.models import Person
from ietf.name.models import ReviewResultName, CountryName, DocRelationshipName, ReviewAssignmentStateName
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.stats.models import MeetingRegistration, CountryAlias
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):
# 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")
if document_type == "rfc":
docalias_filters &= Q(docs__states=rfc_state)
document_filters &= Q(states=rfc_state)
elif document_type == "draft":
docalias_filters &= ~Q(docs__states=rfc_state)
document_filters &= ~Q(states=rfc_state)
if from_time:
# this is actually faster than joining in the database,
@ -229,11 +229,11 @@ def document_stats(request, stats_type=None):
type="draft",
docevent__time__gte=from_time,
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":
doc_label = "RFC"
@ -242,28 +242,15 @@ def document_stats(request, stats_type=None):
else:
doc_label = "document"
total_docs = docalias_qs.values_list("docs__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
total_docs = document_qs.values_list("name").distinct().count()
if stats_type == "authors":
stats_title = "Number of authors for each {}".format(doc_label)
bins = defaultdict(set)
for name, canonical_name, author_count in generate_canonical_names(docalias_qs.values_list("docs__name", "name").annotate(Count("docs__documentauthor"))):
bins[author_count or 0].add(canonical_name)
for name, author_count in document_qs.values_list("name").annotate(Count("documentauthor")).values_list("name","documentauthor__count"):
bins[author_count or 0].add(name)
series_data = []
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)
for name, canonical_name, pages in generate_canonical_names(docalias_qs.values_list("docs__name", "name", "docs__pages")):
bins[pages or 0].add(canonical_name)
for name, pages in document_qs.values_list("name", "pages"):
bins[pages or 0].add(name)
series_data = []
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)
for name, canonical_name, words in generate_canonical_names(docalias_qs.values_list("docs__name", "name", "docs__words")):
bins[put_into_bin(words, bin_size)].add(canonical_name)
for name, words in document_qs.values_list("name", "words"):
bins[put_into_bin(words, bin_size)].add(name)
series_data = []
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
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)
if types:
for dot_ext in types.split(","):
bins[dot_ext.lstrip(".").upper()].add(canonical_name)
bins[dot_ext.lstrip(".").upper()].add(doc_name)
else:
if canonical_name.startswith("rfc"):
filename = canonical_name
if doc_type == "rfc":
filename = doc_name
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
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):
continue
canonical_name = doc_names_with_missing_types.get(basename)
name = doc_names_with_missing_types.get(basename)
if canonical_name:
bins[ext.upper()].add(canonical_name)
if name:
bins[ext.upper()].add(name)
series_data = []
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)
for name, canonical_name, formal_language_name in generate_canonical_names(docalias_qs.values_list("docs__name", "name", "docs__formal_languages__name")):
bins[formal_language_name or ""].add(canonical_name)
for name, formal_language_name in document_qs.values_list("name", "formal_languages__name"):
bins[formal_language_name or ""].add(name)
series_data = []
for formal_language, names in sorted(bins.items(), key=lambda t: t[0]):

View file

@ -108,14 +108,14 @@ class Submission(models.Model):
@property
def active_wg_drafts_replaced(self):
return Document.objects.filter(
docalias__name__in=self.replaces.split(','),
name__in=self.replaces.split(','),
group__in=Group.objects.active_wgs()
)
@property
def closed_wg_drafts_replaced(self):
return Document.objects.filter(
docalias__name__in=self.replaces.split(','),
name__in=self.replaces.split(','),
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)
from ietf.doc.factories import (DocumentFactory, WgDraftFactory, IndividualDraftFactory,
ReviewFactory, WgRfcFactory)
from ietf.doc.models import ( Document, DocAlias, DocEvent, State,
from ietf.doc.models import ( Document, DocEvent, State,
BallotPositionDocEvent, DocumentAuthor, SubmissionDocEvent )
from ietf.doc.utils import create_ballot_if_not_open, can_edit_docextresources, update_action_holders
from ietf.group.factories import GroupFactory, RoleFactory
@ -358,8 +358,6 @@ class SubmitTests(BaseSubmitTestCase):
note="",
)
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"
rev = "00"
@ -400,7 +398,7 @@ class SubmitTests(BaseSubmitTestCase):
r = self.client.post(status_url, dict(action=action))
self.assertEqual(r.status_code, 302)
draft = Document.objects.get(docalias__name=name)
draft = Document.objects.get(name=name)
self.assertEqual(draft.rev, rev)
new_revision = draft.latest_event(type="new_revision")
self.assertEqual(draft.group.acronym, "mars")
@ -420,7 +418,7 @@ class SubmitTests(BaseSubmitTestCase):
self.assertEqual(draft.relations_that_doc("replaces").count(), 1)
self.assertTrue(draft.relations_that_doc("replaces").first().target, draft)
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.assertIn(("I-D Action: %s" % name), outbox[-4]["Subject"])
self.assertIn(author.ascii, get_payload_text(outbox[-4]))
@ -433,7 +431,7 @@ class SubmitTests(BaseSubmitTestCase):
# Check "Review of suggested possible replacements for..." mail
self.assertIn("review", outbox[-1]["Subject"].lower())
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("mars-chairs@", outbox[-1]["To"].lower())
# Check submission settings
@ -684,7 +682,7 @@ class SubmitTests(BaseSubmitTestCase):
self.assertTrue('New version approved' 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.group.acronym, name.split("-")[2])
#
@ -911,7 +909,7 @@ class SubmitTests(BaseSubmitTestCase):
r = self.client.post(confirmation_url, {'action':'confirm'})
self.assertEqual(r.status_code, 302)
draft = Document.objects.get(docalias__name=name)
draft = Document.objects.get(name=name)
self.assertEqual(draft.rev, rev)
new_revision = draft.latest_event()
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()
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)
docauth = doc.documentauthor_set.first()
self.assertEqual(docauth.person, author)
@ -1084,7 +1082,7 @@ class SubmitTests(BaseSubmitTestCase):
self.assertIn("New Version Notification", notification_email["Subject"])
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.docextresource_set.count(), 0)
new_revision = draft.latest_event()
@ -1132,7 +1130,7 @@ class SubmitTests(BaseSubmitTestCase):
self._assert_extresources_form_not_present(r)
# Check that the draft itself got the resources
draft = Document.objects.get(docalias__name=name)
draft = Document.objects.get(name=name)
self.assertCountEqual(
[str(r) for r in draft.docextresource_set.all()],
[str(r) for r in resources],
@ -1178,7 +1176,7 @@ class SubmitTests(BaseSubmitTestCase):
r = self.client.post(confirmation_url, {'action':'confirm'})
self.assertEqual(r.status_code, 302)
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.relateddocument_set.filter(relationship_id='replaces').count(), replaces_count)
self.assertEqual(draft.docextresource_set.count(), 0)
@ -1296,7 +1294,7 @@ class SubmitTests(BaseSubmitTestCase):
r = self.client.post(confirmation_url, {'action':'cancel'})
self.assertEqual(r.status_code, 302)
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)
def test_submit_new_wg_with_dash(self):
@ -1453,7 +1451,7 @@ class SubmitTests(BaseSubmitTestCase):
r = self.client.post(status_url, dict(action=action))
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.docextresource_set.count(), 0)
self.verify_bibxml_ids_creation(draft)

View file

@ -25,7 +25,7 @@ from django.utils import timezone
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 )
from ietf.doc.models import NewRevisionDocEvent
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)
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"))
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",
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 (
', '.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
from ietf.doc.models import Document, DocAlias, AddedMessageEvent
from ietf.doc.models import Document, AddedMessageEvent
from ietf.doc.forms import ExtResourceForm
from ietf.group.models import Group
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")
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(
initial=dict(resources=[er['res'] for er in external_resources]),
extresource_model=SubmissionExtResource,
@ -626,7 +626,7 @@ def edit_submission(request, submission_id, access_token=None):
else:
edit_form = EditSubmissionForm(instance=submission, prefix="edit")
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)
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 = []
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(
# 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
@ -189,7 +189,7 @@ def update_history_with_changes(changes, send_email=True):
state_type=state_type, state=state)
if not e:
try:
doc = Document.objects.get(docalias__name=docname)
doc = Document.objects.get(name=docname)
except Document.DoesNotExist:
warnings.append("Document %s not found" % docname)
continue

View file

@ -17,7 +17,7 @@ from django.utils.encoding import smart_bytes, force_str
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 )
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
@ -156,7 +156,7 @@ def update_drafts_from_queue(drafts):
names = [t[0] for t in drafts]
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()
@ -229,7 +229,7 @@ def update_drafts_from_queue(drafts):
# 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.unset_state("draft-rfceditor")
# 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:
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)
if draft:
doc.formal_languages.set(draft.formal_languages.all())
@ -654,12 +650,15 @@ def update_docs_from_rfc_index(
)
)
if also:
for a in also:
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)}")
# This block attempted to alias subseries names to RFCs.
# Handle that differently when we add subseries as a document type.
#
# if also:
# for a in also:
# 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}", [])
all_rejected = doc_errata and all(

View file

@ -16,7 +16,7 @@ from django.utils import timezone
import debug # pyflakes:ignore
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.group.factories import GroupFactory
from ietf.person.models import Person
@ -30,19 +30,20 @@ from ietf.utils.timezone import date_today, RPC_TZINFO
class IANASyncTests(TestCase):
def test_protocol_page_sync(self):
draft = WgDraftFactory()
DocAlias.objects.create(name="rfc1234").docs.add(draft)
DocEvent.objects.create(doc=draft, rev=draft.rev, type="published_rfc", by=Person.objects.get(name="(System)"))
rfc = RfcFactory(rfc_number=1234)
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>')
self.assertEqual(len(rfc_names), 1)
self.assertEqual(rfc_names[0], "rfc1234")
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
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):
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)
self.assertTrue("errata" in tag_slugs)
self.assertFalse("verified-errata" in tag_slugs)
self.assertTrue(DocAlias.objects.filter(name="rfc1234", docs=rfc_doc))
self.assertTrue(DocAlias.objects.filter(name="bcp1", docs=rfc_doc))
self.assertTrue(DocAlias.objects.filter(name="fyi1", docs=rfc_doc))
self.assertTrue(DocAlias.objects.filter(name="std1", docs=rfc_doc))
# TODO: adjust these when we have subseries document types
# self.assertTrue(DocAlias.objects.filter(name="rfc1234", docs=rfc_doc))
# self.assertTrue(DocAlias.objects.filter(name="bcp1", 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=draft_doc, target=rfc_doc, relationship="became_rfc").exists())
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">
<input class="form-control select2-field search-select"
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"
data-placeholder="Document search">
</label>

View file

@ -29,7 +29,7 @@
href="{% url 'ietf.doc.views_ballot.approve_ballot' name=doc.name %}">Approve ballot</a>
{% endif %}
<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
</a>
</form>

View file

@ -21,7 +21,7 @@
<button class="btn btn-primary" type="submit">Email RFC Editor (DNP) &amp; close ballot"</button>
{% endif %}
<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
</a>
</form>

View file

@ -12,16 +12,16 @@
</h1>
<p>
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.
</p>
{% if not downrefs_to_rfc %}
<p>
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>
<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 %}
<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.
@ -41,7 +41,7 @@
{% csrf_token %}
{% bootstrap_form approve_downrefs_form %}
<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
</a>
<button type="submit" class="btn btn-warning" value="Save checked downrefs">Add checked DOWNREF entries</button>

View file

@ -11,7 +11,7 @@
</h1>
<p>
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.
</p>
{% if doc.telechat_date %}
@ -24,5 +24,5 @@
</p>
{% endif %}
<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 %}

View file

@ -14,14 +14,14 @@
{% csrf_token %}
<p class="alert alert-danger my-3">
<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>
<br>
This will clear all ballot positions and discuss entries.
</p>
<button type="submit" class="btn btn-danger">Clear</button>
<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
</a>
</form>

View file

@ -14,14 +14,14 @@
{% csrf_token %}
<p class="alert alert-danger my-3">
<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>
<br>
The ballot will then be put on the IESG agenda of {{ telechat_date }}.
</p>
<button type="submit" class="btn btn-danger">Defer ballot</button>
<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
</a>
</form>

View file

@ -54,7 +54,7 @@
{% endif %}
{% endif %}
<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
</a>
</div>

View file

@ -39,7 +39,7 @@
href="{% url 'ietf.doc.views_ballot.make_last_call' name=doc.name %}">Issue last call</a>
{% endif %}
<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
</a>
</form>

View file

@ -31,7 +31,7 @@
Clear
</button>
<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
</a>
</form>

View file

@ -37,7 +37,7 @@
</div>
<button type="submit" class="btn btn-danger">Send</button>
<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
</a>
</form>

View file

@ -19,7 +19,7 @@
</p>
<button class="btn btn-danger" type="submit">Undefer ballot</button>
<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
</a>
</form>

View file

@ -32,7 +32,7 @@
Save &amp; {% if ballot_issued %}re-{% endif %}issue ballot
</button>
<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
</a>
</form>

View file

@ -16,7 +16,7 @@
{% bootstrap_form form %}
<button type="submit" class="btn btn-primary">Submit</button>
<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
</a>
</form>

View file

@ -16,7 +16,7 @@
{% bootstrap_form form %}
<button type="submit" class="btn btn-primary">Submit</button>
<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
</a>
</form>

View file

@ -15,7 +15,7 @@
{% bootstrap_form form %}
<button type="submit" class="btn btn-primary">Submit</button>
<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
</a>
</form>

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