Merged in branch/amsl/1.50@6388 from rcross@amsl.com, with secretariat tool

announcement fixes, permission fixes, and agenda database schema fixes.
 - Legacy-Id: 6473
This commit is contained in:
Henrik Levkowetz 2013-10-21 20:29:15 +00:00
parent a7db9eec43
commit edcc97aded
7 changed files with 85 additions and 93 deletions

View file

@ -1,4 +1,4 @@
__version__ = "1.41" __version__ = "1.50"
__date__ = "$Date: 2011/07/26 14:29:17 $" __date__ = "$Date: 2011/07/26 14:29:17 $"

View file

@ -35,7 +35,8 @@ FROM_LIST = ('IETF Secretariat <ietf-secretariat@ietf.org>',
'RSOC Chair <rsoc-chair@iab.org>', 'RSOC Chair <rsoc-chair@iab.org>',
'ISOC Board of Trustees <eburger@standardstrack.com>', 'ISOC Board of Trustees <eburger@standardstrack.com>',
'RFC Series Editor <rse@rfc-editor.org>', 'RFC Series Editor <rse@rfc-editor.org>',
'IAB Executive Director <execd@iab.org>') 'IAB Executive Director <execd@iab.org>',
'IETF Mentoring Program <mentoring@ietf.org>')
TO_LIST = ('IETF Announcement List <ietf-announce@ietf.org>', TO_LIST = ('IETF Announcement List <ietf-announce@ietf.org>',
'I-D Announcement List <i-d-announce@ietf.org>', 'I-D Announcement List <i-d-announce@ietf.org>',
@ -107,12 +108,16 @@ def get_from_choices(user):
group__acronym='iab', group__acronym='iab',
name='execdir'): name='execdir'):
f = (FROM_LIST[6],FROM_LIST[16]) f = (FROM_LIST[6],FROM_LIST[16])
elif Role.objects.filter(person=person,
group__acronym='mentor',
name="chair"):
f = (FROM_LIST[17],)
# NomCom # NomCom
nomcoms = Role.objects.filter(name="chair", nomcoms = Role.objects.filter(name="chair",
group__acronym__startswith="nomcom", group__acronym__startswith="nomcom",
group__state="active", group__state="active",
group__type="ietf", group__type="nomcom",
person=person) person=person)
if nomcoms: if nomcoms:
year = nomcoms[0].group.acronym[-4:] year = nomcoms[0].group.acronym[-4:]
@ -141,7 +146,7 @@ TO_CHOICES = get_to_choices()
class AnnounceForm(forms.ModelForm): class AnnounceForm(forms.ModelForm):
#nomcom = forms.BooleanField(required=False) #nomcom = forms.BooleanField(required=False)
nomcom = forms.ModelChoiceField(queryset=Group.objects.filter(acronym__startswith='nomcom',type='ietf',state='active'),required=False) nomcom = forms.ModelChoiceField(queryset=Group.objects.filter(acronym__startswith='nomcom',type='nomcom',state='active'),required=False)
to_custom = MultiEmailField(required=False,label='') to_custom = MultiEmailField(required=False,label='')
#cc = MultiEmailField(required=False) #cc = MultiEmailField(required=False)

View file

