TICKET:928 use correct role in session request notification email

- Legacy-Id: 5802
This commit is contained in:
Ryan Cross 2013-06-24 22:52:13 +00:00
parent 613746fceb
commit 45ec7a97a1
5 changed files with 96 additions and 85 deletions

View file

@ -15,7 +15,7 @@ from ietf.ietfauth.decorators import has_role
from ietf.utils.mail import send_mail
from ietf.meeting.models import Meeting, Session, Constraint
from ietf.group.models import Group, Role
from ietf.group.models import Group, Role
from ietf.name.models import SessionStatusName, ConstraintName
from forms import *
@ -50,7 +50,7 @@ def get_initial_session(sessions):
initial = {}
# even if there are three sessions requested, the old form has 2 in this field
initial['num_session'] = sessions.count() if sessions.count() <= 2 else 2
# accessing these foreign key fields throw errors if they are unset so we
# need to catch these
initial['length_session1'] = str(sessions[0].requested_duration.seconds)
@ -65,7 +65,7 @@ def get_initial_session(sessions):
initial['conflict3'] = ' '.join([ c.target.acronym for c in conflicts.filter(name__slug='conflic3') ])
initial['comments'] = sessions[0].comments
return initial
def get_lock_message():
'''
Returns the message to display to non-secretariat users when the tool is locked.
@ -84,6 +84,19 @@ def get_meeting():
'''
return Meeting.objects.filter(type='ietf').order_by('-date')[0]
def get_requester_text(person,group):
'''
This function takes a Person object and a Group object and returns the text to use in the
session request notification email, ie. Joe Smith, a Chair of the ancp working group
'''
roles = group.role_set.filter(name__in=('chair','secr'),person=person)
if roles:
return '%s, a %s of the %s working group' % (person, roles[0].name, group.acronym)
if group.parent.role_set.filter(name='ad',person=person):
return '%s, a %s Area Director' % (person, group.parent.acronym.upper())
if person.role_set.filter(name='secr',group__acronym='secretariat'):
return '%s, on behalf of the %s working group' % (person, group.acronym)
def save_conflicts(group, meeting, conflicts, name):
'''
This function takes a Group, Meeting a string which is a list of Groups acronyms (conflicts),
@ -93,7 +106,7 @@ def save_conflicts(group, meeting, conflicts, name):
acronyms = conflicts.replace(',',' ').split()
for acronym in acronyms:
target = Group.objects.get(acronym=acronym)
constraint = Constraint(source=group,
target=target,
meeting=meeting,
@ -111,7 +124,7 @@ def send_notification(group,meeting,login,session,action):
from_email = ('"IETF Meeting Session Request Tool"','session_request_developers@ietf.org')
subject = '%s - New Meeting Session Request for IETF %s' % (group.acronym, meeting.number)
template = 'sreq/session_request_notification.txt'
# send email
context = {}
context['session'] = session
@ -119,12 +132,13 @@ def send_notification(group,meeting,login,session,action):
context['meeting'] = meeting
context['login'] = login
context['header'] = 'A new'
context['requester'] = get_requester_text(login,group)
# update overrides
if action == 'update':
subject = '%s - Update to a Meeting Session Request for IETF %s' % (group.acronym, meeting.number)
context['header'] = 'An update to a'
# if third session requested approval is required
# change headers TO=ADs, CC=session-request, submitter and cochairs
if session.get('length_session3',None):
@ -164,11 +178,11 @@ def approve(request, acronym):
meeting = get_meeting()
group = get_object_or_404(Group, acronym=acronym)
session = Session.objects.get(meeting=meeting,group=group,status='apprw')
if has_role(request.user,'Secretariat') or group.parent.role_set.filter(name='ad',person=request.user.get_profile()):
session.status = SessionStatusName.objects.get(slug='appr')
session.save()
messages.success(request, 'Third session approved')
url = reverse('sessions_view', kwargs={'acronym':acronym})
return HttpResponseRedirect(url)
@ -184,27 +198,27 @@ def cancel(request, acronym):
This view cancels a session request and sends a notification.
To cancel, or withdraw the request set status = deleted.
"canceled" status is used by the secretariat.
NOTE: this function can also be called after a session has been
scheduled during the period when the session request tool is
scheduled during the period when the session request tool is
reopened. In this case be sure to clear the timeslot assignment as well.
'''
meeting = get_meeting()
group = get_object_or_404(Group, acronym=acronym)
sessions = Session.objects.filter(meeting=meeting,group=group).order_by('id')
login = request.user.get_profile()
# delete conflicts
Constraint.objects.filter(meeting=meeting,source=group).delete()
# mark sessions as deleted
for session in sessions:
session.status_id = 'deleted'
session.save()
# clear schedule assignments if already scheduled
session.scheduledsession_set.all().delete()
# send notifitcation
to_email = SESSION_REQUEST_EMAIL
cc_list = get_cc_list(group, login)
@ -214,7 +228,7 @@ def cancel(request, acronym):
{'login':login,
'group':group,
'meeting':meeting}, cc=cc_list)
messages.success(request, 'The %s Session Request has been canceled' % group.acronym)
url = reverse('sessions')
return HttpResponseRedirect(url)
@ -231,23 +245,23 @@ def confirm(request, acronym):
meeting = get_meeting()
group = get_object_or_404(Group,acronym=acronym)
login = request.user.get_profile()
if request.method == 'POST':
# clear http session data
del request.session['session_form']
button_text = request.POST.get('submit', '')
if button_text == 'Cancel':
messages.success(request, 'Session Request has been canceled')
url = reverse('sessions')
return HttpResponseRedirect(url)
# delete any existing session records with status = canceled or notmeet
Session.objects.filter(group=group,meeting=meeting,status__in=('canceled','notmeet')).delete()
# create new session records
count = 0
# lenth_session2 and length_session3 fields might be disabled by javascript and so
# lenth_session2 and length_session3 fields might be disabled by javascript and so
# wouldn't appear in form data
for duration in (form.get('length_session1',None),form.get('length_session2',None),form.get('length_session3',None)):
count += 1
@ -262,30 +276,30 @@ def confirm(request, acronym):
comments=form['comments'],
status=SessionStatusName.objects.get(slug=slug))
new_session.save()
# write constraint records
save_conflicts(group,meeting,form['conflict1'],'conflict')
save_conflicts(group,meeting,form['conflict2'],'conflic2')
save_conflicts(group,meeting,form['conflict3'],'conflic3')
# deprecated in new schema
# log activity
#add_session_activity(group,'New session was requested',meeting,user)
# clear not meeting
Session.objects.filter(group=group,meeting=meeting,status='notmeet').delete()
# send notification
send_notification(group,meeting,login,form,'new')
status_text = 'IETF Agenda to be scheduled'
messages.success(request, 'Your request has been sent to %s' % status_text)
url = reverse('sessions')
return HttpResponseRedirect(url)
# GET logic
session_conflicts = session_conflicts_as_string(group, meeting)
return render_to_response('sreq/confirm.html', {
'session': form,
'group': group,
@ -294,7 +308,7 @@ def confirm(request, acronym):
)
@check_permissions
def edit(request, acronym):
def edit(request, acronym):
'''
This view allows the user to edit details of the session request
'''
@ -305,13 +319,13 @@ def edit(request, acronym):
initial = get_initial_session(sessions)
session_conflicts = session_conflicts_as_string(group, meeting)
login = request.user.get_profile()
if request.method == 'POST':
button_text = request.POST.get('submit', '')
if button_text == 'Cancel':
url = reverse('sessions_view', kwargs={'acronym':acronym})
return HttpResponseRedirect(url)
form = SessionForm(request.POST,initial=initial)
if form.is_valid():
if form.has_changed():
@ -322,7 +336,7 @@ def edit(request, acronym):
session = sessions[0]
session.requested_duration = datetime.timedelta(0,int(form.cleaned_data['length_session1']))
session.save()
# session 2
if 'length_session2' in form.changed_data:
length_session2 = form.cleaned_data['length_session2']
@ -344,7 +358,7 @@ def edit(request, acronym):
session = sessions[1]
session.requested_duration = duration
session.save()
# session 3
if 'length_session3' in form.changed_data:
length_session3 = form.cleaned_data['length_session3']
@ -366,8 +380,8 @@ def edit(request, acronym):
session = sessions[2]
session.requested_duration = duration
session.save()
if 'attendees' in form.changed_data:
sessions.update(attendees=form.cleaned_data['attendees'])
if 'comments' in form.changed_data:
@ -381,21 +395,21 @@ def edit(request, acronym):
if 'conflict3' in form.changed_data:
Constraint.objects.filter(meeting=meeting,source=group,name='conflic3').delete()
save_conflicts(group,meeting,form.cleaned_data['conflict3'],'conflic3')
# deprecated
# log activity
#add_session_activity(group,'Session Request was updated',meeting,user)
# send notification
send_notification(group,meeting,login,form.cleaned_data,'update')
messages.success(request, 'Session Request updated')
url = reverse('sessions_view', kwargs={'acronym':acronym})
return HttpResponseRedirect(url)
else:
form = SessionForm(initial=initial)
return render_to_response('sreq/edit.html', {
'meeting': meeting,
'form': form,
@ -407,22 +421,22 @@ def edit(request, acronym):
def main(request):
'''
Display list of groups the user has access to.
Template variables
form: a select box populated with unscheduled groups
meeting: the current meeting
scheduled_sessions:
scheduled_sessions:
'''
# check for locked flag
is_locked = check_app_locked()
if is_locked and not has_role(request.user,'Secretariat'):
message = get_lock_message()
return render_to_response('sreq/locked.html', {
'message': message},
RequestContext(request, {}),
)
# TODO this is not currently used in the main template
if request.method == 'POST':
button_text = request.POST.get('submit', '')
@ -432,15 +446,15 @@ def main(request):
else:
redirect_url = reverse('sessions_new', kwargs={'acronym':request.POST['group']})
return HttpResponseRedirect(redirect_url)
meeting = get_meeting()
scheduled_groups,unscheduled_groups = groups_by_session(request.user, meeting)
# load form select with unscheduled groups
choices = zip([ g.pk for g in unscheduled_groups ],
[ str(g) for g in unscheduled_groups ])
form = GroupSelectForm(choices=choices)
# add session status messages for use in template
for group in scheduled_groups:
sessions = group.session_set.filter(meeting=meeting)
@ -448,12 +462,12 @@ def main(request):
group.status_message = sessions[0].status
else:
group.status_message = 'First two sessions: %s, Third session: %s' % (sessions[0].status,sessions[2].status)
# add not meeting indicators for use in template
for group in unscheduled_groups:
if group.session_set.filter(meeting=meeting,status='notmeet'):
group.not_meeting = True
return render_to_response('sreq/main.html', {
'is_locked': is_locked,
'form': form,
@ -469,18 +483,18 @@ def new(request, acronym):
This view gathers details for a new session request. The user proceeds to confirm()
to create the request.
'''
group = get_object_or_404(Group, acronym=acronym)
meeting = get_meeting()
session_conflicts = session_conflicts_as_string(group, meeting)
user = request.user
if request.method == 'POST':
button_text = request.POST.get('submit', '')
if button_text == 'Cancel':
url = reverse('sessions')
return HttpResponseRedirect(url)
form = SessionForm(request.POST)
if form.is_valid():
# check if request already exists for this group
@ -488,13 +502,13 @@ def new(request, acronym):
messages.warning(request, 'Sessions for working group %s have already been requested once.' % group.acronym)
url = reverse('sessions')
return HttpResponseRedirect(url)
# save in user session
request.session['session_form'] = form.data
url = reverse('sessions_confirm',kwargs={'acronym':acronym})
return HttpResponseRedirect(url)
# the "previous" querystring causes the form to be returned
# pre-populated with data from last meeeting's session request
elif request.method == 'GET' and request.GET.has_key('previous'):
@ -507,10 +521,10 @@ def new(request, acronym):
initial = get_initial_session(previous_sessions)
form = SessionForm(initial=initial)
else:
form = SessionForm()
return render_to_response('sreq/new.html', {
'meeting': meeting,
'form': form,
@ -530,7 +544,7 @@ def no_session(request, acronym):
meeting = get_meeting()
group = get_object_or_404(Group, acronym=acronym)
login = request.user.get_profile()
# delete canceled record if there is one
Session.objects.filter(group=group,meeting=meeting,status='canceled').delete()
@ -539,7 +553,7 @@ def no_session(request, acronym):
messages.info(request, 'The group %s is already marked as not meeting' % group.acronym)
url = reverse('sessions')
return HttpResponseRedirect(url)
session = Session(group=group,
meeting=meeting,
requested=datetime.datetime.now(),
@ -547,7 +561,7 @@ def no_session(request, acronym):
requested_duration=0,
status=SessionStatusName.objects.get(slug='notmeet'))
session.save()
# send notification
to_email = SESSION_REQUEST_EMAIL
cc_list = get_cc_list(group, login)
@ -557,12 +571,12 @@ def no_session(request, acronym):
{'login':login,
'group':group,
'meeting':meeting}, cc=cc_list)
# deprecated?
# log activity
#text = 'A message was sent to notify not having a session at IETF %d' % meeting.meeting_num
#add_session_activity(group,text,meeting,request.person)
# redirect
messages.success(request, 'A message was sent to notify not having a session at IETF %s' % meeting.number)
url = reverse('sessions')
@ -574,32 +588,32 @@ def tool_status(request):
This view handles locking and unlocking of the tool to the public.
'''
is_locked = check_app_locked()
if request.method == 'POST':
button_text = request.POST.get('submit', '')
if button_text == 'Done':
url = reverse('sessions')
return HttpResponseRedirect(url)
form = ToolStatusForm(request.POST)
if button_text == 'Lock':
if form.is_valid():
f = open(LOCKFILE,'w')
f.write(form.cleaned_data['message'])
f.close()
messages.success(request, 'Session Request Tool is now Locked')
url = reverse('sessions')
return HttpResponseRedirect(url)
elif button_text == 'Unlock':
os.remove(LOCKFILE)
messages.success(request, 'Session Request Tool is now Unlocked')
url = reverse('sessions')
return HttpResponseRedirect(url)
else:
if is_locked:
message = get_lock_message()
@ -607,7 +621,7 @@ def tool_status(request):
form = ToolStatusForm(initial=initial)
else:
form = ToolStatusForm()
return render_to_response('sreq/tool_status.html', {
'is_locked': is_locked,
'form': form},
@ -621,12 +635,12 @@ def view(request, acronym):
meeting = get_meeting()
group = get_object_or_404(Group, acronym=acronym)
sessions = Session.objects.filter(~Q(status__in=('canceled','notmeet','deleted')),meeting=meeting,group=group).order_by('id')
# if there are no session requests yet, redirect to new session request page
if not sessions:
redirect_url = reverse('sessions_new', kwargs={'acronym':acronym})
return HttpResponseRedirect(redirect_url)
# TODO simulate activity records
activities = [{'act_date':sessions[0].requested.strftime('%b %d, %Y'),
'act_time':sessions[0].requested.strftime('%H:%M:%S'),
@ -637,20 +651,20 @@ def view(request, acronym):
'act_time':sessions[0].scheduled.strftime('%H:%M:%S'),
'activity':'Session was scheduled',
'act_by':'Secretariat'})
# other groups that list this group in their conflicts
session_conflicts = session_conflicts_as_string(group, meeting)
show_approve_button = False
# if sessions include a 3rd session waiting approval and the user is a secretariat or AD of the group
# display approve button
if sessions.filter(status='apprw'):
if has_role(request.user,'Secretariat') or group.parent.role_set.filter(name='ad',person=request.user.get_profile()):
show_approve_button = True
# build session dictionary (like querydict from new session request form) for use in template
session = get_initial_session(sessions)
return render_to_response('sreq/view.html', {
'session': session,
'activities': activities,

View file

@ -180,14 +180,11 @@ def doc_detail(request, date, name):
doc = get_object_or_404(Document, docalias__name=name)
# As of Datatracker v4.32, Conflict Review (conflrev) Document Types can
# be added to the Telechat agenda. We need to check the document type here
# and set the state_type for use later in the view
# be added to the Telechat agenda. If Document.type_id == draft use draft-iesg
# for state type
state_type = doc.type_id
if doc.type_id == 'draft':
state_type = 'draft-iesg'
elif doc.type_id == 'conflrev':
state_type = 'conflrev'
elif doc.type_id == 'charter':
state_type = 'charter'
started_process = doc.latest_event(type="started_iesg_process")
login = request.user.get_profile()

View file

@ -1,7 +1,7 @@
Dear {{ group.parent }} Director(s):
{{ header }} meeting session request has just been
submitted by {{ login }}, a working group chair of {{ group.name }}.
submitted by {{ requester }}.
The third session requires your approval.
To approve the session go to the session request view here:

View file

@ -1,4 +1,4 @@
{% load ams_filters %}
A request to cancel a meeting session has just been submitted by {{ login|smart_login }} {{ group.acronym }} working group.
A request to cancel a meeting session has just been submitted by {{ requester }}.

View file

@ -1,5 +1,5 @@
{% load ams_filters %}
{{ header }} meeting session request has just been submitted by {{ login|smart_login }} {{ group.acronym }} working group.
{{ header }} meeting session request has just been submitted by {{ requester }}.
{% include "includes/session_info.txt" %}