datatracker/ietf/ietfworkflows/forms.py
2012-01-24 17:17:24 +00:00

368 lines
15 KiB
Python

import datetime
from django.conf import settings
from django import forms
from django.template.loader import render_to_string
from workflows.models import State
from workflows.utils import set_workflow_for_object
from ietf.idtracker.models import PersonOrOrgInfo, IETFWG, InternetDraft
from ietf.wgchairs.accounts import get_person_for_user
from ietf.ietfworkflows.models import Stream, StreamDelegate
from ietf.ietfworkflows.utils import (get_workflow_for_draft, get_workflow_for_wg,
get_state_for_draft, get_state_by_name,
update_state, FOLLOWUP_TAG,
get_annotation_tags_for_draft,
update_tags, update_stream)
from ietf.ietfworkflows.accounts import is_secretariat
from ietf.ietfworkflows.streams import (get_stream_from_draft, get_streamed_draft,
get_stream_by_name, set_stream_for_draft)
from ietf.ietfworkflows.constants import CALL_FOR_ADOPTION, IETF_STREAM
from ietf.doc.utils import get_tags_for_stream_id
from ietf.doc.models import save_document_in_history, DocEvent, Document
from ietf.name.models import DocTagName, StreamName, RoleName
from ietf.group.models import Group, GroupStateTransitions, Role
from ietf.group.utils import save_group_in_history
from ietf.person.models import Person, Email
class StreamDraftForm(forms.Form):
can_cancel = False
template = None
def __init__(self, *args, **kwargs):
self.draft = kwargs.pop('draft', None)
self.user = kwargs.pop('user', None)
self.person = get_person_for_user(self.user)
self.workflow = get_workflow_for_draft(self.draft)
self.message = {}
super(StreamDraftForm, self).__init__(*args, **kwargs)
def get_message(self):
return self.message
def set_message(self, msg_type, msg_value):
self.message = {'type': msg_type,
'value': msg_value,
}
def __unicode__(self):
return render_to_string(self.template, {'form': self})
class NoWorkflowStateForm(StreamDraftForm):
comment = forms.CharField(widget=forms.Textarea)
weeks = forms.IntegerField(required=False)
wg = forms.ChoiceField(required=False)
template = 'ietfworkflows/noworkflow_state_form.html'
def __init__(self, *args, **kwargs):
super(NoWorkflowStateForm, self).__init__(*args, **kwargs)
self.wgs = None
if is_secretariat(self.user):
wgs = IETFWG.objects.all().order_by('group_acronym__acronym')
else:
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
wgs = IETFWG.objects.filter(type="wg", state="active", role__name__in=("chair", "delegate"), role__person__user=self.user).order_by('acronym').distinct()
else:
wgs = set([i.group_acronym for i in self.person.wgchair_set.all()]).union(set([i.wg for i in self.person.wgdelegate_set.all()]))
wgs = list(wgs)
wgs.sort(lambda x, y: cmp(x.group_acronym.acronym, y.group_acronym.acronym))
self.wgs = wgs
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
self.fields['wg'].choices = [(i.pk, '%s - %s' % (i.acronym, i.name)) for i in self.wgs]
else:
self.fields['wg'].choices = [(i.pk, '%s - %s' % (i.group_acronym.acronym, i.group_acronym.name)) for i in self.wgs]
def save(self):
comment = self.cleaned_data.get('comment').strip()
weeks = self.cleaned_data.get('weeks')
wg = IETFWG.objects.get(pk=self.cleaned_data.get('wg'))
estimated_date = None
if weeks:
now = datetime.date.today()
estimated_date = now + datetime.timedelta(weeks=weeks)
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
# do changes on real Document object instead of proxy to avoid trouble
doc = Document.objects.get(pk=self.draft.pk)
save_document_in_history(doc)
doc.time = datetime.datetime.now()
new_stream = StreamName.objects.get(slug="ietf")
if doc.stream != new_stream:
e = DocEvent(type="changed_stream")
e.time = doc.time
e.by = self.user.get_profile()
e.doc = doc
e.desc = u"Changed to <b>%s</b>" % new_stream.name
if doc.stream:
e.desc += u" from %s" % doc.stream.name
e.save()
doc.stream = new_stream
if doc.group.pk != wg.pk:
e = DocEvent(type="changed_group")
e.time = doc.time
e.by = self.user.get_profile()
e.doc = doc
e.desc = u"Changed group to <b>%s (%s)</b>" % (wg.name, wg.acronym.upper())
if doc.group.type_id != "individ":
e.desc += " from %s (%s)" % (doc.group.name, doc.group.acronym)
e.save()
doc.group_id = wg.pk
doc.save()
self.draft = InternetDraft.objects.get(pk=doc.pk) # make sure proxy object is updated
else:
workflow = get_workflow_for_wg(wg)
set_workflow_for_object(self.draft, workflow)
stream = get_stream_by_name(IETF_STREAM)
streamed = get_streamed_draft(self.draft)
if not streamed:
set_stream_for_draft(self.draft, stream)
streamed = get_streamed_draft(self.draft)
streamed.stream = stream
streamed.group = wg
streamed.save()
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from ietf.doc.models import State
to_state = State.objects.get(slug="c-adopt", type="draft-stream-%s" % self.draft.stream_id)
else:
to_state = get_state_by_name(CALL_FOR_ADOPTION)
update_state(self.request, self.draft,
comment=comment,
person=self.person,
to_state=to_state,
estimated_date=estimated_date)
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
if comment:
e = DocEvent(type="added_comment")
e.time = self.draft.time
e.by = self.person
e.doc_id = self.draft.pk
e.desc = comment
e.save()
class DraftTagsStateForm(StreamDraftForm):
comment = forms.CharField(widget=forms.Textarea)
new_state = forms.ChoiceField()
weeks = forms.IntegerField(required=False)
tags = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, required=False)
template = 'ietfworkflows/state_form.html'
def __init__(self, *args, **kwargs):
super(DraftTagsStateForm, self).__init__(*args, **kwargs)
self.state = get_state_for_draft(self.draft)
self.fields['new_state'].choices = self.get_states()
if self.is_bound:
for key, value in self.data.items():
if key.startswith('transition_'):
new_state = self.get_new_state(key)
if new_state:
self.data = self.data.copy()
self.data.update({'new_state': new_state.id})
if key.startswith('new_state_'): # hack to get value from submit buttons
self.data = self.data.copy()
self.data['new_state'] = key.replace('new_state_', '')
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
possible_tags = get_tags_for_stream_id(self.draft.stream_id)
if self.draft.stream_id == "ietf" and self.draft.group:
unused_tags = self.draft.group.unused_tags.values_list("slug", flat=True)
possible_tags = [t for t in possible_tags if t not in unused_tags]
self.available_tags = DocTagName.objects.filter(slug__in=possible_tags)
self.tags = self.draft.tags.filter(slug__in=possible_tags)
else:
self.available_tags = self.workflow.get_tags()
self.tags = [i.annotation_tag for i in get_annotation_tags_for_draft(self.draft)]
self.fields['tags'].choices = [(i.pk, i.name) for i in self.available_tags]
self.fields['tags'].initial = [i.pk for i in self.tags]
def get_new_state(self, key):
transition_id = key.replace('transition_', '')
transition = self.get_transitions().filter(id=transition_id)
if transition:
return transition[0].destination
return None
def get_transitions(self):
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
return []
return self.state.transitions.filter(workflow=self.workflow)
def get_next_states(self):
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from ietf.doc.models import State
state_type = "draft-stream-%s" % self.draft.stream_id
s = self.draft.get_state(state_type)
next_states = []
if s:
next_states = s.next_states.all()
if self.draft.stream_id == "ietf" and self.draft.group:
transitions = self.draft.group.groupstatetransitions_set.filter(state=s)
if transitions:
next_states = transitions[0].next_states.all()
else:
# return the initial state
states = State.objects.filter(type=state_type).order_by('order')
if states:
next_states = states[:1]
unused = []
if self.draft.group:
unused = self.draft.group.unused_states.values_list("pk", flat=True)
return [n for n in next_states if n.pk not in unused]
return []
def get_states(self):
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from ietf.doc.models import State
states = State.objects.filter(type="draft-stream-%s" % self.draft.stream_id)
if self.draft.stream_id == "ietf" and self.draft.group:
unused_states = self.draft.group.unused_states.values_list("pk", flat=True)
states = [s for s in states if s.pk not in unused_states]
return [(i.pk, i.name) for i in states]
return [(i.pk, i.name) for i in self.workflow.get_states()]
def save_tags(self):
comment = self.cleaned_data.get('comment')
new_tags = self.cleaned_data.get('tags')
set_tags = [tag for tag in self.available_tags if str(tag.pk) in new_tags and tag not in self.tags]
reset_tags = [tag for tag in self.available_tags if str(tag.pk) not in new_tags and tag in self.tags]
followup = bool([tag for tag in set_tags if tag.name == FOLLOWUP_TAG])
extra_notify = []
if followup:
try:
shepherd = self.draft.shepherd
if shepherd:
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
extra_notify = [shepherd.formatted_email()]
else:
extra_notify = ['%s <%s>' % shepherd.email()]
except PersonOrOrgInfo.DoesNotExist:
pass
if not set_tags and not reset_tags:
return
update_tags(self.request, self.draft,
comment=comment,
person=self.person,
set_tags=set_tags,
reset_tags=reset_tags,
extra_notify=extra_notify)
def save_state(self):
comment = self.cleaned_data.get('comment')
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from ietf.doc.models import State
state = State.objects.get(pk=self.cleaned_data.get('new_state'))
weeks = self.cleaned_data.get('weeks')
estimated_date = None
if weeks:
now = datetime.date.today()
estimated_date = now + datetime.timedelta(weeks=weeks)
update_state(self.request, self.draft,
comment=comment,
person=self.person,
to_state=state,
estimated_date=estimated_date)
def save(self):
self.save_tags()
if 'only_tags' not in self.data.keys():
self.save_state()
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
comment = self.cleaned_data.get('comment').strip()
if comment:
e = DocEvent(type="added_comment")
e.time = self.draft.time
e.by = self.person
e.doc_id = self.draft.pk
e.desc = comment
e.save()
class DraftStreamForm(StreamDraftForm):
comment = forms.CharField(widget=forms.Textarea)
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
stream = forms.ModelChoiceField(StreamName.objects.exclude(slug="legacy"))
else:
stream = forms.ModelChoiceField(Stream.objects.all())
template = 'ietfworkflows/stream_form.html'
def __init__(self, *args, **kwargs):
super(DraftStreamForm, self).__init__(*args, **kwargs)
self.stream = get_stream_from_draft(self.draft)
self.tags = [i.annotation_tag for i in get_annotation_tags_for_draft(self.draft)]
if self.stream:
self.fields['stream'].initial = self.stream.pk
def save(self):
comment = self.cleaned_data.get('comment').strip()
to_stream = self.cleaned_data.get('stream')
update_stream(self.request, self.draft,
comment=comment,
person=self.person,
to_stream=to_stream)
if comment:
e = DocEvent(type="added_comment")
e.time = self.draft.time
e.by = self.person
e.doc_id = self.draft.pk
e.desc = comment
e.save()
class StreamDelegatesForm(forms.Form):
email = forms.EmailField()
def __init__(self, *args, **kwargs):
self.stream = kwargs.pop('stream')
super(StreamDelegatesForm, self).__init__(*args, **kwargs)
def get_person(self, email):
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
persons = Person.objects.filter(email__address=email).distinct()
else:
persons = PersonOrOrgInfo.objects.filter(emailaddress__address=email).distinct()
if not persons:
return None
return persons[0]
def clean_email(self):
email = self.cleaned_data.get('email')
self.person = self.get_person(email)
if not self.person:
raise forms.ValidationError('There is no user with this email in the system')
return email
def save(self):
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
stream_group = Group.objects.get(acronym=self.stream.slug)
save_group_in_history(stream_group)
Role.objects.get_or_create(person=self.person,
group=stream_group,
name=RoleName.objects.get(slug="delegate"),
email=Email.objects.get(address=self.cleaned_data.get('email')))
return
StreamDelegate.objects.get_or_create(
person=self.person,
stream=self.stream)