View to design/remove delegates into an stream. Fixes #699

- Legacy-Id: 3300
This commit is contained in:
Emilio A. Sánchez López 2011-08-11 12:18:59 +00:00
parent 322caf332c
commit b28469f117
8 changed files with 175 additions and 22 deletions

View file

@ -1,5 +1,3 @@
from django.db.models.query import QuerySet
from ietf.ietfworkflows.streams import get_streamed_draft
@ -24,20 +22,42 @@ def is_wgdelegate(person):
return bool(person.wgdelegate_set.all())
def is_chair_of_draft(user, draft):
def is_delegate_of_stream(user, stream):
if is_secretariat(user):
return True
person = get_person_for_user(user)
return stream.check_delegate(person)
def is_chair_of_stream(user, stream):
if is_secretariat(user):
return True
person = get_person_for_user(user)
return stream.check_chair(person)
def is_authorized_in_draft_stream(user, draft):
if is_secretariat(user):
return True
person = get_person_for_user(user)
if not person:
return False
streamed = get_streamed_draft(draft)
if not streamed or not streamed.stream:
return False
# Check if the person is chair of the stream
if is_chair_of_stream(user, streamed.stream):
return True
# Check if the person is delegate of the stream
if is_delegate_of_stream(user, streamed.stream):
return True
# Check if the person is chair of the related group
chairs = streamed.stream.get_chairs_for_document(draft)
if not chairs:
return False
if isinstance(chairs, QuerySet):
return bool(chairs.filter(person=person).count())
else:
return person in chairs
if chairs and person in chairs:
return True
# Check if the person is authorized by a delegate system
delegates = streamed.stream.get_delegates_for_document(draft)
return bool(person in delegates)
def can_edit_state(user, draft):
@ -50,7 +70,7 @@ def can_edit_state(user, draft):
is_wgchair(person) or
is_wgdelegate(person))
return (is_secretariat(user) or
is_chair_of_draft(user, draft))
is_authorized_in_draft_stream(user, draft))
def can_edit_stream(user, draft):

View file

@ -8,7 +8,7 @@ from workflows.utils import set_workflow_for_object
from ietf.idtracker.models import PersonOrOrgInfo, IETFWG
from ietf.wgchairs.accounts import get_person_for_user
from ietf.ietfworkflows.models import Stream
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,
@ -62,7 +62,7 @@ class NoWorkflowStateForm(StreamDraftForm):
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()]))
if len(wgs) > 1:
self.wgs = list(wgs)
self.wgs.sort(lambda x,y: cmp(x.group_acronym.acronym, y.group_acronym.acronym))
self.wgs.sort(lambda x, y: cmp(x.group_acronym.acronym, y.group_acronym.acronym))
self.fields['wg'].choices = [(i.pk, '%s - %s' % (i.group_acronym.acronym, i.group_acronym.name)) for i in self.wgs]
else:
self.onlywg = list(wgs)[0].group_acronym
@ -200,3 +200,28 @@ class DraftStreamForm(StreamDraftForm):
comment=comment,
person=self.person,
to_stream=to_stream)
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):
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')
def save(self):
StreamDelegate.objects.get_or_create(
person=self.person,
stream=self.stream)

View file

@ -148,7 +148,7 @@ class Stream(models.Model):
def _irtf_group(self, document):
filename = document.filename.split('-')
if len(filename) > 2 and filename[0] == 'draft' and filename[1] =='irtf':
if len(filename) > 2 and filename[0] == 'draft' and filename[1] == 'irtf':
try:
return IRTF.objects.get(acronym=filename[2])
except IRTF.DoesNotExist:
@ -163,7 +163,6 @@ class Stream(models.Model):
chairs.append(Role.objects.get(pk=Role.IRTF_CHAIR).person)
return chairs
def _ietf_delegates_for_document(self, document):
group = self.get_group_for_document(document)
if not group:
@ -215,8 +214,8 @@ class Stream(models.Model):
def get_chairs(self):
chairs = []
if hasattr(self, '_%s_stream_chairs' % self.name.lower()):
chairs += list(getattr(self, '_%s_stream_chairs' % self.name.lower())(person))
chairs += list(getattr(self, '_%s_stream_chairs' % self.name.lower())())
role_key = getattr(Role, '%s_CHAIR' % self.name.upper(), None)
if role_key:
try:
@ -228,7 +227,7 @@ class Stream(models.Model):
def get_delegates(self):
delegates = []
if hasattr(self, '_%s_stream_delegates' % self.name.lower()):
delegates += list(getattr(self, '_%s_stream_delegates' % self.name.lower())(person))
delegates += list(getattr(self, '_%s_stream_delegates' % self.name.lower())())
delegates += [i.person for i in StreamDelegate.objects.filter(stream=self)]
return list(set(delegates))

