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 $"

View file

@ -35,7 +35,8 @@ FROM_LIST = ('IETF Secretariat <ietf-secretariat@ietf.org>',
'RSOC Chair <rsoc-chair@iab.org>',
'ISOC Board of Trustees <eburger@standardstrack.com>',
'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>',
'I-D Announcement List <i-d-announce@ietf.org>',
@ -107,12 +108,16 @@ def get_from_choices(user):
group__acronym='iab',
name='execdir'):
f = (FROM_LIST[6],FROM_LIST[16])
elif Role.objects.filter(person=person,
group__acronym='mentor',
name="chair"):
f = (FROM_LIST[17],)
# NomCom
nomcoms = Role.objects.filter(name="chair",
group__acronym__startswith="nomcom",
group__state="active",
group__type="ietf",
group__type="nomcom",
person=person)
if nomcoms:
year = nomcoms[0].group.acronym[-4:]
@ -141,7 +146,7 @@ TO_CHOICES = get_to_choices()
class AnnounceForm(forms.ModelForm):
#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='')
#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
'''
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,
group__acronym__in=groups_with_access,
name="chair") or has_role(user, ["Secretariat","IAD"]):
@ -31,7 +31,7 @@ def check_access(user):
if Role.objects.filter(name="chair",
group__acronym__startswith="nomcom",
group__state="active",
group__type="ietf",
group__type="nomcom",
person=person):
return True
if Role.objects.filter(person=person,

View file

@ -146,7 +146,7 @@ class NewSessionForm(forms.Form):
time_obj = datetime.datetime.combine(day_obj,hour)
slot = TimeSlot.objects.get(meeting=self.meeting,time=time_obj,location=room)
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')
return cleaned_data

View file

@ -12,7 +12,7 @@ from django.utils.functional import curry
from django.utils import simplejson
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.group.models import Group
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.views import get_initial_session, session_conflicts_as_string
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 *
@ -106,6 +106,8 @@ def build_nonsession(meeting):
last_meeting = get_last_meeting(meeting)
delta = meeting.date - last_meeting.date
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')):
new_time = slot.time + delta
session = None
@ -119,9 +121,8 @@ def build_nonsession(meeting):
status_id='sched')
session.save()
TimeSlot.objects.create(type=slot.type,
ts = TimeSlot.objects.create(type=slot.type,
meeting=meeting,
session=session,
name=slot.name,
time=new_time,
duration=slot.duration,
@ -136,7 +137,7 @@ def is_combined(session):
'''
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
else:
return False
@ -175,7 +176,7 @@ def send_notification(request, sessions):
# easier to populate template from timeslot perspective. assuming one-to-one timeslot-session
count = 0
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:
count += 1
session_info += session_info_template.format(group.acronym,
@ -204,8 +205,7 @@ def send_notification(request, sessions):
def sort_groups(meeting):
'''
Similar to sreq.views.sort_groups
Takes a Django User object and a Meeting object
Returns a tuple scheduled_groups, unscheduled groups.
Takes a Meeting object and returns a tuple scheduled_groups, unscheduled groups.
'''
scheduled_groups = []
unscheduled_groups = []
@ -418,6 +418,14 @@ def non_session(request, meeting_id):
t = meeting.date + datetime.timedelta(days=int(day))
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
# NOTE: we're setting group to none here, but the set_room page will force user
# to pick a legitimate group
@ -431,14 +439,10 @@ def non_session(request, meeting_id):
status_id='sched')
session.save()
# create TimeSlot object
TimeSlot.objects.create(type=form.cleaned_data['type'],
meeting=meeting,
# create association
ScheduledSession.objects.create(timeslot=timeslot,
session=session,
name=name,
time=new_time,
duration=duration,
show_location=form.cleaned_data['show_location'])
schedule=meeting.agenda)
messages.success(request, 'Non-Sessions updated successfully')
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)
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)
url = reverse('meetings_non_session', kwargs={'meeting_id':meeting_id})
return HttpResponseRedirect(url)
else:
slot.session.delete()
slot.sessions.all().delete()
slot.delete()
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)
slot = get_object_or_404(TimeSlot, id=slot_id)
session = get_session(slot)
if request.method == 'POST':
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})
return HttpResponseRedirect(url)
form = NonSessionEditForm(request.POST,meeting=meeting, session=slot.session)
form = NonSessionEditForm(request.POST,meeting=meeting, session=session)
if form.is_valid():
location = form.cleaned_data['location']
group = form.cleaned_data['group']
@ -500,7 +506,6 @@ def non_session_edit(request, meeting_id, slot_id):
slot.name = name
slot.save()
# save group to session object
session = slot.session
session.group = group
session.name = name
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
# of group after materials have been uploaded
initial = {'location':slot.location,
'group':slot.session.group,
'name':slot.session.name,
'short':slot.session.short}
form = NonSessionEditForm(meeting=meeting,session=slot.session,initial=initial)
'group':session.group,
'name':session.name,
'short':session.short}
form = NonSessionEditForm(meeting=meeting,session=session,initial=initial)
return render_to_response('meetings/non_session_edit.html', {
'meeting': meeting,
@ -538,10 +543,10 @@ def remove_session(request, meeting_id, acronym):
now = datetime.datetime.now()
for session in sessions:
for timeslot in session.timeslot_set.all():
timeslot.session = None
timeslot.modified = now
timeslot.save()
ss = session.official_scheduledsession()
ss.session = None
ss.modified = now
ss.save()
session.status_id = 'canceled'
session.modified = now
session.save()
@ -610,11 +615,12 @@ def schedule(request, meeting_id, acronym):
for s in sessions:
d = {'session':s.id,
'note':s.agenda_note}
qs = s.timeslot_set.all()
if qs:
d['room'] = qs[0].location.id
d['day'] = qs[0].time.isoweekday() % 7 + 1 # adjust to django week_day
d['time'] = qs[0].time.strftime('%H%M')
timeslot = get_timeslot(s)
if timeslot:
d['room'] = timeslot.location.id
d['day'] = timeslot.time.isoweekday() % 7 + 1 # adjust to django week_day
d['time'] = timeslot.time.strftime('%H%M')
else:
d['day'] = 2 # default
if is_combined(s,meeting):
@ -647,35 +653,24 @@ def schedule(request, meeting_id, acronym):
day = form.cleaned_data['day']
combine = form.cleaned_data.get('combine',None)
session = Session.objects.get(id=id)
was_combined = is_combined(session)
initial_timeslots = session.timeslot_set.all()
if initial_timeslots:
initial_timeslot = initial_timeslots[0]
else:
initial_timeslot = None
initial_timeslot = get_timeslot(session)
# find new timeslot
new_day = meeting.date + datetime.timedelta(days=int(day)-1)
hour = datetime.time(int(time[:2]),int(time[2:]))
new_time = datetime.datetime.combine(new_day,hour)
qs = TimeSlot.objects.filter(meeting=meeting,time=new_time,location=room)
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)
timeslot = TimeSlot.objects.filter(meeting=meeting,time=new_time,location=room)[0]
# 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')):
# clear the old timeslot(s)
for ts in initial_timeslots:
# clear the old association
if initial_timeslot:
# get SS record(s) and unschedule by removing the session reference
for ss in session.scheduledsession_set.filter(schedule=meeting.agenda):
ss.session = None
@ -696,16 +691,10 @@ def schedule(request, meeting_id, acronym):
session.modified = now
session.save()
# COMBINE SECTION ----------------------
if 'combine' in form.changed_data:
# COMBINE SECTION - AFTER ---------------
if 'combine' in form.changed_data and combine:
next_slot = get_next_slot(timeslot)
if combine:
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
@ -713,7 +702,7 @@ def schedule(request, meeting_id, acronym):
if (has_changed
and not extra_form.cleaned_data.get('no_notify',False)
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)
notification_message = "Notification sent."
@ -724,6 +713,7 @@ def schedule(request, meeting_id, acronym):
url = reverse('meetings_select_group', kwargs={'meeting_id':meeting_id})
return HttpResponseRedirect(url)
else:
formset = NewSessionFormset(initial=initial)
extra_form = ExtraSessionForm()
@ -856,9 +846,10 @@ def times_delete(request, meeting_id, time):
parts = [ int(x) for x in time.split(':') ]
dtime = datetime.datetime(*parts)
if ScheduledSession.objects.filter(timeslot__time=dtime,
timeslot__meeting=meeting,
session__isnull=False):
qs = meeting.agenda.scheduledsession_set.filter(timeslot__time=dtime,
session__isnull=False)
if qs:
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})
return HttpResponseRedirect(url)

