Merged django-1.8 work forward to copy of 6.39.1

- Legacy-Id: 12504
This commit is contained in:
Henrik Levkowetz 2016-12-10 19:32:46 +00:00
commit 03d90163a5
36 changed files with 421 additions and 517 deletions

1
env/.gitignore vendored
View file

@ -5,3 +5,4 @@
/local
/lib
/include
/pip-selfcheck.json

View file

@ -4,7 +4,7 @@ from docutils.core import publish_string
from docutils.utils import SystemMessage
import debug # pyflakes:ignore
from django.template import Template as DjangoTemplate, TemplateDoesNotExist, TemplateEncodingError
from django.template.base import Template as DjangoTemplate, TemplateDoesNotExist, TemplateEncodingError
from django.template.loader import BaseLoader
from django.utils.encoding import smart_unicode

View file

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('doc', '0016_auto_20160927_0713'),
]
operations = [
migrations.AlterField(
model_name='docevent',
name='type',
field=models.CharField(max_length=50, choices=[(b'new_revision', b'Added new revision'), (b'new_submission', b'Uploaded new revision'), (b'changed_document', b'Changed document metadata'), (b'added_comment', b'Added comment'), (b'added_message', b'Added message'), (b'deleted', b'Deleted document'), (b'changed_state', b'Changed state'), (b'changed_stream', b'Changed document stream'), (b'expired_document', b'Expired document'), (b'extended_expiry', b'Extended expiry of document'), (b'requested_resurrect', b'Requested resurrect'), (b'completed_resurrect', b'Completed resurrect'), (b'changed_consensus', b'Changed consensus'), (b'published_rfc', b'Published RFC'), (b'added_suggested_replaces', b'Added suggested replacement relationships'), (b'reviewed_suggested_replaces', b'Reviewed suggested replacement relationships'), (b'changed_group', b'Changed group'), (b'changed_protocol_writeup', b'Changed protocol writeup'), (b'changed_charter_milestone', b'Changed charter milestone'), (b'initial_review', b'Set initial review time'), (b'changed_review_announcement', b'Changed WG Review text'), (b'changed_action_announcement', b'Changed WG Action text'), (b'started_iesg_process', b'Started IESG process on document'), (b'created_ballot', b'Created ballot'), (b'closed_ballot', b'Closed ballot'), (b'sent_ballot_announcement', b'Sent ballot announcement'), (b'changed_ballot_position', b'Changed ballot position'), (b'changed_ballot_approval_text', b'Changed ballot approval text'), (b'changed_ballot_writeup_text', b'Changed ballot writeup text'), (b'changed_rfc_editor_note_text', b'Changed RFC Editor Note text'), (b'changed_last_call_text', b'Changed last call text'), (b'requested_last_call', b'Requested last call'), (b'sent_last_call', b'Sent last call'), (b'scheduled_for_telechat', b'Scheduled for telechat'), (b'iesg_approved', b'IESG approved document (no problem)'), (b'iesg_disapproved', b'IESG disapproved document (do not publish)'), (b'approved_in_minute', b'Approved in minute'), (b'iana_review', b'IANA review comment'), (b'rfc_in_iana_registry', b'RFC is in IANA registry'), (b'rfc_editor_received_announcement', b'Announcement was received by RFC Editor'), (b'requested_publication', b'Publication at RFC Editor requested'), (b'sync_from_rfc_editor', b'Received updated information from RFC Editor'), (b'requested_review', b'Requested review'), (b'assigned_review_request', b'Assigned review request'), (b'closed_review_request', b'Closed review request')]),
),
migrations.AlterField(
model_name='dochistory',
name='tags',
field=models.ManyToManyField(to='name.DocTagName', blank=True),
),
migrations.AlterField(
model_name='document',
name='tags',
field=models.ManyToManyField(to='name.DocTagName', blank=True),
),
]

View file

@ -3,6 +3,7 @@
import datetime, os
from django.db import models
from django.core import checks
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse as urlreverse
from django.core.validators import URLValidator
@ -26,6 +27,20 @@ class StateType(models.Model):
def __unicode__(self):
return self.slug
@checks.register('db-consistency')
def check_statetype_slugs(app_configs, **kwargs):
errors = []
state_type_slugs = [ t.slug for t in StateType.objects.all() ]
for type in DocTypeName.objects.all():
if not type.slug in state_type_slugs:
errors.append(checks.Error(
"The document type '%s (%s)' does not have a corresponding entry in the doc.StateType table" % (type.name, type.slug),
hint="You should add a doc.StateType entry with a slug '%s' to match the DocTypeName slug."%(type.slug),
obj=type,
id='datatracker.doc.E0015',
))
return errors
class State(models.Model):
type = models.ForeignKey(StateType)
slug = models.SlugField()
@ -53,7 +68,7 @@ class DocumentInfo(models.Model):
title = models.CharField(max_length=255)
states = models.ManyToManyField(State, blank=True) # plain state (Active/Expired/...), IESG state, stream state
tags = models.ManyToManyField(DocTagName, blank=True, null=True) # Revised ID Needed, ExternalParty, AD Followup, ...
tags = models.ManyToManyField(DocTagName, blank=True) # Revised ID Needed, ExternalParty, AD Followup, ...
stream = models.ForeignKey(StreamName, blank=True, null=True) # IETF, IAB, IRTF, Independent Submission
group = models.ForeignKey(Group, blank=True, null=True) # WG, RG, IAB, IESG, Edu, Tools
@ -277,7 +292,7 @@ class DocumentInfo(models.Model):
if isinstance(self, Document):
return RelatedDocument.objects.filter(target__document=self, relationship__in=relationship).select_related('source')
elif isinstance(self, DocHistory):
return RelatedDocHistory.objects.filter(target__document=self, relationship__in=relationship).select_related('source')
return RelatedDocHistory.objects.filter(target__document=self.doc, relationship__in=relationship).select_related('source')
else:
return RelatedDocument.objects.none()