View file

@ -6,7 +6,9 @@ from ietf.ietfworkflows.utils import (get_workflow_for_draft,
from ietf.wgchairs.accounts import (can_manage_shepherd_of_a_document,
can_manage_writeup_of_a_document)
from ietf.ietfworkflows.streams import get_stream_from_wrapper
from ietf.ietfworkflows.accounts import (can_edit_state, can_edit_stream)
from ietf.ietfworkflows.models import Stream
from ietf.ietfworkflows.accounts import (can_edit_state, can_edit_stream,
is_chair_of_stream)
register = template.Library()
@ -14,7 +16,6 @@ register = template.Library()
@register.inclusion_tag('ietfworkflows/stream_state.html', takes_context=True)
def stream_state(context, doc):
request = context.get('request', None)
data = {}
stream = get_stream_from_wrapper(doc)
data.update({'stream': stream})
@ -72,3 +73,33 @@ def edit_actions(context, wrapper):
'draft': draft,
'doc': wrapper,
}
class StreamListNode(template.Node):
def __init__(self, user, var_name):
self.user = user
self.var_name = var_name
def render(self, context):
user = self.user.resolve(context)
streams = []
for i in Stream.objects.all():
if is_chair_of_stream(user, i):
streams.append(i)
context.update({self.var_name: streams})
return ''
@register.tag
def get_user_managed_streams(parser, token):
firstbits = token.contents.split(None, 2)
if len(firstbits) != 3:
raise template.TemplateSyntaxError("'get_user_managed_streams' tag takes three arguments")
user = parser.compile_filter(firstbits[1])
lastbits_reversed = firstbits[2][::-1].split(None, 2)
if lastbits_reversed[1][::-1] != 'as':
raise template.TemplateSyntaxError("next-to-last argument to 'get_user_managed_stream' tag must"
" be 'as'")
var_name = lastbits_reversed[0][::-1]
return StreamListNode(user, var_name)

View file

@ -6,4 +6,5 @@ urlpatterns = patterns('ietf.ietfworkflows.views',
url(r'^(?P<name>[^/]+)/history/$', 'stream_history', name='stream_history'),
url(r'^(?P<name>[^/]+)/edit/state/$', 'edit_state', name='edit_state'),
url(r'^(?P<name>[^/]+)/edit/stream/$', 'edit_stream', name='edit_stream'),
url(r'^delegates/(?P<stream_name>[^/]+)/$', 'stream_delegates', name='stream_delegates'),
)

View file