View file

@ -14,7 +14,7 @@ from itertools import chain
from ietf.secr.proceedings.models import Registration
from ietf.secr.utils.document import get_rfc_num
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 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
'''
try:
group = timeslot.session.group
session = get_session(timeslot)
group = session.group
key = '%s:%s' % (group.parent.acronym, group.acronym)
except AttributeError:
key = None
@ -528,7 +529,7 @@ def gen_research(context):
def gen_training(context):
meeting = context['meeting']
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):
slides = session.materials.filter(type='slides')
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.utils import get_charter_text
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.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
# 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'):
choices = []
#for session in Session.objects.filter(meeting=meeting).exclude(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))
ss = ScheduledSession.objects.filter(schedule=meeting.agenda,timeslot__type='other')
choices = [ (i.session.id, i.session.name) for i in sorted(ss,key=lambda x: x.session.name) ]
training_form = GroupSelectForm(choices=choices)
else:
training_form = None
# iniialize plenary form
if has_role(user,['Secretariat','IETF Chair','IAB Chair']):
choices = []
for session in Session.objects.filter(meeting=meeting,
timeslot__type='plenary').order_by('name'):
choices.append((session.id,session.timeslot_set.all()[0].name))
ss = ScheduledSession.objects.filter(schedule=meeting.agenda,timeslot__type='plenary')
choices = [ (i.session.id, i.session.name) for i in sorted(ss,key=lambda x: x.session.name) ]
plenary_form = GroupSelectForm(choices=choices)
else:
plenary_form = None