modifications to support agenda tool db changes

- Legacy-Id: 5762
This commit is contained in:
Ryan Cross 2013-05-28 17:48:07 +00:00
parent adb9164653
commit c9e2955d75
5 changed files with 143 additions and 104 deletions

View file

@ -90,7 +90,7 @@ class TimeChoiceField(forms.ChoiceField):
class MeetingModelForm(forms.ModelForm):
class Meta:
model = Meeting
exclude = ('type')
exclude = ('type','agenda')
def clean_number(self):
number = self.cleaned_data['number']

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.group.models import Group
from ietf.name.models import SessionStatusName, TimeSlotTypeName
from ietf.person.models import Person
@ -21,7 +21,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 *
@ -31,7 +31,7 @@ import datetime
# --------------------------------------------------
# Helper Functions
# --------------------------------------------------
def build_timeslots(meeting,room=None):
def build_timeslots(request,meeting,room=None):
'''
This function takes a Meeting object and an optional room argument. If room isn't passed we
pre-create the full set of timeslot records using the last meeting as a template.
@ -62,14 +62,14 @@ def build_timeslots(meeting,room=None):
for t in timeslots:
new_time = t.time + delta
for room in rooms:
TimeSlot.objects.create(type_id='session',
ts = TimeSlot.objects.create(type_id='session',
meeting=meeting,
name=t.name,
time=new_time,
location=room,
duration=t.duration)
def build_nonsession(meeting):
def build_nonsession(request, meeting):
'''
This function takes a meeting object and creates non-session records
for a new meeting, based on the last meeting
@ -77,6 +77,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
@ -84,29 +86,51 @@ def build_nonsession(meeting):
if slot.type.slug in ('other','plenary'):
session = Session(meeting=meeting,
name=slot.name,
short=slot.session.short,
group=slot.session.group,
short=get_session(slot).short,
group=get_session(slot).group,
requested_by=system,
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,
show_location=slot.show_location)
ScheduledSession.create(schedule=schedule,
session=session,
timeslot=ts)
def get_last_meeting(meeting):
last_number = int(meeting.number) - 1
return Meeting.objects.get(number=last_number)
def get_schedule(request,meeting):
'''
This function takes a Request object and Meeting object and returns the Official
Schdeule for the meeting. It will create the Schedule if it doesn't already
exist. Call this function after creating a new meeting.
'''
schedule = meeting.agenda
if schedule is None:
name = "mtg:%s" % meeting.number
person = request.user.get_profile()
schedule, created = Schedule.objects.get_or_create(meeting=meeting,
name=name,
defaults={'owner':person,
'visible':True,
'public':True})
meeting.agenda = schedule
meeting.save()
return schedule
def is_combined(session):
def is_combined(session, meeting):
'''
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
@ -125,7 +149,8 @@ def make_directories(meeting):
def send_notification(request, sessions):
'''
This view generates notifications for schedule sessions
This view generates notifications for schedule sessions. It takes an HttpRequest object and
a query set, sessions, consisting of one or more sessions scheduled for a particular group.
'''
session_info_template = '''{0} Session {1} ({2})
{3}, {4} {5}
@ -145,7 +170,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,
@ -174,18 +199,18 @@ 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 = []
#sessions = Session.objects.filter(meeting=meeting,status__in=('schedw','apprw','appr','sched','notmeet','canceled'))
sessions = Session.objects.filter(meeting=meeting,status__in=('schedw','apprw','appr','sched','canceled'))
groups_with_sessions = [ s.group for s in sessions ]
groups_with_sessions = [ s.group for s in sessions if s.group.type.slug in ('wg','rg','ag') ]
gset = set(groups_with_sessions)
sorted_groups_with_sessions = sorted(gset, key = lambda instance: instance.acronym)
slots = TimeSlot.objects.filter(meeting=meeting,session__isnull=False)
groups_with_timeslots = [ s.session.group for s in slots ]
slots = TimeSlot.objects.filter(meeting=meeting,
scheduledsession__schedule=meeting.agenda,
scheduledsession__session__isnull=False)
groups_with_timeslots = [ get_session(s).group for s in slots ]
for group in sorted_groups_with_sessions:
if group in groups_with_timeslots:
scheduled_groups.append(group)
@ -237,6 +262,9 @@ def add(request):
if form.is_valid():
meeting = form.save()
#Create initial Official schedule
get_schedule(request,meeting)
#Create Physical new meeting directory and subdirectories
make_directories(meeting)
@ -371,7 +399,7 @@ def non_session(request, meeting_id):
# if the Break/Registration records don't exist yet (new meeting) create them
if not TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other')):
build_nonsession(meeting)
build_nonsession(request, meeting)
slots = TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other','plenary')).order_by('-type__name','time')
@ -388,6 +416,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
@ -401,15 +437,11 @@ def non_session(request, meeting_id):
status_id='sched')
session.save()
# create TimeSlot object
TimeSlot.objects.create(type=form.cleaned_data['type'],
meeting=meeting,
session=session,
name=name,
time=new_time,
duration=duration,
show_location=form.cleaned_data['show_location'])
# create association
ScheduledSession.objects.create(timeslot=timeslot,
session=session,
schedule=meeting.agenda)
messages.success(request, 'Non-Sessions updated successfully')
url = reverse('meetings_non_session', kwargs={'meeting_id':meeting_id})
return HttpResponseRedirect(url)
@ -434,13 +466,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')
@ -453,14 +486,15 @@ 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', '')
if button_text == 'Cancel':
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']
@ -470,7 +504,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
@ -484,10 +517,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,
@ -508,10 +541,10 @@ def remove_session(request, meeting_id, acronym):
now = datetime.datetime.now()
for session in sessions:
timeslot = session.timeslot_set.all()[0]
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()
@ -543,14 +576,14 @@ def rooms(request, meeting_id):
# if we are creating rooms for the first time create full set of timeslots
if first_time:
build_timeslots(meeting)
build_timeslots(request, meeting)
# otherwise if we're modifying rooms
else:
# add timeslots for new rooms, deleting rooms automatically deletes timeslots
for form in formset.forms[formset.initial_form_count():]:
if form.instance.pk:
build_timeslots(meeting,room=form.instance)
build_timeslots(request, meeting,room=form.instance)
messages.success(request, 'Meeting Rooms changed successfully')
url = reverse('meetings_rooms', kwargs={'meeting_id':meeting_id})
@ -580,14 +613,16 @@ 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
if is_combined(s):
if is_combined(s,meeting):
d['combine'] = True
initial.append(d)
@ -617,49 +652,28 @@ def schedule(request, meeting_id, acronym):
day = form.cleaned_data['day']
combine = form.cleaned_data.get('combine',None)
session = Session.objects.get(id=id)
if session.timeslot_set.all():
initial_timeslot = session.timeslot_set.all()[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]
if any(x in form.changed_data for x in ('day','time','room')):
# clear the old timeslot
# clear the old association
if initial_timeslot:
# if the initial timeslot is one of multiple we should delete it
tqs = TimeSlot.objects.filter(meeting=meeting,
type='session',
time=initial_timeslot.time,
location=initial_timeslot.location)
if tqs.count() > 1:
initial_timeslot.delete()
else:
initial_timeslot.session = None
initial_timeslot.modified = now
initial_timeslot.save()
initial_timeslot.scheduledsession_set.filter(schedule=meeting.agenda,session=session).delete()
if timeslot:
timeslot.session = session
timeslot.modified = now
timeslot.save()
# create association
ScheduledSession.objects.create(schedule=meeting.agenda,
session=session,
timeslot=timeslot)
if timeslot.sessions.all().count() > 1:
messages.warning(request, 'WARNING: There are now two sessions scheduled for the timeslot: %s' % timeslot)
session.status_id = 'sched'
else:
session.status_id = 'schedw'
@ -675,11 +689,12 @@ def schedule(request, meeting_id, acronym):
if 'combine' in form.changed_data:
next_slot = get_next_slot(timeslot)
if combine:
next_slot.session = session
ScheduledSession.objects.create(schedule=meeting.agenda,
session=session,
timeslot=next_slot)
else:
next_slot.session = None
next_slot.modified = now
next_slot.save()
next_slot.scheduledsession_set.filter(schedule=meeting.agenda,session=session).delete()
# ---------------------------------------
# notify. dont send if Tutorial, BOF or indicated on form
@ -687,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."
@ -711,7 +726,7 @@ def schedule(request, meeting_id, acronym):
'formset': formset},
RequestContext(request, {}),
)
def select_group(request, meeting_id):
'''
In this view the user can select the group to schedule. Only those groups that have
@ -791,7 +806,6 @@ def times(request, meeting_id):
new_time = datetime.datetime(t.year,t.month,t.day,time.hour,time.minute)
# don't allow creation of timeslots with same start time as existing timeslots
# assert False, (new_time, time_seen)
if new_time in time_seen:
messages.error(request, 'There is already a timeslot for %s. To change you must delete the old one first.' % new_time.strftime('%a %H:%M'))
url = reverse('meetings_times', kwargs={'meeting_id':meeting_id})
@ -829,7 +843,10 @@ def times_delete(request, meeting_id, time):
parts = [ int(x) for x in time.split(':') ]
dtime = datetime.datetime(*parts)
if Session.objects.filter(timeslot__time=dtime,timeslot__meeting=meeting):
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, get_timeslot
from models import InterimMeeting # proxy model
from urllib2 import urlopen
@ -32,7 +32,7 @@ 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
group = get_session(timeslot).group
key = '%s:%s' % (group.parent.acronym, group.acronym)
except AttributeError:
key = None

View file

@ -202,14 +202,8 @@ def cancel(request, acronym):
session.status_id = 'deleted'
session.save()
# clear timeslot assignment if already scheduled
if session.timeslot_set.all():
timeslot = session.timeslot_set.all()[0]
timeslot.session = None
timeslot.save()
# log activity
#add_session_activity(group,'Session was cancelled',meeting,user)
# clear schedule assignments if already scheduled
session.scheduledsession_set.all().delete()
# send notifitcation
to_email = SESSION_REQUEST_EMAIL

View file

@ -1,5 +1,5 @@
from django.conf import settings
from ietf.meeting.models import Meeting
from ietf.meeting.models import Meeting, Session, Schedule, TimeSlot
import os
@ -28,6 +28,34 @@ def get_proceedings_path(meeting, group):
path = os.path.join(get_upload_root(meeting),'%s.html' % group.acronym)
return path
def get_session(timeslot, schedule=None):
'''
Helper function to get the session given a timeslot, assume Official schedule if one isn't
provided. Replaces "timeslot.session"
'''
# todo, doesn't account for shared timeslot
if not schedule:
schedule = timeslot.meeting.agenda
qs = timeslot.sessions.filter(scheduledsession__schedule=schedule) #.exclude(states__slug='deleted')
if qs:
return qs[0]
else:
return None
def get_timeslot(session, schedule=None):
'''
Helper function to get the timeslot associated with a session. Created for Agenda Tool
db schema changes. Use this function in place of session.timeslot_set.all()[0]. Don't specify
schedule to use the meeting "official" schedule.
'''
if not schedule:
schedule = session.meeting.agenda
ss = session.scheduledsession_set.filter(schedule=schedule)
if ss:
return ss[0].timeslot
else:
return None
def get_upload_root(meeting):
path = ''
if meeting.type.slug == 'ietf':