@ -23,7 +23,7 @@ def check_access(user):
Secretariat, IAD, IAB Chair, IETF Chair, RSOC Chair, IAOC Chair, NomCom Chair, RSE Chair Secretariat, IAD, IAB Chair, IETF Chair, RSOC Chair, IAOC Chair, NomCom Chair, RSE Chair
''' '''
person = user.get_profile() person = user.get_profile()
groups_with_access = ("iab", "rsoc", "ietf", "iaoc", "rse") groups_with_access = ("iab", "rsoc", "ietf", "iaoc", "rse", "mentor")
if Role.objects.filter(person=person, if Role.objects.filter(person=person,
group__acronym__in=groups_with_access, group__acronym__in=groups_with_access,
name="chair") or has_role(user, ["Secretariat","IAD"]): name="chair") or has_role(user, ["Secretariat","IAD"]):
@ -31,7 +31,7 @@ def check_access(user):
if Role.objects.filter(name="chair", if Role.objects.filter(name="chair",
group__acronym__startswith="nomcom", group__acronym__startswith="nomcom",
group__state="active", group__state="active",
group__type="ietf", group__type="nomcom",
person=person): person=person):
return True return True
if Role.objects.filter(person=person, if Role.objects.filter(person=person,

View file

@ -146,7 +146,7 @@ class NewSessionForm(forms.Form):
time_obj = datetime.datetime.combine(day_obj,hour) time_obj = datetime.datetime.combine(day_obj,hour)
slot = TimeSlot.objects.get(meeting=self.meeting,time=time_obj,location=room) slot = TimeSlot.objects.get(meeting=self.meeting,time=time_obj,location=room)
next_slot = get_next_slot(slot) next_slot = get_next_slot(slot)
if not next_slot or next_slot.session != None: if not next_slot:
raise forms.ValidationError('There is no next session to combine') raise forms.ValidationError('There is no next session to combine')
return cleaned_data return cleaned_data

View file

@ -12,7 +12,7 @@ from django.utils.functional import curry
from django.utils import simplejson from django.utils import simplejson
from ietf.utils.mail import send_mail from ietf.utils.mail import send_mail
from ietf.meeting.models import Meeting, Session, Room, TimeSlot from ietf.meeting.models import Meeting, Session, Room, TimeSlot, Schedule, ScheduledSession
from ietf.meeting.helpers import get_schedule from ietf.meeting.helpers import get_schedule
from ietf.group.models import Group from ietf.group.models import Group
from ietf.name.models import SessionStatusName, TimeSlotTypeName from ietf.name.models import SessionStatusName, TimeSlotTypeName
@ -22,7 +22,7 @@ from ietf.secr.proceedings.views import build_choices, handle_upload_file
from ietf.secr.sreq.forms import GroupSelectForm from ietf.secr.sreq.forms import GroupSelectForm
from ietf.secr.sreq.views import get_initial_session, session_conflicts_as_string from ietf.secr.sreq.views import get_initial_session, session_conflicts_as_string
from ietf.secr.utils.mail import get_cc_list from ietf.secr.utils.mail import get_cc_list
from ietf.secr.utils.meeting import get_upload_root from ietf.secr.utils.meeting import get_upload_root, get_session, get_timeslot
from forms import * from forms import *
@ -106,6 +106,8 @@ def build_nonsession(meeting):
last_meeting = get_last_meeting(meeting) last_meeting = get_last_meeting(meeting)
delta = meeting.date - last_meeting.date delta = meeting.date - last_meeting.date
system = Person.objects.get(name='(system)') system = Person.objects.get(name='(system)')
schedule = get_schedule(request, meeting)
for slot in TimeSlot.objects.filter(meeting=last_meeting,type__in=('break','reg','other','plenary')): for slot in TimeSlot.objects.filter(meeting=last_meeting,type__in=('break','reg','other','plenary')):
new_time = slot.time + delta new_time = slot.time + delta
session = None session = None
@ -119,9 +121,8 @@ def build_nonsession(meeting):
status_id='sched') status_id='sched')
session.save() session.save()
TimeSlot.objects.create(type=slot.type, ts = TimeSlot.objects.create(type=slot.type,
meeting=meeting, meeting=meeting,
session=session,
name=slot.name, name=slot.name,
time=new_time, time=new_time,
duration=slot.duration, duration=slot.duration,
@ -136,7 +137,7 @@ def is_combined(session):
''' '''
Check to see if this session is using two combined timeslots Check to see if this session is using two combined timeslots
''' '''
if session.timeslot_set.count() > 1: if session.scheduledsession_set.filter(schedule=meeting.agenda).count() > 1:
return True return True
else: else:
return False return False
@ -175,7 +176,7 @@ def send_notification(request, sessions):
# easier to populate template from timeslot perspective. assuming one-to-one timeslot-session # easier to populate template from timeslot perspective. assuming one-to-one timeslot-session
count = 0 count = 0
session_info = '' session_info = ''
data = [ (s,s.timeslot_set.all()[0]) for s in sessions ] data = [ (s,get_timeslot(s)) for s in sessions ]
for s,t in data: for s,t in data:
count += 1 count += 1
session_info += session_info_template.format(group.acronym, session_info += session_info_template.format(group.acronym,
@ -204,8 +205,7 @@ def send_notification(request, sessions):
def sort_groups(meeting): def sort_groups(meeting):
''' '''
Similar to sreq.views.sort_groups Similar to sreq.views.sort_groups
Takes a Django User object and a Meeting object Takes a Meeting object and returns a tuple scheduled_groups, unscheduled groups.
Returns a tuple scheduled_groups, unscheduled groups.
''' '''
scheduled_groups = [] scheduled_groups = []
unscheduled_groups = [] unscheduled_groups = []
@ -217,10 +217,10 @@ def sort_groups(meeting):
scheduled_sessions = ScheduledSession.objects.filter(schedule=meeting.agenda,session__isnull=False) scheduled_sessions = ScheduledSession.objects.filter(schedule=meeting.agenda,session__isnull=False)
groups_with_timeslots = [ x.session.group for x in scheduled_sessions ] groups_with_timeslots = [ x.session.group for x in scheduled_sessions ]
for group in sorted_groups_with_sessions: for group in sorted_groups_with_sessions:
if group in groups_with_timeslots: if group in groups_with_timeslots:
scheduled_groups.append(group) scheduled_groups.append(group)
else: else:
unscheduled_groups.append(group) unscheduled_groups.append(group)
return scheduled_groups, unscheduled_groups return scheduled_groups, unscheduled_groups
@ -418,6 +418,14 @@ def non_session(request, meeting_id):
t = meeting.date + datetime.timedelta(days=int(day)) t = meeting.date + datetime.timedelta(days=int(day))
new_time = datetime.datetime(t.year,t.month,t.day,time.hour,time.minute) new_time = datetime.datetime(t.year,t.month,t.day,time.hour,time.minute)
# create TimeSlot object
timeslot = TimeSlot.objects.create(type=form.cleaned_data['type'],
meeting=meeting,
name=name,
time=new_time,
duration=duration,
show_location=form.cleaned_data['show_location'])
# create a dummy Session object to hold materials # create a dummy Session object to hold materials
# NOTE: we're setting group to none here, but the set_room page will force user # NOTE: we're setting group to none here, but the set_room page will force user
# to pick a legitimate group # to pick a legitimate group
@ -430,15 +438,11 @@ def non_session(request, meeting_id):
requested_by=Person.objects.get(name='(system)'), requested_by=Person.objects.get(name='(system)'),
status_id='sched') status_id='sched')
session.save() session.save()
# create TimeSlot object # create association
TimeSlot.objects.create(type=form.cleaned_data['type'], ScheduledSession.objects.create(timeslot=timeslot,
meeting=meeting, session=session,
session=session, schedule=meeting.agenda)
name=name,
time=new_time,
duration=duration,
show_location=form.cleaned_data['show_location'])
messages.success(request, 'Non-Sessions updated successfully') messages.success(request, 'Non-Sessions updated successfully')
url = reverse('meetings_non_session', kwargs={'meeting_id':meeting_id}) url = reverse('meetings_non_session', kwargs={'meeting_id':meeting_id})
@ -464,13 +468,14 @@ def non_session_delete(request, meeting_id, slot_id):
''' '''
slot = get_object_or_404(TimeSlot, id=slot_id) slot = get_object_or_404(TimeSlot, id=slot_id)
if slot.type_id in ('other','plenary'): if slot.type_id in ('other','plenary'):
if slot.session.materials.exclude(states__slug='deleted'): session = get_session(slot)
if session and session.materials.exclude(states__slug='deleted'):
messages.error(request, 'Materials have already been uploaded for "%s". You must delete those before deleting the timeslot.' % slot.name) messages.error(request, 'Materials have already been uploaded for "%s". You must delete those before deleting the timeslot.' % slot.name)
url = reverse('meetings_non_session', kwargs={'meeting_id':meeting_id}) url = reverse('meetings_non_session', kwargs={'meeting_id':meeting_id})
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
else: else:
slot.session.delete() slot.sessions.all().delete()
slot.delete() slot.delete()
messages.success(request, 'Non-Session timeslot deleted successfully') messages.success(request, 'Non-Session timeslot deleted successfully')
@ -483,6 +488,7 @@ def non_session_edit(request, meeting_id, slot_id):
''' '''
meeting = get_object_or_404(Meeting, number=meeting_id) meeting = get_object_or_404(Meeting, number=meeting_id)
slot = get_object_or_404(TimeSlot, id=slot_id) slot = get_object_or_404(TimeSlot, id=slot_id)
session = get_session(slot)
if request.method == 'POST': if request.method == 'POST':
button_text = request.POST.get('submit', '') button_text = request.POST.get('submit', '')
@ -490,7 +496,7 @@ def non_session_edit(request, meeting_id, slot_id):
url = reverse('meetings_non_session', kwargs={'meeting_id':meeting_id}) url = reverse('meetings_non_session', kwargs={'meeting_id':meeting_id})
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
form = NonSessionEditForm(request.POST,meeting=meeting, session=slot.session) form = NonSessionEditForm(request.POST,meeting=meeting, session=session)
if form.is_valid(): if form.is_valid():
location = form.cleaned_data['location'] location = form.cleaned_data['location']
group = form.cleaned_data['group'] group = form.cleaned_data['group']
@ -500,7 +506,6 @@ def non_session_edit(request, meeting_id, slot_id):
slot.name = name slot.name = name
slot.save() slot.save()
# save group to session object # save group to session object
session = slot.session
session.group = group session.group = group
session.name = name session.name = name
session.short = short session.short = short
@ -514,10 +519,10 @@ def non_session_edit(request, meeting_id, slot_id):
# we need to pass the session to the form in order to disallow changing # we need to pass the session to the form in order to disallow changing
# of group after materials have been uploaded # of group after materials have been uploaded
initial = {'location':slot.location, initial = {'location':slot.location,
'group':slot.session.group, 'group':session.group,
'name':slot.session.name, 'name':session.name,
'short':slot.session.short} 'short':session.short}
form = NonSessionEditForm(meeting=meeting,session=slot.session,initial=initial) form = NonSessionEditForm(meeting=meeting,session=session,initial=initial)
return render_to_response('meetings/non_session_edit.html', { return render_to_response('meetings/non_session_edit.html', {
'meeting': meeting, 'meeting': meeting,
@ -538,10 +543,10 @@ def remove_session(request, meeting_id, acronym):
now = datetime.datetime.now() now = datetime.datetime.now()
for session in sessions: for session in sessions:
for timeslot in session.timeslot_set.all(): ss = session.official_scheduledsession()
timeslot.session = None ss.session = None
timeslot.modified = now ss.modified = now
timeslot.save() ss.save()
session.status_id = 'canceled' session.status_id = 'canceled'
session.modified = now session.modified = now
session.save() session.save()
@ -610,11 +615,12 @@ def schedule(request, meeting_id, acronym):
for s in sessions: for s in sessions:
d = {'session':s.id, d = {'session':s.id,
'note':s.agenda_note} 'note':s.agenda_note}
qs = s.timeslot_set.all() timeslot = get_timeslot(s)
if qs:
d['room'] = qs[0].location.id if timeslot:
d['day'] = qs[0].time.isoweekday() % 7 + 1 # adjust to django week_day d['room'] = timeslot.location.id
d['time'] = qs[0].time.strftime('%H%M') d['day'] = timeslot.time.isoweekday() % 7 + 1 # adjust to django week_day
d['time'] = timeslot.time.strftime('%H%M')
else: else:
d['day'] = 2 # default d['day'] = 2 # default
if is_combined(s,meeting): if is_combined(s,meeting):
@ -647,35 +653,24 @@ def schedule(request, meeting_id, acronym):
day = form.cleaned_data['day'] day = form.cleaned_data['day']
combine = form.cleaned_data.get('combine',None) combine = form.cleaned_data.get('combine',None)
session = Session.objects.get(id=id) session = Session.objects.get(id=id)
was_combined = is_combined(session) initial_timeslot = get_timeslot(session)
initial_timeslots = session.timeslot_set.all()
if initial_timeslots:
initial_timeslot = initial_timeslots[0]
else:
initial_timeslot = None
# find new timeslot # find new timeslot
new_day = meeting.date + datetime.timedelta(days=int(day)-1) new_day = meeting.date + datetime.timedelta(days=int(day)-1)
hour = datetime.time(int(time[:2]),int(time[2:])) hour = datetime.time(int(time[:2]),int(time[2:]))
new_time = datetime.datetime.combine(new_day,hour) new_time = datetime.datetime.combine(new_day,hour)
qs = TimeSlot.objects.filter(meeting=meeting,time=new_time,location=room) timeslot = TimeSlot.objects.filter(meeting=meeting,time=new_time,location=room)[0]
if qs.filter(session=None):
timeslot = qs.filter(session=None)[0]
else:
# we need to create another, identical timeslot
timeslot = TimeSlot.objects.create(meeting=qs[0].meeting,
type=qs[0].type,
name=qs[0].name,
time=qs[0].time,
duration=qs[0].duration,
location=qs[0].location,
show_location=qs[0].show_location,
modified=now)
messages.warning(request, 'WARNING: There are now two sessions scheduled for the timeslot: %s' % timeslot)
# COMBINE SECTION - BEFORE --------------
if 'combine' in form.changed_data and not combine:
next_slot = get_next_slot(initial_timeslot)
for ss in next_slot.scheduledsession_set.filter(schedule=meeting.agenda,session=session):
ss.session = None
ss.save()
# ---------------------------------------
if any(x in form.changed_data for x in ('day','time','room')): if any(x in form.changed_data for x in ('day','time','room')):
# clear the old timeslot(s) # clear the old association
for ts in initial_timeslots: if initial_timeslot:
# get SS record(s) and unschedule by removing the session reference # get SS record(s) and unschedule by removing the session reference
for ss in session.scheduledsession_set.filter(schedule=meeting.agenda): for ss in session.scheduledsession_set.filter(schedule=meeting.agenda):
ss.session = None ss.session = None
@ -696,16 +691,10 @@ def schedule(request, meeting_id, acronym):
session.modified = now session.modified = now
session.save() session.save()
# COMBINE SECTION ---------------------- # COMBINE SECTION - AFTER ---------------
if 'combine' in form.changed_data: if 'combine' in form.changed_data and combine:
next_slot = get_next_slot(timeslot) next_slot = get_next_slot(timeslot)
if combine: assign(session,next_slot,meeting)
assign(session,next_slot,meeting)
else:
for ss in next_slot.scheduledsession_set.filter(schedule=meeting.agenda,session=session):
ss.session = None
ss.save()
# --------------------------------------- # ---------------------------------------
# notify. dont send if Tutorial, BOF or indicated on form # notify. dont send if Tutorial, BOF or indicated on form
@ -713,7 +702,7 @@ def schedule(request, meeting_id, acronym):
if (has_changed if (has_changed
and not extra_form.cleaned_data.get('no_notify',False) and not extra_form.cleaned_data.get('no_notify',False)
and group.state.slug != 'bof' and group.state.slug != 'bof'
and session.timeslot_set.all()): # and the session is scheduled, else skip and get_timeslot(session)): # and the session is scheduled, else skip
send_notification(request, sessions) send_notification(request, sessions)
notification_message = "Notification sent." notification_message = "Notification sent."
@ -724,6 +713,7 @@ def schedule(request, meeting_id, acronym):
url = reverse('meetings_select_group', kwargs={'meeting_id':meeting_id}) url = reverse('meetings_select_group', kwargs={'meeting_id':meeting_id})
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
else: else:
formset = NewSessionFormset(initial=initial) formset = NewSessionFormset(initial=initial)
extra_form = ExtraSessionForm() extra_form = ExtraSessionForm()
@ -856,9 +846,10 @@ def times_delete(request, meeting_id, time):
parts = [ int(x) for x in time.split(':') ] parts = [ int(x) for x in time.split(':') ]
dtime = datetime.datetime(*parts) dtime = datetime.datetime(*parts)
if ScheduledSession.objects.filter(timeslot__time=dtime, qs = meeting.agenda.scheduledsession_set.filter(timeslot__time=dtime,
timeslot__meeting=meeting, session__isnull=False)
session__isnull=False):
if qs:
messages.error(request, 'ERROR deleting timeslot. There is one or more sessions scheduled for this timeslot.') messages.error(request, 'ERROR deleting timeslot. There is one or more sessions scheduled for this timeslot.')
url = reverse('meetings_times', kwargs={'meeting_id':meeting_id}) url = reverse('meetings_times', kwargs={'meeting_id':meeting_id})
return HttpResponseRedirect(url) return HttpResponseRedirect(url)

View file

@ -14,7 +14,7 @@ from itertools import chain
from ietf.secr.proceedings.models import Registration from ietf.secr.proceedings.models import Registration
from ietf.secr.utils.document import get_rfc_num from ietf.secr.utils.document import get_rfc_num
from ietf.secr.utils.group import groups_by_session from ietf.secr.utils.group import groups_by_session
from ietf.secr.utils.meeting import get_upload_root, get_proceedings_path, get_material from ietf.secr.utils.meeting import get_upload_root, get_proceedings_path, get_material, get_session
from models import InterimMeeting # proxy model from models import InterimMeeting # proxy model
from urllib2 import urlopen from urllib2 import urlopen
@ -32,7 +32,8 @@ def mycomp(timeslot):
This takes a timeslot object and returns a key to sort by the area acronym or None This takes a timeslot object and returns a key to sort by the area acronym or None
''' '''
try: try:
group = timeslot.session.group session = get_session(timeslot)
group = session.group
key = '%s:%s' % (group.parent.acronym, group.acronym) key = '%s:%s' % (group.parent.acronym, group.acronym)
except AttributeError: except AttributeError:
key = None key = None
@ -528,7 +529,7 @@ def gen_research(context):
def gen_training(context): def gen_training(context):
meeting = context['meeting'] meeting = context['meeting']
timeslots = context['others'] timeslots = context['others']
sessions = [ t.session for t in timeslots ] sessions = [ get_session(t) for t in timeslots ]
for counter,session in enumerate(sessions, start=1): for counter,session in enumerate(sessions, start=1):
slides = session.materials.filter(type='slides') slides = session.materials.filter(type='slides')
minutes = session.materials.filter(type='minutes') minutes = session.materials.filter(type='minutes')

View file

@ -27,7 +27,7 @@ from ietf.group.models import Group
from ietf.group.proxy import IETFWG from ietf.group.proxy import IETFWG
from ietf.group.utils import get_charter_text from ietf.group.utils import get_charter_text
from ietf.ietfauth.decorators import has_role from ietf.ietfauth.decorators import has_role
from ietf.meeting.models import Meeting, Session, TimeSlot from ietf.meeting.models import Meeting, Session, TimeSlot, ScheduledSession
from ietf.name.models import MeetingTypeName, SessionStatusName from ietf.name.models import MeetingTypeName, SessionStatusName
from ietf.person.models import Person from ietf.person.models import Person
@ -685,22 +685,17 @@ def select(request, meeting_num):
# initialize Training form, this select widget needs to have a session id, because it's # initialize Training form, this select widget needs to have a session id, because it's
# utilmately the session that we associate material with # utilmately the session that we associate material with
# NOTE: there are two ways to query for the groups we want, the later seems more specific
if has_role(user,'Secretariat'): if has_role(user,'Secretariat'):
choices = [] ss = ScheduledSession.objects.filter(schedule=meeting.agenda,timeslot__type='other')
#for session in Session.objects.filter(meeting=meeting).exclude(name=""): choices = [ (i.session.id, i.session.name) for i in sorted(ss,key=lambda x: x.session.name) ]
for session in Session.objects.filter(meeting=meeting,timeslot__type='other').order_by('name'):
choices.append((session.id,session.timeslot_set.all()[0].name))
training_form = GroupSelectForm(choices=choices) training_form = GroupSelectForm(choices=choices)
else: else:
training_form = None training_form = None
# iniialize plenary form # iniialize plenary form
if has_role(user,['Secretariat','IETF Chair','IAB Chair']): if has_role(user,['Secretariat','IETF Chair','IAB Chair']):
choices = [] ss = ScheduledSession.objects.filter(schedule=meeting.agenda,timeslot__type='plenary')
for session in Session.objects.filter(meeting=meeting, choices = [ (i.session.id, i.session.name) for i in sorted(ss,key=lambda x: x.session.name) ]
timeslot__type='plenary').order_by('name'):
choices.append((session.id,session.timeslot_set.all()[0].name))
plenary_form = GroupSelectForm(choices=choices) plenary_form = GroupSelectForm(choices=choices)
else: else:
plenary_form = None plenary_form = None