View file

@ -13,7 +13,7 @@ from ietf.doc.utils import get_document_content
from ietf.utils.text import fill
from django import template
from django.conf import settings
from django.utils.html import escape, fix_ampersands
from django.utils.html import escape
from django.template.defaultfilters import truncatewords_html, linebreaksbr, stringfilter, striptags, urlize
from django.template import resolve_variable
from django.utils.safestring import mark_safe, SafeData
@ -69,7 +69,7 @@ def parse_email_list(value):
(name, email) = parseaddr(addr)
if not(name):
name = email
ret.append('<a href="mailto:%s">%s</a>' % ( fix_ampersands(email), escape(name) ))
ret.append('<a href="mailto:%s">%s</a>' % ( email.replace('&', '&amp;'), escape(name) ))
return mark_safe(", ".join(ret))
else:
return value

View file

@ -12,7 +12,7 @@ def fill_in_document_table_attributes(docs):
docs_dict = dict((d.pk, d) for d in docs)
doc_ids = docs_dict.keys()
rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=doc_ids).values_list("document_id", "name"))
rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=doc_ids).values_list("document", "name"))
# latest event cache
event_types = ("published_rfc",
@ -79,9 +79,9 @@ def fill_in_document_table_attributes(docs):
d.updated_by_list = []
xed_by = RelatedDocument.objects.filter(target__name__in=rfc_aliases.values(),
relationship__in=("obs", "updates")).select_related('target__document_id')
relationship__in=("obs", "updates")).select_related('target__document')
rel_rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc",
document__in=[rel.source_id for rel in xed_by]).values_list('document_id', 'name'))
document__in=[rel.source_id for rel in xed_by]).values_list('document', 'name'))
for rel in xed_by:
d = docs_dict[rel.target.document_id]
if rel.relationship_id == "obs":
@ -101,7 +101,7 @@ def prepare_document_table(request, docs, query=None, max_results=500):
if not isinstance(docs, list):
# evaluate and fill in attribute results immediately to decrease
# the number of queries
docs = docs.select_related("ad", "ad__person", "std_level", "intended_std_level", "group", "stream")
docs = docs.select_related("ad", "std_level", "intended_std_level", "group", "stream")
docs = docs.prefetch_related("states__type", "tags", "groupmilestone_set__group", "reviewrequest_set__team")
docs = list(docs[:max_results])

View file

@ -38,7 +38,7 @@ class UploadMaterialForm(forms.Form):
def __init__(self, doc_type, action, group, doc, *args, **kwargs):
super(UploadMaterialForm, self).__init__(*args, **kwargs)
self.fields["state"].queryset = self.fields["state"].queryset.filter(type=doc_type)
self.fields["state"].queryset = self.fields["state"].queryset.filter(type__slug=doc_type.slug)
self.doc_type = doc_type
self.action = action

View file