@ -3,16 +3,19 @@ from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
from ietf.idtracker.models import InternetDraft
from ietf.ietfworkflows.models import Stream, StreamDelegate
from ietf.ietfworkflows.forms import (DraftTagsStateForm,
DraftStreamForm,
NoWorkflowStateForm)
NoWorkflowStateForm,
StreamDelegatesForm)
from ietf.ietfworkflows.streams import (get_stream_from_draft,
get_streamed_draft)
from ietf.ietfworkflows.utils import (get_workflow_history_for_draft,
get_workflow_for_draft,
get_annotation_tags_for_draft,
get_state_for_draft)
from ietf.ietfworkflows.accounts import (can_edit_state, can_edit_stream)
from ietf.ietfworkflows.accounts import (can_edit_state, can_edit_stream,
is_chair_of_stream)
REDUCED_HISTORY_LEN = 20
@ -81,8 +84,34 @@ def edit_state(request, name):
return HttpResponseForbidden('You have no permission to access this view')
return _edit_draft_stream(request, draft, DraftTagsStateForm)
def edit_stream(request, name):
draft = get_object_or_404(InternetDraft, filename=name)
if not can_edit_stream(request.user, draft):
return HttpResponseForbidden('You have no permission to access this view')
return _edit_draft_stream(request, draft, DraftStreamForm)
def stream_delegates(request, stream_name):
stream = get_object_or_404(Stream, name=stream_name)
if not is_chair_of_stream(request.user, stream):
return HttpResponseForbidden('You have no permission to access this view')
chairs = stream.get_chairs()
form = StreamDelegatesForm(stream=stream)
if request.method == 'POST':
if request.POST.get('delete', False):
pk_list = request.POST.getlist('remove_delegate')
StreamDelegate.objects.filter(stream=stream, person__pk__in=pk_list).delete()
else:
form = StreamDelegatesForm(request.POST, stream=stream)
if form.is_valid():
form.save()
form = StreamDelegatesForm(stream=stream)
delegates = stream.get_delegates()
return render_to_response('ietfworkflows/stream_delegates.html',
{'stream': stream,
'chairs': chairs,
'delegates': delegates,
'form': form,
},
context_instance=RequestContext(request))

View file

@ -33,7 +33,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{% endcomment %}
{% load wg_menu %}
{% load ietf_filters %}
{% load ietf_filters ietf_streams %}
<ul>
{% if user|in_group:"Area_Director" %}
<li class="sect first">AD Dashboard</li>
@ -47,6 +47,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<li><a href="{% url ietf.iesg.views.telechat_dates %}">Telechat Dates</a></li>
<li><a href="{% url iesg_working_group_actions %}">Working Groups</a></li>
{% endif %}
{% get_user_managed_streams user as stream_list %}
{% if stream_list %}
<li class="sect{% if not user|in_group:"Area_Director,Secretariat" %} first{% endif %}">Streams</li>
{% for stream in stream_list %}
<li{% if forloop.last %} style="margin-bottom: 2px;"{% endif %}><a href="{% url stream_delegates stream.name %}">{{ stream.name }} stream</a></li>
{% endfor %}
{% endif %}
<li class="sect{% if not user|in_group:"Area_Director,Secretariat" %} first{% endif %}">Working Groups</li>
<li style="padding-bottom:0;"><div id="wgs" class="yuimenu"><div class="bd" style="border:0;">

View file

@ -0,0 +1,41 @@
{% extends "base.html" %}
{% load ietf_streams ietf_filters %}
{% block content %}
<h1>Stream: {{ stream.name }}</h1>
{% if chairs %}
<h2>{{ stream.name }} stream chairs</h2>
<table class="ietf-table">
<tr><th>Name</th><th>Email</th></tr>
{% for chair in chairs %}
<tr class="{% cycle "oddrow" "evenrow" %}"><td>{{ chair }}</td><td>{{ chair.email.0 }} &lt;{{ chair.email.1 }}&gt;</td></tr>
{% endfor %}
</table>
{% endif %}
<h2>{{ stream.name }} stream delegates</h2>
<form action="" method="POST">
{% if delegates %}
<table class="ietf-table">
<tr><th></th><th>Name</th><th>Email</th></tr>
{% for delegate in delegates %}
<tr class="{% cycle "oddrow" "evenrow" %}"><td><input type="checkbox" name="remove_delegate" value="{{ delegate.pk }}" /></td><td>{{ delegate }}</td><td>{{ delegate.email.0 }} &lt;{{ delegate.email.1 }}&gt;</td></tr>
{% endfor %}
</table>
<p>
<input type="submit" value="Remove selected delegates" name="delete" />
</p>
{% else %}
<p>
No delegates for {{ stream.name }} stream asigned.
</p>
{% endif %}
<p>
Enter a valid e-mail address to add a new delegate.
</p>
{% if form.errors.email %}{{ form.errors.email }}{% endif %}
{{ form.email }}
<input type="submit" value="Add new delegate" />
</form>
{% endblock %}