Introduce generic states and reminders
- Legacy-Id: 3615
This commit is contained in:
parent
08ff44dd18
commit
f6261a9a49
|
@ -1,22 +1,88 @@
|
|||
from django.utils.safestring import mark_safe
|
||||
from django.contrib import admin
|
||||
from models import *
|
||||
from person.models import *
|
||||
from django import forms
|
||||
|
||||
class DocAliasAdmin(admin.ModelAdmin):
|
||||
list_display = [ 'name', 'document_link', ]
|
||||
search_fields = [ 'name', 'document__name', ]
|
||||
raw_id_fields = ['document']
|
||||
admin.site.register(DocAlias, DocAliasAdmin)
|
||||
from models import *
|
||||
from redesign.person.models import *
|
||||
from redesign.doc.utils import get_state_types
|
||||
|
||||
class StateTypeAdmin(admin.ModelAdmin):
|
||||
list_display = ["slug", "label"]
|
||||
admin.site.register(StateType, StateTypeAdmin)
|
||||
|
||||
class StateAdmin(admin.ModelAdmin):
|
||||
list_display = ["slug", "type", 'name', 'order', 'desc']
|
||||
filter_horizontal = ["next_states"]
|
||||
admin.site.register(State, StateAdmin)
|
||||
|
||||
class DocAliasInline(admin.TabularInline):
|
||||
model = DocAlias
|
||||
extra = 1
|
||||
|
||||
# document form for managing states in a less confusing way
|
||||
|
||||
class StatesWidget(forms.SelectMultiple):
|
||||
"""Display all applicable states as separate select boxes,
|
||||
requires 'instance' have been set on the widget."""
|
||||
def render(self, name, value, attrs=None, choices=()):
|
||||
|
||||
types = StateType.objects.filter(slug__in=get_state_types(self.instance))
|
||||
|
||||
categorized_choices = []
|
||||
for t in types:
|
||||
states = State.objects.filter(type=t).select_related()
|
||||
if states:
|
||||
categorized_choices.append((t.label, states))
|
||||
|
||||
html = []
|
||||
first = True
|
||||
for label, states in categorized_choices:
|
||||
htmlid = "id_%s_%s" % (name, label)
|
||||
|
||||
html.append('<div style="clear:both;padding-top:%s">' % ("1em" if first else "0.5em"))
|
||||
html.append(u'<label for="%s">%s:</label>' % (htmlid, label))
|
||||
html.append(u'<select name="%s" id="%s">' % (name, htmlid))
|
||||
html.append(u'<option value="">-----------</option>')
|
||||
for s in states:
|
||||
html.append('<option %s value="%s">%s</option>' % ("selected" if s.pk in value else "", s.pk, s.name))
|
||||
html.append(u'</select>')
|
||||
html.append("</div>")
|
||||
|
||||
first = False
|
||||
|
||||
return mark_safe(u"".join(html))
|
||||
|
||||
class StatesField(forms.ModelMultipleChoiceField):
|
||||
def __init__(self, *args, **kwargs):
|
||||
# use widget with multiple select boxes
|
||||
kwargs['widget'] = StatesWidget
|
||||
super(StatesField, self).__init__(*args, **kwargs)
|
||||
|
||||
def clean(self, value):
|
||||
if value and isinstance(value, (list, tuple)):
|
||||
# remove "", in case a state is reset
|
||||
value = [x for x in value if x]
|
||||
return super(StatesField, self).clean(value)
|
||||
|
||||
class DocumentForm(forms.ModelForm):
|
||||
states = StatesField(queryset=State.objects.all(), required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(DocumentForm, self).__init__(*args, **kwargs)
|
||||
|
||||
# we don't normally have access to the instance in the widget
|
||||
# so set it here
|
||||
self.fields["states"].widget.instance = self.instance
|
||||
|
||||
class Meta:
|
||||
model = Document
|
||||
|
||||
class DocumentAdmin(admin.ModelAdmin):
|
||||
list_display = ['name', 'rev', 'state', 'group', 'pages', 'intended_std_level', 'author_list', 'time']
|
||||
search_fields = ['name']
|
||||
raw_id_fields = ['authors', 'related', 'group', 'shepherd', 'ad']
|
||||
inlines = [DocAliasInline]
|
||||
form = DocumentForm
|
||||
|
||||
admin.site.register(Document, DocumentAdmin)
|
||||
|
||||
|
@ -25,8 +91,15 @@ class DocHistoryAdmin(admin.ModelAdmin):
|
|||
search_fields = ['doc__name']
|
||||
ordering = ['time', 'doc', 'rev']
|
||||
raw_id_fields = ['doc', 'authors', 'related', 'group', 'shepherd', 'ad']
|
||||
|
||||
admin.site.register(DocHistory, DocHistoryAdmin)
|
||||
|
||||
class DocAliasAdmin(admin.ModelAdmin):
|
||||
list_display = [ 'name', 'document_link', ]
|
||||
search_fields = [ 'name', 'document__name', ]
|
||||
raw_id_fields = ['document']
|
||||
admin.site.register(DocAlias, DocAliasAdmin)
|
||||
|
||||
|
||||
# events
|
||||
|
||||
|
|
|
@ -11,6 +11,29 @@ from redesign.util import admin_link
|
|||
|
||||
import datetime, os
|
||||
|
||||
class StateType(models.Model):
|
||||
slug = models.CharField(primary_key=True, max_length=30) # draft, draft_iesg, charter, ...
|
||||
label = models.CharField(max_length=255) # State, IESG state, WG state, ...
|
||||
|
||||
def __unicode__(self):
|
||||
return self.label
|
||||
|
||||
class State(models.Model):
|
||||
type = models.ForeignKey(StateType)
|
||||
slug = models.SlugField()
|
||||
name = models.CharField(max_length=255)
|
||||
used = models.BooleanField(default=True)
|
||||
desc = models.TextField(blank=True)
|
||||
order = models.IntegerField(default=0)
|
||||
|
||||
next_states = models.ManyToManyField('State', related_name="previous_states")
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
ordering = ["type", "order"]
|
||||
|
||||
class DocumentInfo(models.Model):
|
||||
"""Any kind of document. Draft, RFC, Charter, IPR Statement, Liaison Statement"""
|
||||
time = models.DateTimeField(default=datetime.datetime.now) # should probably have auto_now=True
|
||||
|
@ -18,12 +41,13 @@ class DocumentInfo(models.Model):
|
|||
type = models.ForeignKey(DocTypeName, blank=True, null=True) # Draft, Agenda, Minutes, Charter, Discuss, Guideline, Email, Review, Issue, Wiki, External ...
|
||||
title = models.CharField(max_length=255)
|
||||
# State
|
||||
states = models.ManyToManyField(State, blank=True)
|
||||
|
||||
state = models.ForeignKey(DocStateName, blank=True, null=True) # Active/Expired/RFC/Replaced/Withdrawn
|
||||
tags = models.ManyToManyField(DocInfoTagName, blank=True, null=True) # Revised ID Needed, ExternalParty, AD Followup, ...
|
||||
tags = models.ManyToManyField(DocTagName, blank=True, null=True) # Revised ID Needed, ExternalParty, AD Followup, ...
|
||||
stream = models.ForeignKey(DocStreamName, blank=True, null=True) # IETF, IAB, IRTF, Independent Submission
|
||||
group = models.ForeignKey(Group, blank=True, null=True) # WG, RG, IAB, IESG, Edu, Tools
|
||||
wg_state = models.ForeignKey(WgDocStateName, verbose_name="WG state", blank=True, null=True) # Not/Candidate/Active/Parked/LastCall/WriteUp/Submitted/Dead
|
||||
iesg_state = models.ForeignKey(IesgDocStateName, verbose_name="IESG state", blank=True, null=True) #
|
||||
iesg_state = models.ForeignKey(IesgDocStateName, verbose_name="IESG state", blank=True, null=True) #
|
||||
iana_state = models.ForeignKey(IanaDocStateName, verbose_name="IANA state", blank=True, null=True)
|
||||
rfc_state = models.ForeignKey(RfcDocStateName, verbose_name="RFC state", blank=True, null=True)
|
||||
# Other
|
||||
|
@ -48,7 +72,24 @@ class DocumentInfo(models.Model):
|
|||
return os.path.join(settings.AGENDA_PATH, meeting, self.type_id) + "/"
|
||||
else:
|
||||
raise NotImplemented
|
||||
|
||||
|
||||
def set_state(self, state):
|
||||
already_set = self.states.filter(type=state.type)
|
||||
others = [s for s in already_set if s != state]
|
||||
if others:
|
||||
self.states.remove(*others)
|
||||
if state not in already_set:
|
||||
self.states.add(state)
|
||||
|
||||
def unset_state(self, state):
|
||||
self.states.remove(state)
|
||||
|
||||
def get_state(self, state_type):
|
||||
try:
|
||||
return self.states.get(type=state_type)
|
||||
except State.DoesNotExist:
|
||||
return None
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
def author_list(self):
|
||||
|
@ -116,7 +157,6 @@ class Document(DocumentInfo):
|
|||
if a:
|
||||
name = a[0].name
|
||||
return name
|
||||
|
||||
|
||||
class RelatedDocHistory(models.Model):
|
||||
source = models.ForeignKey('DocHistory')
|
||||
|
@ -144,6 +184,9 @@ class DocHistory(DocumentInfo):
|
|||
authors = models.ManyToManyField(Email, through=DocHistoryAuthor, blank=True)
|
||||
def __unicode__(self):
|
||||
return unicode(self.doc.name)
|
||||
class Meta:
|
||||
verbose_name = "document history"
|
||||
verbose_name_plural = "document histories"
|
||||
|
||||
def save_document_in_history(doc):
|
||||
def get_model_fields_as_dict(obj):
|
||||
|
@ -198,6 +241,12 @@ class DocAlias(models.Model):
|
|||
verbose_name = "document alias"
|
||||
verbose_name_plural = "document aliases"
|
||||
|
||||
class DocReminder(models.Model):
|
||||
event = models.ForeignKey('DocEvent')
|
||||
type = models.ForeignKey(DocReminderTypeName)
|
||||
due = models.DateTimeField()
|
||||
active = models.BooleanField(default=True)
|
||||
|
||||
|
||||
EVENT_TYPES = [
|
||||
# core events
|
||||
|
@ -205,6 +254,7 @@ EVENT_TYPES = [
|
|||
("changed_document", "Changed document metadata"),
|
||||
|
||||
# misc document events
|
||||
("changed_stream", "Changed document stream"),
|
||||
("added_comment", "Added comment"),
|
||||
("expired_document", "Expired document"),
|
||||
("requested_resurrect", "Requested resurrect"),
|
||||
|
@ -212,6 +262,7 @@ EVENT_TYPES = [
|
|||
("published_rfc", "Published RFC"),
|
||||
|
||||
# WG events
|
||||
("changed_group", "Changed group"),
|
||||
("changed_protocol_writeup", "Changed protocol writeup"),
|
||||
|
||||
# IESG events
|
||||
|
|
|
@ -7,28 +7,30 @@ def get_state_types(doc):
|
|||
return res
|
||||
|
||||
res.append(doc.type_id)
|
||||
|
||||
#if doc.type_id in ("agenda", "minutes", "slides", "liai-att"):
|
||||
# res.append(doc.type_id)
|
||||
if doc.type_id == "draft":
|
||||
if doc.stream_id == "ietf":
|
||||
wg_specific = doc.type_id + ":" + "wg" + ":" + doc.group.acronym
|
||||
if State.objects.filter(type=wg_specific):
|
||||
res.append(wg_specific)
|
||||
else:
|
||||
res.append(doc.type_id + ":" + "wg")
|
||||
elif doc.stream_id == "irtf":
|
||||
res.append(doc.type_id + ":" + "rg")
|
||||
elif doc.stream_id == "iab":
|
||||
res.append(doc.type_id + ":" + "iab")
|
||||
elif doc.stream_id == "ise":
|
||||
res.append(doc.type_id + ":" + "ise")
|
||||
if doc.stream_id != "legacy":
|
||||
res.append("draft-stream-%s" % doc.stream_id)
|
||||
|
||||
res.append(doc.type_id + ":" + "iesg")
|
||||
res.append(doc.type_id + ":" + "iana")
|
||||
res.append(doc.type_id + ":" + "rfc-editor")
|
||||
res.append("draft-iesg")
|
||||
res.append("draft-iana")
|
||||
res.append("draft-rfceditor")
|
||||
|
||||
return res
|
||||
|
||||
def get_tags_for_stream_id(stream_id):
|
||||
if stream_id == "ietf":
|
||||
return ["w-expert", "w-extern", "w-merge", "need-aut", "w-refdoc", "w-refing", "rev-wglc", "rev-ad", "rev-iesg", "sheph-u", "other"]
|
||||
elif stream_id == "iab":
|
||||
return ["need-ed", "w-part", "w-review", "need-rev", "sh-f-up"]
|
||||
elif stream_id == "irtf":
|
||||
return ["need-ed", "need-sh", "w-dep", "need-rev", "iesg-com"]
|
||||
elif stream_id == "ise":
|
||||
return ["w-dep", "w-review", "need-rev", "iesg-com"]
|
||||
else:
|
||||
return []
|
||||
|
||||
def active_ballot_positions(doc):
|
||||
"""Return dict mapping each active AD to a current ballot position (or None if they haven't voted)."""
|
||||
|
|
Loading…
Reference in a new issue