@ -36,7 +36,7 @@ def model_to_timeline_data(model, field='time', **kwargs):
a JsonResponse() argument. The model must have a DateTimeField field.
If the time field is named something else than 'time', the name must
be supplied."""
assert field in model._meta.get_all_field_names()
assert field in [ f.name for f in model._meta.get_fields() ]
objects = ( model.objects.filter(**kwargs)
.order_by('date')

View file

@ -101,7 +101,7 @@ 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 = drafts.select_related('group', 'group__parent', 'ad', 'ad__email', 'intended_std_level', 'shepherd', 'shepherd__email')
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",

View file

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ipr', '0008_auto_20160720_0218'),
]
operations = [
migrations.AlterField(
model_name='genericiprdisclosure',
name='holder_contact_email',
field=models.EmailField(max_length=254),
),
migrations.AlterField(
model_name='holderiprdisclosure',
name='holder_contact_email',
field=models.EmailField(max_length=254),
),
migrations.AlterField(
model_name='holderiprdisclosure',
name='ietfer_contact_email',
field=models.EmailField(max_length=254, blank=True),
),
migrations.AlterField(
model_name='iprdisclosurebase',
name='submitter_email',
field=models.EmailField(max_length=254, blank=True),
),
migrations.AlterField(
model_name='nondocspecificiprdisclosure',
name='holder_contact_email',
field=models.EmailField(max_length=254),
),
migrations.AlterField(
model_name='thirdpartyiprdisclosure',
name='ietfer_contact_email',
field=models.EmailField(max_length=254),
),
]

View file

@ -1,227 +0,0 @@
class LegacyRouter(object):
def db_for_read(self, model, **hints):
if model._meta.db_table in legacy_tables:
return 'legacy'
return None
def db_for_write(self, model, **hints):
if model._meta.db_table in legacy_tables:
raise Exception("You can't write to the legacy table %s" % model._meta.db_table)
return None
def allow_relation(self, obj1, obj2, **hints):
if (obj1._meta.db_table in legacy_tables) != (obj2._meta.db_table in legacy_tables):
return False
return None
def allow_syncdb(self, db, model):
if db == 'legacy':
return False
if model._meta.db_table in legacy_tables:
return False
return None
legacy_tables = set((
"acronym",
"agenda_cat",
"agenda_items",
"all_id",
"announced_from",
"announced_to",
"announcements",
"area_directors",
"area_group",
"area_status",
"areas",
"ballot_info",
"ballots",
"ballots_comment",
"ballots_discuss",
"bash_agenda",
"chairs",
"chairs_history",
"document_comments",
"draft_versions_mirror",
"dt_request",
"email_addresses",
"from_bodies",
"g_chairs",
"g_editors",
"g_secretaries",
"g_secretary",
"g_status",
"g_tech_advisors",
"g_type",
"general_info",
"goals_milestones",
"group_flag",
"group_internal",
"groups_ietf",
"hit_counter",
"id_approved_detail",
"id_authors",
"id_dates",
"id_intended_status",
"id_internal",
"id_restricted_word",
"id_status",
"id_submission_detail",
"id_submission_env",
"id_submission_status",
"idst_users",
"iesg_history",
"iesg_login",
"iesg_password",
"ietfauth_ietfuserprofile",
"ietfauth_usermap",
"ietfworkflows_annotationtag",
"ietfworkflows_annotationtagobjectrelation",
"ietfworkflows_objectannotationtaghistoryentry",
"ietfworkflows_objecthistoryentry",
"ietfworkflows_objectstreamhistoryentry",
"ietfworkflows_objectworkflowhistoryentry",
"ietfworkflows_statedescription",
"ietfworkflows_stateobjectrelationmetadata",
"ietfworkflows_stream",
"ietfworkflows_streamdelegate",
"ietfworkflows_streamedid",
"ietfworkflows_wgworkflow",
"ietfworkflows_wgworkflow_selected_states",
"ietfworkflows_wgworkflow_selected_tags",
"imported_mailing_list",
"interim_info",
"interim_meetings_acronym",
"interim_meetings_groups_ietf",
"interim_meetings_interim_info",
"interim_meetings_interim_new",
"interim_meetings_meetings",
"interim_meetings_minutes",
"interim_meetings_slides",
"internet_drafts",
"ipr_contacts",
"ipr_detail",
"ipr_ids",
"ipr_licensing",
"ipr_notifications",
"ipr_rfcs",
"ipr_selecttype",
"ipr_updates",
"irtf",
"irtf_chairs",
"liaison_detail",
"liaison_detail_temp",
"liaison_managers",
"liaison_purpose",
"liaisons_interim",
"liaisons_members",
"liaisons_outgoingliaisonapproval",
"liaisons_sdoauthorizedindividual",
"lists_email",
"lists_email_refs",
"lists_list",
"mailing_list",
"mailinglists_domain",
"mailinglists_domain_approvers",
"management_issues",
"meeting_agenda_count",
"meeting_attendees",
"meeting_conflict",
"meeting_conflict_groups",
"meeting_hours",
"meeting_rooms",
"meeting_sessionstatusname",
"meeting_times",
"meeting_venues",
"meetings",
"messages",
"migrate_stat",
"minutes",
"nomcom",
"nomcom_members",
"non_session",
"non_session_ref",
"none_wg_mailing_list",
"not_meeting_groups",
"old_document_comments",
"outstanding_tasks",
"permissions_objectpermission",
"permissions_objectpermissioninheritanceblock",
"permissions_permission",
"permissions_permission_content_types",
"permissions_principalrolerelation",
"permissions_role",
"person_or_org_info",
"phone_numbers",
"postal_addresses",
"print_name",
"prior_address",
"proceedings",
"pwg_cat",
"ref_doc_states_new",
"ref_next_states_new",
"ref_resp",
"replaced_ids",
"request",
"rfc_authors",
"rfc_editor_queue_mirror",
"rfc_editor_queue_mirror_refs",
"rfc_index_mirror",
"rfc_intend_status",
"rfc_status",
"rfcs",
"rfcs_obsolete",
"roll_call",
"scheduled_announcements",
"scheduled_announcements_temp",
"sdo_chairs",
"sdos",
"secretariat_staff",
"session_conflicts",
"session_names",
"session_request_activities",
"session_status",
"slide_types",
"slides",
"staff_work_detail",
"staff_work_history",
"sub_state",
"switches",
"task_status",
"telechat",
"telechat_dates",
"telechat_minutes",
"telechat_users",
"temp_admins",
"temp_agenda71166",
"temp_id_authors",
"temp_telechat_attendees",
"temp_txt",
"templates",
"updated_ipr",
"uploads",
"uploads_temp",
"users",
"web_gm_chairs",
"web_login_info",
"web_user_info",
"wg_agenda",
"wg_meeting_sessions",
"wg_meeting_sessions_temp",
"wg_password",
"wg_proceedings_activities",
"wg_www_pages",
"wgchairs_protowriteup",
"wgchairs_wgdelegate",
"workflows_state",
"workflows_state_transitions",
"workflows_stateinheritanceblock",
"workflows_stateobjectrelation",
"workflows_statepermissionrelation",
"workflows_transition",
"workflows_workflow",
"workflows_workflowmodelrelation",
"workflows_workflowobjectrelation",
"workflows_workflowpermissionrelation",
))

View file

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('liaisons', '0011_auto_20161013_1034'),
]
operations = [
migrations.AlterField(
model_name='liaisonstatement',
name='tags',
field=models.ManyToManyField(to='name.LiaisonStatementTagName', blank=True),
),
migrations.AlterField(
model_name='liaisonstatementgroupcontacts',
name='group',
field=models.ForeignKey(null=True, to='group.Group', unique=True),
),
]

View file

@ -40,7 +40,7 @@ class LiaisonStatement(models.Model):
other_identifiers = models.TextField(blank=True, null=True) # Identifiers from other bodies
body = models.TextField(blank=True)
tags = models.ManyToManyField(LiaisonStatementTagName, blank=True, null=True)
tags = models.ManyToManyField(LiaisonStatementTagName, blank=True)
attachments = models.ManyToManyField(Document, through='LiaisonStatementAttachment', blank=True)
state = models.ForeignKey(LiaisonStatementState, default='pending')
@ -212,7 +212,7 @@ class RelatedLiaisonStatement(models.Model):
class LiaisonStatementGroupContacts(models.Model):
group = models.ForeignKey(Group, unique=True)
group = models.ForeignKey(Group, unique=True, null=True)
contacts = models.CharField(max_length=255,blank=True)
cc_contacts = models.CharField(max_length=255,blank=True)

View file

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mailtrigger', '0007_add_interim_announce'),
]
operations = [
migrations.AlterField(
model_name='mailtrigger',
name='cc',
field=models.ManyToManyField(related_name='used_in_cc', to='mailtrigger.Recipient', blank=True),
),
migrations.AlterField(
model_name='mailtrigger',
name='to',
field=models.ManyToManyField(related_name='used_in_to', to='mailtrigger.Recipient', blank=True),
),
]

View file

@ -22,8 +22,8 @@ def clean_duplicates(addrlist):
class MailTrigger(models.Model):
slug = models.CharField(max_length=32, primary_key=True)
desc = models.TextField(blank=True)
to = models.ManyToManyField('Recipient', null=True, blank=True, related_name='used_in_to')
cc = models.ManyToManyField('Recipient', null=True, blank=True, related_name='used_in_cc')
to = models.ManyToManyField('Recipient', blank=True, related_name='used_in_to')
cc = models.ManyToManyField('Recipient', blank=True, related_name='used_in_cc')
class Meta:
ordering = ["slug"]

File diff suppressed because one or more lines are too long

View file

@ -1,93 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0"><object pk="179" model="dbtemplate.dbtemplate"><field type="CharField" name="path">/meeting/proceedings/defaults/overview.rst</field><field type="CharField" name="title">Proceedings Overview Template</field><field type="TextField" name="variables"><None></None></field><field to="name.dbtemplatetypename" name="type" rel="ManyToOneRel">rst</field><field type="TextField" name="content">The Internet Engineering Task Force (IETF) provides a forum for working groups to coordinate technical development of new protocols. Its most important function is the development and selection of standards within the Internet protocol suite.
The IETF began in January 1986 as a forum for technical coordination by contractors for the then US Defense Advanced Research Projects Agency (DARPA), working on the ARPANET, US Defense Data Network (DDN), and the Internet core gateway system. Since that time, the IETF has grown into a large open international community of network designers, operators, vendors, and researchers concerned with the evolution of the Internet architecture and the smooth operation of the Internet.
The IETF mission includes:
* Identifying and proposing solutions to pressing operational and technical problems in the Internet
* Specifying the development or usage of protocols and the near-term architecture, to solve technical problems for the Internet
* Facilitating technology transfer from the Internet Research Task Force (IRTF) to the wider Internet community;and
* Providing a forum for the exchange of relevant information within the Internet community between vendors, users, researchers, agency contractors, and network managers.
Technical activities in the IETF are addressed within working groups. All working groups are organized roughly by function into seven areas. Each area is led by one or more Area Directors who have primary responsibility for that one area of IETF activity. Together with the Chair of the IETF/IESG, these Area Directors comprise the Internet Engineering Steering Group (IESG).
=================== =================================== ========================
Name Area Email
=================== =================================== ========================
Jari Arkko IETF Chair chair@ietf.org
Jari Arkko General Area jari.arkko@piuha.net
Alia Atlas Routing Area akatlas@gmail.com
Deborah Brungard Routing Areas db3546@att.com
Ben Campbell Applications and Real-Time Area ben@nostrum.com
Benoit Claise Operations and Management Area bclaise@cisco.com
Alissa Cooper Applications and Real-Time Area alissa@cooperw.in
Spencer Dawkins Transport Area spencerdawkins.ietf@gmail.com
Stephen Farrell Security Area stephen.farrell@cs.tcd.ie
Brian Haberman Internet Area brian@innovationslab.net
Joel Jaeggli Operations and Management Area joelja@bogus.com
Barry Leiba Applications and Real-Time Area barryleiba@computer.org
Terry Manderson Internet Area terry.manderson@icann.org
Kathleen Moriarty Security Area Kathleen.Moriarty.ietf@gmail.com
Alvaro Retana Routing Area aretana@cisco.com
Martin Stiemerling Transport Area mls.ietf@gmail.com
=================== =================================== ========================
Liaison and ex-officio members include:
=================== =================================== ========================
Olaf Kolkman IAB Chair iab-chair@iab.org
Danny McPherson IAB Liaison danny@tcb.net
Michelle Cotton IANA Liaison iana@iana.org
Sandy Ginoza RFC Editor Liaison rfc-editor@rfc-editor.org
Alexa Morris IETF Secretariat Liaison exec-director@ietf.org
=================== =================================== ========================
The IETF has a Secretariat, which is managed by Association Management Solutions, LLC (AMS) in Fremont, California.The IETF Executive Director is Alexa Morris (exec-director@ietf.org).
Other personnel that provide full-time support to the Secretariat include:
========================= ===================================
Senior Meeting Planner Marcia Beaulieu
Project Manager Stephanie McCammon
Meeting Regsitrar Maddy Conner
Project Manager Cindy Morgan
Project Manager Amy Vezza
========================= ===================================
To contact the Secretariat, please refer to the addresses and URLs provided on the IETF Secretariat Web page.
The IETF also has a general Administrative Support Activity headed by the IETF Administrative Director, Ray Pelletier iad@ietf.org
The working groups conduct their business during the tri-annual IETF meetings, at interim working group meetings, and via electronic mail on mailing lists established for each group. The tri-annual IETF meetings are 4.5 days in duration, and consist of working group sessions, training sessions, and plenary sessions. The plenary sessions include technical presentations, status reports, and an open IESG meeting.
Following each meeting, the IETF Secretariat publishes meeting proceedings, which contain reports from all of the groups that met, as well as presentation slides, where available. The proceedings also include a summary of the standards-related activities that took place since the previous IETF meeting.
Meeting minutes, working group charters (including information about the working group mailing lists), and general information on current IETF activities are available on the IETF Web site at https://www.ietf.org.</field><field to="group.group" name="group" rel="ManyToOneRel">1</field></object></django-objects>

View file

@ -1,14 +1,9 @@
import datetime
import os
import re
import codecs
from django import forms
from django.core.validators import ValidationError
from django.db.models import Q
from django.forms.fields import Field
from django.utils.encoding import force_text
from django.utils import six
from django.forms.fields import DurationField
from ietf.doc.models import Document, DocAlias, State, NewRevisionDocEvent
from ietf.doc.utils import get_document_content
@ -26,100 +21,6 @@ from ietf.utils.fields import DatepickerDateField
countries.insert(0, ('', ''))
timezones.insert(0, ('', '-' * 9))
# -------------------------------------------------
# DurationField from Django 1.8
# -------------------------------------------------
def duration_string(duration):
days = duration.days
seconds = duration.seconds
microseconds = duration.microseconds
minutes = seconds // 60
seconds = seconds % 60
hours = minutes // 60
minutes = minutes % 60
# string = '{:02d}:{:02d}:{:02d}'.format(hours, minutes, seconds)
string = '{:02d}:{:02d}'.format(hours, minutes)
if days:
string = '{} '.format(days) + string
if microseconds:
string += '.{:06d}'.format(microseconds)
return string
custom_duration_re = re.compile(
r'^(?P<hours>\d+):(?P<minutes>\d+)$'
)
standard_duration_re = re.compile(
r'^'
r'(?:(?P<days>-?\d+) (days?, )?)?'
r'((?:(?P<hours>\d+):)(?=\d+:\d+))?'
r'(?:(?P<minutes>\d+):)?'
r'(?P<seconds>\d+)'
r'(?:\.(?P<microseconds>\d{1,6})\d{0,6})?'
r'$'
)
# Support the sections of ISO 8601 date representation that are accepted by
# timedelta
iso8601_duration_re = re.compile(
r'^P'
r'(?:(?P<days>\d+(.\d+)?)D)?'
r'(?:T'
r'(?:(?P<hours>\d+(.\d+)?)H)?'
r'(?:(?P<minutes>\d+(.\d+)?)M)?'
r'(?:(?P<seconds>\d+(.\d+)?)S)?'
r')?'
r'$'
)
def parse_duration(value):
"""Parses a duration string and returns a datetime.timedelta.
The preferred format for durations in Django is '%d %H:%M:%S.%f'.
Also supports ISO 8601 representation.
"""
match = custom_duration_re.match(value)
if not match:
match = standard_duration_re.match(value)
if not match:
match = iso8601_duration_re.match(value)
if match:
kw = match.groupdict()
if kw.get('microseconds'):
kw['microseconds'] = kw['microseconds'].ljust(6, '0')
kw = {k: float(v) for k, v in six.iteritems(kw) if v is not None}
return datetime.timedelta(**kw)
class DurationField(Field):
default_error_messages = {
'invalid': 'Enter a valid duration.',
}
def prepare_value(self, value):
if isinstance(value, datetime.timedelta):
return duration_string(value)
return value
def to_python(self, value):
if value in self.empty_values:
return None
if isinstance(value, datetime.timedelta):
return value
value = parse_duration(force_text(value))
if value is None:
raise ValidationError(self.error_messages['invalid'], code='invalid')
return value
# -------------------------------------------------
# Helpers
# -------------------------------------------------
@ -301,7 +202,7 @@ class InterimSessionModelForm(forms.ModelForm):
name=filename,
rev='00',
external_url='{}-00.txt'.format(filename))
doc.set_state(State.objects.get(type=doc.type, slug='active'))
doc.set_state(State.objects.get(type__slug=doc.type.slug, slug='active'))
DocAlias.objects.create(name=doc.name, document=doc)
self.instance.sessionpresentation_set.create(document=doc, rev=doc.rev)
NewRevisionDocEvent.objects.create(

View file

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('meeting', '0040_fix_mext_meeting_materials'),
]
operations = [
migrations.AlterField(
model_name='timeslot',
name='sessions',
field=models.ManyToManyField(help_text='Scheduled session, if any.', related_name='slots', through='meeting.SchedTimeSessAssignment', to='meeting.Session', blank=True),
),
]

View file

@ -418,7 +418,7 @@ class TimeSlot(models.Model):
duration = TimedeltaField()
location = models.ForeignKey(Room, blank=True, null=True)
show_location = models.BooleanField(default=True, help_text="Show location in agenda.")
sessions = models.ManyToManyField('Session', related_name='slots', through='SchedTimeSessAssignment', null=True, blank=True, help_text=u"Scheduled session, if any.")
sessions = models.ManyToManyField('Session', related_name='slots', through='SchedTimeSessAssignment', blank=True, help_text=u"Scheduled session, if any.")
modified = models.DateTimeField(auto_now=True)
#

View file

@ -2748,6 +2748,20 @@
"model": "doc.statetype",
"pk": "review"
},
{
"fields": {
"label": "Shepherd's writeup state"
},
"model": "doc.statetype",
"pk": "shepwrit"
},
{
"fields": {
"label": "Liaison state"
},
"model": "doc.statetype",
"pk": "liaison"
},
{
"fields": {
"used": true,

View file

@ -1,6 +1,6 @@
from django.conf import settings
from django import forms
from django.contrib.formtools.preview import FormPreview, AUTO_ID
from formtools.preview import FormPreview, AUTO_ID
from django.shortcuts import get_object_or_404, redirect
from django.utils.decorators import method_decorator
from django.shortcuts import render_to_response

View file

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('nomcom', '0010_nominee_person'),
]
operations = [
migrations.AlterField(
model_name='feedback',
name='author',
field=models.EmailField(max_length=254, verbose_name=b'Author', blank=True),
),
migrations.AlterField(
model_name='feedback',
name='nominees',
field=models.ManyToManyField(to='nomcom.Nominee', blank=True),
),
migrations.AlterField(
model_name='feedback',
name='positions',
field=models.ManyToManyField(to='nomcom.Position', blank=True),
),
migrations.AlterField(
model_name='nomination',
name='nominator_email',
field=models.EmailField(max_length=254, verbose_name=b'Nominator Email', blank=True),
),
]

View file

@ -205,8 +205,8 @@ class Position(models.Model):
class Feedback(models.Model):
nomcom = models.ForeignKey('NomCom')
author = models.EmailField(verbose_name='Author', blank=True)
positions = models.ManyToManyField('Position', blank=True, null=True)
nominees = models.ManyToManyField('Nominee', blank=True, null=True)
positions = models.ManyToManyField('Position', blank=True)
nominees = models.ManyToManyField('Nominee', blank=True)
subject = models.TextField(verbose_name='Subject', blank=True)
comments = EncryptedTextField(verbose_name='Comments')
type = models.ForeignKey(FeedbackTypeName, blank=True, null=True)

View file

@ -75,8 +75,8 @@ def merge_persons(source,target,stream):
admin_site = admin.site
using = 'default'
deletable_objects, perms_needed, protected = admin.utils.get_deleted_objects(
objs, opts, user, admin_site, using)
deletable_objects, model_count, perms_needed, protected = (
admin.utils.get_deleted_objects(objs, opts, user, admin_site, using) )
if len(deletable_objects) > 1:
print >>stream, "Not Deleting Person: {}({})".format(source.ascii,source.pk)

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import ietf.utils.validators
class Migration(migrations.Migration):
dependencies = [
('review', '0005_auto_20161130_0628'),
]
operations = [
migrations.AlterField(
model_name='reviewersettings',
name='filter_re',
field=models.CharField(blank=True, help_text=b'Draft names matching this regular expression should not be assigned', max_length=255, verbose_name=b'Filter regexp', validators=[ietf.utils.validators.RegexStringValidator()]),
),
]

View file

@ -5,6 +5,8 @@ from django.db.models import Q, Max, F
from django.core.urlresolvers import reverse as urlreverse
from django.contrib.sites.models import Site
import debug # pyflakes:ignore
from ietf.group.models import Group, Role
from ietf.doc.models import (Document, ReviewRequestDocEvent, State,
LastCallDocEvent, TelechatDocEvent,
@ -62,9 +64,9 @@ def augment_review_requests_with_events(review_reqs):
def no_review_from_teams_on_doc(doc, rev):
return Group.objects.filter(
reviewrequest__doc=doc,
reviewrequest__doc__name=doc.name,
reviewrequest__reviewed_rev=rev,
reviewrequest__state="no-review-version",
reviewrequest__state__slug="no-review-version",
).distinct()
def unavailable_periods_to_list(past_days=14):

View file

@ -21,7 +21,6 @@ from ietf import __version__
import debug
DEBUG = True
TEMPLATE_DEBUG = DEBUG
debug.debug = DEBUG
# Valid values:
@ -65,12 +64,6 @@ DATABASES = {
#'PASSWORD': 'ietf',
#'OPTIONS': {},
},
# 'legacy': {
# 'NAME': 'ietf',
# 'ENGINE': 'django.db.backends.mysql',
# 'USER': 'ietf',
# #'PASSWORD': 'ietf',
# },
}
DATABASE_TEST_OPTIONS = {
@ -158,8 +151,6 @@ WSGI_APPLICATION = "ietf.wsgi.application"
AUTHENTICATION_BACKENDS = ( 'django.contrib.auth.backends.ModelBackend', )
#DATABASE_ROUTERS = ["ietf.legacy_router.LegacyRouter"]
# ------------------------------------------------------------------------
# Django/Python Logging Framework Modifications
@ -216,13 +207,42 @@ SESSION_SAVE_EVERY_REQUEST = True
PREFERENCES_COOKIE_AGE = 60 * 60 * 24 * 365 * 50 # Age of cookie, in seconds: 50 years
TEMPLATE_LOADERS = (
('django.template.loaders.cached.Loader', (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)),
'ietf.dbtemplate.template.Loader',
)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
BASE_DIR + "/templates",
BASE_DIR + "/secr/templates",
],
'OPTIONS': {
'context_processors': [
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.request',
'django.template.context_processors.media',
#'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'ietf.context_processors.server_mode',
'ietf.context_processors.debug_mark_queries_from_view',
'ietf.context_processors.revision_info',
'ietf.secr.context_processors.secr_revision_info',
'ietf.context_processors.rfcdiff_base_url',
],
'loaders': [
('django.template.loaders.cached.Loader', (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)),
'ietf.dbtemplate.template.Loader',
]
},
},
]
if DEBUG:
TEMPLATES[0]['OPTIONS']['string_if_invalid'] = "** No value found for '%s' **"
MIDDLEWARE_CLASSES = (
'django.middleware.csrf.CsrfViewMiddleware',
@ -240,25 +260,6 @@ MIDDLEWARE_CLASSES = (
ROOT_URLCONF = 'ietf.urls'
TEMPLATE_DIRS = (
BASE_DIR + "/templates",
BASE_DIR + "/secr/templates",
)
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.request',
'django.core.context_processors.media',
'django.contrib.messages.context_processors.messages',
'ietf.context_processors.server_mode',
'ietf.context_processors.debug_mark_queries_from_view',
'ietf.context_processors.revision_info',
'ietf.secr.context_processors.secr_revision_info',
'ietf.context_processors.rfcdiff_base_url',
)
# Additional locations of static files (in addition to each app's static/ dir)
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
@ -754,6 +755,10 @@ LIST_ACCOUNT_DELAY = 60*60*25 # 25 hours
ACCOUNT_REQUEST_EMAIL = 'account-request@ietf.org'
SILENCED_SYSTEM_CHECKS = [
"fields.W342", # Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.
]
# Put the production SECRET_KEY in settings_local.py, and also any other
# sensitive or site-specific changes. DO NOT commit settings_local.py to svn.
@ -768,7 +773,7 @@ for app in INSTALLED_APPS:
# Add DEV_APPS to INSTALLED_APPS
INSTALLED_APPS += DEV_APPS
MIDDLEWARE_CLASSES += DEV_MIDDLEWARE_CLASSES
TEMPLATE_CONTEXT_PROCESSORS += DEV_TEMPLATE_CONTEXT_PROCESSORS
TEMPLATES[0]['OPTIONS']['context_processors'] += DEV_TEMPLATE_CONTEXT_PROCESSORS
# We provide a secret key only for test and development modes. It's
@ -777,7 +782,9 @@ TEMPLATE_CONTEXT_PROCESSORS += DEV_TEMPLATE_CONTEXT_PROCESSORS
# publicly available, for instance from the source repository.
if SERVER_MODE != 'production':
# stomp out the cached template loader, it's annoying
TEMPLATE_LOADERS = tuple(l for e in TEMPLATE_LOADERS for l in (e[1] if isinstance(e, tuple) and "cached.Loader" in e[0] else (e,)))
loaders = TEMPLATES[0]['OPTIONS']['loaders']
loaders = tuple(l for e in loaders for l in (e[1] if isinstance(e, tuple) and "cached.Loader" in e[0] else (e,)))
TEMPLATES[0]['OPTIONS']['loaders'] = loaders
CACHES = {
'default': {

View file

@ -6,8 +6,9 @@
#
from settings import * # pyflakes:ignore
from settings import TEMPLATES
TEMPLATE_LOADERS = (
TEMPLATES[0]['OPTIONS']['loaders'] = (
('django.template.loaders.cached.Loader', (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',

View file

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('submit', '0016_fix_duplicate_upload_docevents'),
]
operations = [
migrations.AlterField(
model_name='submissioncheck',
name='time',
field=models.DateTimeField(auto_now=True),
),
]

View file

@ -77,7 +77,7 @@ class Submission(models.Model):
return Document.objects.filter(name=self.name).first()
class SubmissionCheck(models.Model):
time = models.DateTimeField(auto_now=True, default=None) # The default is to make makemigrations happy
time = models.DateTimeField(auto_now=True)
submission = models.ForeignKey(Submission, related_name='checks')
checker = models.CharField(max_length=256, blank=True)
passed = models.NullBooleanField(default=False)

View file

@ -37,7 +37,8 @@ def create_person(group, role_name, name=None, username=None, email_address=None
return person
def create_group(**kwargs):
return Group.objects.create(state_id="active", **kwargs)
group, created = Group.objects.get_or_create(state_id="active", **kwargs)
return group
def make_immutable_base_data():
"""Some base data (groups, etc.) that doesn't need to be modified by

View file

@ -51,15 +51,16 @@ from fnmatch import fnmatch
from coverage.report import Reporter
from coverage.results import Numbers
from coverage.misc import NotPython
from optparse import make_option
from django.conf import settings
from django.template import TemplateDoesNotExist
from django.template.loaders.base import Loader as BaseLoader
from django.test.runner import DiscoverRunner
from django.core.management import call_command
from django.core.urlresolvers import RegexURLResolver
import debug # pyflakes:ignore
debug.debug = True
import ietf
import ietf.utils.mail
@ -86,7 +87,7 @@ def safe_create_1(self, verbosity, *args, **kwargs):
if settings.GLOBAL_TEST_FIXTURES:
print " Loading global test fixtures: %s" % ", ".join(settings.GLOBAL_TEST_FIXTURES)
loadable = [f for f in settings.GLOBAL_TEST_FIXTURES if "." not in f]
call_command('loaddata', *loadable, verbosity=0, commit=False, database="default")
call_command('loaddata', *loadable, verbosity=verbosity, commit=False, database="default")
for f in settings.GLOBAL_TEST_FIXTURES:
if f not in loadable:
@ -108,11 +109,15 @@ def safe_destroy_0_1(*args, **kwargs):
settings.DATABASES["default"]["NAME"] = test_database_name
return old_destroy(*args, **kwargs)
def template_coverage_loader(template_name, dirs):
if template_coverage_collection == True:
loaded_templates.add(str(template_name))
raise TemplateDoesNotExist
template_coverage_loader.is_usable = True
class TemplateCoverageLoader(BaseLoader):
is_usable = True
def load_template_source(self, template_name, dirs):
global template_coverage_collection, loaded_templates
if template_coverage_collection == True:
loaded_templates.add(str(template_name))
raise TemplateDoesNotExist
load_template_source.is_usable = True
class RecordUrlsMiddleware(object):
def process_request(self, request):
@ -156,7 +161,7 @@ def get_template_paths(apps=None):
# TODO: Add app templates to the full list, if we are using
# django.template.loaders.app_directories.Loader
templates = set()
templatepaths = settings.TEMPLATE_DIRS
templatepaths = settings.TEMPLATES[0]['DIRS']
for templatepath in templatepaths:
for dirpath, dirs, files in os.walk(templatepath):
if ".svn" in dirs:
@ -333,19 +338,18 @@ class CoverageTest(TestCase):
self.skipTest("Coverage switched off with --skip-coverage")
class IetfTestRunner(DiscoverRunner):
option_list = (
make_option('--skip-coverage',
action='store_true', dest='skip_coverage', default=False,
help='Skip test coverage measurements for code, templates, and URLs. '
),
make_option('--save-version-coverage',
action='store', dest='save_version_coverage', default=False,
help='Save test coverage data under the given version label'),
make_option('--save-testresult',
@classmethod
def add_arguments(cls, parser):
parser.add_argument('--skip-coverage',
action='store_true', dest='skip_coverage', default=False,
help='Skip test coverage measurements for code, templates, and URLs. ' )
parser.add_argument('--save-version-coverage',
action='store', dest='save_version_coverage', default=False,
help='Save test coverage data under the given version label')
parser.add_argument('--save-testresult',
action='store_true', dest='save_testresult', default=False,
help='Save short test result data in %s/.testresult' % os.path.dirname(os.path.dirname(settings.BASE_DIR))),
)
def __init__(self, skip_coverage=False, save_version_coverage=None, **kwargs):
#
@ -393,8 +397,7 @@ class IetfTestRunner(DiscoverRunner):
},
}
settings.TEMPLATE_LOADERS = ('ietf.utils.test_runner.template_coverage_loader',) + settings.TEMPLATE_LOADERS
template_coverage_collection = True
settings.TEMPLATES[0]['OPTIONS']['loaders'] = ('ietf.utils.test_runner.TemplateCoverageLoader',) + settings.TEMPLATES[0]['OPTIONS']['loaders']
settings.MIDDLEWARE_CLASSES = ('ietf.utils.test_runner.RecordUrlsMiddleware',) + settings.MIDDLEWARE_CLASSES
url_coverage_collection = True
@ -410,9 +413,9 @@ class IetfTestRunner(DiscoverRunner):
print " Changing SITE_ID to '1' during testing."
settings.SITE_ID = 1
if settings.TEMPLATE_STRING_IF_INVALID != '':
print " Changing TEMPLATE_STRING_IF_INVALID to '' during testing."
settings.TEMPLATE_STRING_IF_INVALID = ''
if settings.TEMPLATES[0]['OPTIONS']['string_if_invalid'] != '':
print(" Changing TEMPLATES[0]['OPTIONS']['string_if_invalid'] to '' during testing")
settings.TEMPLATES[0]['OPTIONS']['string_if_invalid'] = ''
assert not settings.IDTRACKER_BASE_URL.endswith('/')
@ -487,14 +490,15 @@ class IetfTestRunner(DiscoverRunner):
return test_apps, test_paths
def run_tests(self, test_labels, extra_tests=[], **kwargs):
global old_destroy, old_create, test_database_name, template_coverage_collection
from django.db import connection
# Tests that involve switching back and forth between the real
# database and the test database are way too dangerous to run
# against the production database
if socket.gethostname().split('.')[0] in ['core3', 'ietfa', 'ietfb', 'ietfc', ]:
raise EnvironmentError("Refusing to run tests on production server")
global old_destroy, old_create, test_database_name
from django.db import connection
old_create = connection.creation.__class__.create_test_db
connection.creation.__class__.create_test_db = safe_create_1
old_destroy = connection.creation.__class__.destroy_test_db
@ -508,6 +512,7 @@ class IetfTestRunner(DiscoverRunner):
self.test_apps, self.test_paths = self.get_test_paths(test_labels)
if self.check_coverage:
template_coverage_collection = True
extra_tests += [
CoverageTest(test_runner=self, methodName='url_coverage_test'),
CoverageTest(test_runner=self, methodName='template_coverage_test'),

View file

@ -16,8 +16,8 @@ from django.conf import settings
from django.core.management import call_command
from django.template import Context
from django.template.defaulttags import URLNode
from django.template.loader import get_template
from django.templatetags.static import StaticNode
from django.template.loaders.filesystem import Loader
import debug # pyflakes:ignore
@ -104,7 +104,6 @@ def get_callbacks(urllist):
return list(callbacks)
debug.debug = True
class TemplateChecksTestCase(TestCase):
paths = []
@ -112,12 +111,11 @@ class TemplateChecksTestCase(TestCase):
def setUp(self):
set_coverage_checking(False)
self.loader = Loader()
self.paths = list(get_template_paths())
self.paths.sort()
for path in self.paths:
try:
self.templates[path], _ = self.loader.load_template(path)
self.templates[path] = get_template(path).template
except Exception:
pass
@ -134,7 +132,7 @@ class TemplateChecksTestCase(TestCase):
if not path in self.templates:
try:
self.loader.load_template(path)
get_template(path)
except Exception as e:
errors.append((path, e))
if errors:

Binary file not shown.

View file

@ -7,8 +7,9 @@ coverage>=4.0.1,!=4.0.2
#cssselect>=0.6.1 # for PyQuery
decorator>=3.4.0
defusedxml>=0.4.1 # for TastyPie when ussing xml; not a declared dependency
Django>=1.7.10,<1.8
Django>=1.8.16,<1.9
django-bootstrap3>=5.1.1,<7.0.0 # django-bootstrap 7.0 requires django 1.8
django-formtools>=1.0 # instead of django.contrib.formtools in 1.8
django-markup>=1.1
django-tastypie>=0.13.1
django-widget-tweaks>=1.3