merging forward

- Legacy-Id: 10738
This commit is contained in:
Robert Sparks 2016-01-26 21:18:55 +00:00
commit 12ed190fd3
28 changed files with 466 additions and 157 deletions

View file

@ -475,7 +475,8 @@ def email_charter_internal_review(request, charter):
charter_url=settings.IDTRACKER_BASE_URL + charter.get_absolute_url(),
chairs=charter.group.role_set.filter(name="chair"),
secr=charter.group.role_set.filter(name="secr"),
ads=charter.group.role_set.filter(name='ad').values_list('person__name',flat=True),
ads=charter.group.role_set.filter(name='ad'),
parent_ads=charter.group.parent.role_set.filter(name='ad'),
techadv=charter.group.role_set.filter(name="techadv"),
milestones=charter.group.groupmilestone_set.filter(state="charter"),
),

View file

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
from django.db.models import F
def reverse(apps, schema_editor):
pass
def forward(apps, schema_editor):
Document = apps.get_model('doc','Document')
for doc in Document.objects.filter(type__in=['recording','liaison','liai-att']).exclude(docalias__name=F('name')):
doc.docalias_set.create(name=doc.name)
class Migration(migrations.Migration):
dependencies = [
('doc', '0010_auto_20150930_0251'),
]
operations = [
migrations.RunPython(forward,reverse)
]

View file

@ -234,7 +234,7 @@ class DocumentInfo(models.Model):
def meeting_related(self):
answer = False
if self.type_id in ("agenda","minutes","bluesheets","slides"):
if self.type_id in ("agenda","minutes","bluesheets","slides","recording"):
answer = (self.name.split("-")[1] == "interim"
or (self if isinstance(self, Document) else self.doc).session_set.exists())
if self.type_id in ("slides",):

View file

@ -558,6 +558,9 @@ Man Expires September 22, 2015 [Page 3]
"agenda-42-mars",
"minutes-42-mars",
"slides-42-mars-1",
# TODO: add
#"bluesheets-42-mars-1",
#"recording-42-mars-1-00",
]:
doc = Document.objects.get(name=docname)
# give it some history

View file

@ -111,7 +111,7 @@ class EditCharterTests(TestCase):
for word in ["Chairs", "Ames Man <ameschairman@ietf.org>",
"Secretaries", "Secretary <amessecretary@ietf.org>",
"Assigned Area Director", "Areað Irector <aread@ietf.org>",
"Area Directors", "Mailing list", "ames-wg@ietf.org",
"Mailing list", "ames-wg@ietf.org",
"Charter", "Milestones"]:
self.assertIn(word, body)

View file

@ -111,6 +111,8 @@ def default_action_text(group, charter, by):
chairs=group.role_set.filter(name="chair"),
secr=group.role_set.filter(name="secr"),
techadv=group.role_set.filter(name="techadv"),
ads=group.role_set.filter(name='ad'),
parent_ads=group.parent.role_set.filter(name='ad'),
milestones=group.groupmilestone_set.filter(state="charter"),
action_type=action,
to=addrs.to,
@ -145,6 +147,8 @@ def default_review_text(group, charter, by):
charter_text=read_charter_text(charter),
chairs=group.role_set.filter(name="chair"),
secr=group.role_set.filter(name="secr"),
ads=group.role_set.filter(name='ad'),
parent_ads=group.parent.role_set.filter(name='ad'),
techadv=group.role_set.filter(name="techadv"),
milestones=group.groupmilestone_set.filter(state="charter"),
review_date=(datetime.date.today() + datetime.timedelta(weeks=1)).isoformat(),

View file

@ -522,6 +522,8 @@ def document_main(request, name, rev=None):
),
context_instance=RequestContext(request))
# TODO : Add "recording", and "bluesheets" here when those documents are appropriately
# created and content is made available on disk
if doc.type_id in ("slides", "agenda", "minutes"):
can_manage_material = can_manage_materials(request.user, doc.group)
presentations = None

View file

@ -70,7 +70,7 @@ class SearchForm(forms.Form):
sort = forms.ChoiceField(choices=(("document", "Document"), ("title", "Title"), ("date", "Date"), ("status", "Status"), ("ipr", "Ipr"), ("ad", "AD")), required=False, widget=forms.HiddenInput)
doctypes = DocTypeName.objects.exclude(slug='draft').order_by('name');
doctypes = DocTypeName.objects.filter(used=True).exclude(slug='draft').order_by('name');
def __init__(self, *args, **kwargs):
super(SearchForm, self).__init__(*args, **kwargs)

View file

@ -36,6 +36,7 @@ import os
import itertools
import re
from tempfile import mkstemp
import datetime
from collections import OrderedDict
from django.shortcuts import render, redirect
@ -333,6 +334,8 @@ def construct_group_menu_context(request, group, selected, group_type, others):
entries.append(("About", urlreverse("group_about", kwargs=kwargs)))
if group.features.has_materials and get_group_materials(group).exists():
entries.append(("Materials", urlreverse("ietf.group.info.materials", kwargs=kwargs)))
if group.type_id in ('rg','wg'):
entries.append(("Meetings", urlreverse("ietf.group.info.meetings", kwargs=kwargs)))
entries.append(("Email expansions", urlreverse("ietf.group.info.email", kwargs=kwargs)))
entries.append(("History", urlreverse("ietf.group.info.history", kwargs=kwargs)))
if group.features.has_documents:
@ -724,3 +727,47 @@ def email_aliases(request, acronym=None, group_type=None):
return render(request,'group/email_aliases.html',{'aliases':aliases,'ietf_domain':settings.IETF_DOMAIN,'group':group})
def meetings(request, acronym=None, group_type=None):
group = get_group_or_404(acronym,group_type) if acronym else None
four_years_ago = datetime.datetime.now()-datetime.timedelta(days=4*365)
sessions = group.session_set.filter(status__in=['sched','schedw','appr','canceled'],meeting__date__gt=four_years_ago)
def sort_key(session):
if session.meeting.type.slug=='ietf':
official_sessions = session.timeslotassignments.filter(schedule=session.meeting.agenda)
if official_sessions:
return official_sessions.first().timeslot.time
elif session.meeting.date:
return datetime.datetime.combine(session.meeting.date,datetime.datetime.min.time())
else:
return session.requested
else:
# TODO: use timeslots for interims once they have them
return datetime.datetime.combine(session.meeting.date,datetime.datetime.min.time())
for s in sessions:
s.time=sort_key(s)
sessions = sorted(sessions,key=lambda s:s.time,reverse=True)
today = datetime.date.today()
future = []
in_progress = []
past = []
for s in sessions:
if s.meeting.date > today:
future.append(s)
elif s.meeting.end_date() >= today:
in_progress.append(s)
else:
past.append(s)
return render(request,'group/meetings.html',
construct_group_menu_context(request, group, "meetings", group_type, {
'group':group,
'future':future,
'in_progress':in_progress,
'past':past,
}))

View file

@ -22,6 +22,8 @@ from ietf.utils.test_utils import TestCase, unicontent
from ietf.utils.mail import outbox, empty_outbox
from ietf.utils.test_data import make_test_data
from ietf.utils.test_utils import login_testing_unauthorized
from ietf.group.factories import GroupFactory
from ietf.meeting.factories import SessionFactory
class GroupPagesTests(TestCase):
def setUp(self):
@ -988,3 +990,29 @@ class AjaxTests(TestCase):
mars_wg = Group.objects.get(acronym="mars")
self.assertEqual(mars_wg_data["name"], mars_wg.name)
class MeetingInfoTests(TestCase):
def setUp(self):
self.group = GroupFactory.create(type_id='wg')
today = datetime.date.today()
SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today-datetime.timedelta(days=90))
self.inprog = SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today-datetime.timedelta(days=1))
SessionFactory.create(meeting__type_id='ietf',group=self.group,meeting__date=today+datetime.timedelta(days=90))
SessionFactory.create(meeting__type_id='interim',group=self.group,meeting__date=today+datetime.timedelta(days=45))
def test_meeting_info(self):
url = urlreverse('ietf.group.info.meetings',kwargs={'acronym':self.group.acronym})
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
q = PyQuery(response.content)
self.assertTrue(q('#inprogressmeets'))
self.assertTrue(q('#futuremeets'))
self.assertTrue(q('#pastmeets'))
self.group.session_set.filter(id=self.inprog.id).delete()
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
q = PyQuery(response.content)
self.assertFalse(q('#inprogressmeets'))

View file

@ -10,7 +10,6 @@ urlpatterns = patterns('',
(r'^chartering/create/(?P<group_type>(wg|rg))/$', 'ietf.group.edit.edit', {'action': "charter"}, "group_create"),
(r'^concluded/$', 'ietf.group.info.concluded_groups'),
(r'^email-aliases/$', 'ietf.group.info.email_aliases'),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/$', 'ietf.group.info.group_home', None, "group_home"),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/', include('ietf.group.urls_info_details')),
)

View file

@ -10,6 +10,7 @@ urlpatterns = patterns('',
(r'^history/$','ietf.group.info.history'),
(r'^email/$', 'ietf.group.info.email'),
(r'^deps/(?P<output_type>[\w-]+)/$', 'ietf.group.info.dependencies'),
(r'^meetings/$', 'ietf.group.info.meetings'),
(r'^init-charter/', 'ietf.group.edit.submit_initial_charter'),
(r'^edit/$', 'ietf.group.edit.edit', {'action': "edit"}, "group_edit"),
(r'^conclude/$', 'ietf.group.edit.conclude'),

View file

@ -346,7 +346,7 @@ class LiaisonModelForm(BetterModelForm):
extension = ''
written += 1
name = self.instance.name() + ("-attachment-%s" % written)
attach, _ = Document.objects.get_or_create(
attach, created = Document.objects.get_or_create(
name = name,
defaults=dict(
title = attachment_title,
@ -354,6 +354,8 @@ class LiaisonModelForm(BetterModelForm):
external_url = name + extension, # strictly speaking not necessary, but just for the time being ...
)
)
if created:
attach.docalias_set.create(name=attach.name)
LiaisonStatementAttachment.objects.create(statement=self.instance,document=attach)
attach_file = open(os.path.join(settings.LIAISON_ATTACH_PATH, attach.name + extension), 'w')
attach_file.write(attached_file.read())

99
ietf/meeting/factories.py Normal file
View file

@ -0,0 +1,99 @@
import factory
import random
import datetime
from django.db.models import Max
from ietf.meeting.models import Meeting, Session, Schedule, TimeSlot
from ietf.group.factories import GroupFactory
from ietf.person.factories import PersonFactory
class MeetingFactory(factory.DjangoModelFactory):
class Meta:
model = Meeting
type_id = factory.Iterator(['ietf','interim'])
date = datetime.date(2010,1,1)+datetime.timedelta(days=random.randint(0,3652))
city = factory.Faker('city')
country = factory.Faker('country_code')
time_zone = factory.Faker('timezone')
idsubmit_cutoff_day_offset_00 = 13
idsubmit_cutoff_day_offset_01 = 13
idsubmit_cutoff_time_utc = datetime.timedelta(0, 86399)
idsubmit_cutoff_warning_days = 21
venue_name = factory.Faker('sentence')
venue_addr = factory.Faker('address')
break_area = factory.Faker('sentence')
reg_area = factory.Faker('sentence')
@factory.lazy_attribute_sequence
def number(self,n):
if self.type_id == 'ietf':
if Meeting.objects.filter(type='ietf').exists():
return '%02d'%(int(Meeting.objects.filter(type='ietf').aggregate(Max('number'))['number__max'])+1)
else:
return '%02d'%(n+80)
else:
return 'interim-%d-%s-%d'%(self.date.year,GroupFactory().acronym,n)
@factory.post_generation
def populate_agenda(self, create, extracted, **kwargs):
'''
Create a default agenda, unless the factory is called
with populate_agenda=False
'''
if extracted is None:
extracted = True
if create and extracted:
for x in range(3):
TimeSlotFactory(meeting=self)
self.agenda = ScheduleFactory(meeting=self)
self.save()
class SessionFactory(factory.DjangoModelFactory):
class Meta:
model = Session
meeting = factory.SubFactory(MeetingFactory)
type_id='session'
group = factory.SubFactory(GroupFactory)
requested_by = factory.SubFactory(PersonFactory)
status_id='sched'
@factory.post_generation
def add_to_schedule(self, create, extracted, **kwargs):
'''
Put this session in a timeslot unless the factory is called
with add_to_schedule=False
'''
if extracted is None:
extracted = True
if create and extracted:
ts = self.meeting.timeslot_set.all()
self.timeslotassignments.create(timeslot=ts[random.randrange(len(ts))],schedule=self.meeting.agenda)
class ScheduleFactory(factory.DjangoModelFactory):
class Meta:
model = Schedule
meeting = factory.SubFactory(MeetingFactory)
name = factory.Faker('text',max_nb_chars=16)
owner = factory.SubFactory(PersonFactory)
class TimeSlotFactory(factory.DjangoModelFactory):
class Meta:
model = TimeSlot
meeting = factory.SubFactory(MeetingFactory)
type_id = 'session'
@factory.lazy_attribute
def time(self):
return datetime.datetime.combine(self.meeting.date,datetime.time(11,0))
@factory.lazy_attribute
def duration(self):
return datetime.timedelta(minutes=30+random.randrange(9)*15)

View file

@ -106,15 +106,18 @@ def get_wg_list(assignments):
return Group.objects.filter(acronym__in = set(wg_name_list)).order_by('parent__acronym','acronym')
def get_meetings(num=None):
def get_meetings(num=None,type_in=['ietf',]):
meetings = Meeting.objects
if type_in:
meetings = meetings.filter(type__in=type_in)
if num == None:
meetings = Meeting.objects.filter(type="ietf").order_by("-date")
meetings = meetings.order_by("-date")
else:
meetings = Meeting.objects.filter(type="ietf", number=num)
meetings = meetings.filter(number=num)
return meetings
def get_meeting(num=None):
meetings = get_meetings(num)
def get_meeting(num=None,type_in=['ietf',]):
meetings = get_meetings(num,type_in)
if meetings.exists():
return meetings.first()
else:

View file

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
def forward(apps, schema_editor):
Session = apps.get_model('meeting','Session')
assert(Session.objects.filter(meeting__number__in=['88','89'],group__type__in=['ag','iab','rg','wg'],status_id='sched').count() == 0)
Session.objects.filter(meeting__number__in=['88','89'],group__type__in=['ag','iab','rg','wg'],status_id='schedw').update(status_id='sched')
def reverse(apps, schema_editor):
Session = apps.get_model('meeting','Session')
Session.objects.filter(meeting__number__in=['88','89'],group__type__in=['ag','iab','rg','wg'],status_id='sched').update(status_id='schedw')
class Migration(migrations.Migration):
dependencies = [
('meeting', '0015_auto_20151102_1845'),
]
operations = [
migrations.RunPython(forward,reverse),
]

View file

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
from collections import Counter
affected = ['interim-2010-drinks-1','interim-2010-core-1','interim-2010-behave-1','interim-2010-siprec-1','interim-2010-cuss-1','interim-2010-iri-1','interim-2010-pcp-1','interim-2010-geopriv-1','interim-2010-soc-1','interim-2010-precis-1','interim-2010-mptcp-1','interim-2010-roll-1','interim-2011-sipclf-1','interim-2011-ipsecme-1','interim-2011-siprec-1','interim-2011-alto-1','interim-2011-xmpp-1','interim-2011-precis-1','interim-2011-nfsv4-1','interim-2011-pcp-1','interim-2011-clue-1','interim-2011-oauth-1','interim-2011-rtcweb-1','interim-2011-drinks-1','interim-2011-atoca-1','interim-2011-cuss-1','interim-2011-softwire-1','interim-2011-ppsp-1','interim-2011-homenet-1','interim-2011-mptcp-1','interim-2012-rtcweb-1','interim-2012-drinks-1','interim-2012-sidr-1','interim-2012-clue-1','interim-2012-krb-wg-1','interim-2012-behave-1','interim-2012-bfcpbis-1','interim-2012-mboned-1']
def forward(apps, schema_editor):
Session = apps.get_model('meeting','Session')
assert( Counter(Session.objects.filter(meeting__number__in=affected).values_list('status',flat=True)) == Counter({u'appr':38}) )
Session.objects.filter(meeting__number__in=affected).update(status_id='sched')
def reverse(apps, schema_editor):
Session = apps.get_model('meeting','Session')
Session.objects.filter(meeting__number__in=affected).update(status_id='appr')
class Migration(migrations.Migration):
dependencies = [
('meeting', '0016_schedule_ietf88_and_89'),
]
operations = [
migrations.RunPython(forward,reverse),
]

View file

@ -96,7 +96,12 @@ class Meeting(models.Model):
return self.date + datetime.timedelta(days=offset)
def end_date(self):
return self.get_meeting_date(5)
if self.type.slug == 'ietf':
return self.get_meeting_date(5)
else:
# TODO: Once interims have timeslots assigned,
# look for the last ending timeslot instead
return self.date
def get_00_cutoff(self):
start_date = datetime.datetime(year=self.date.year, month=self.date.month, day=self.date.day, tzinfo=pytz.utc)

View file

@ -1,74 +1,71 @@
# Copyright The IETF Trust 2007, All Rights Reserved
from django.conf.urls import patterns
from django.conf.urls import url, include
from django.views.generic import RedirectView
from ietf.meeting import views
from ietf.meeting import ajax
urlpatterns = patterns('',
(r'^(?P<meeting_num>\d+)/materials.html$', views.materials),
(r'^agenda/$', views.agenda),
(r'^agenda(-utc)?(?P<ext>.html)?$', views.agenda),
(r'^agenda(?P<ext>.txt)$', views.agenda),
(r'^agenda(?P<ext>.csv)$', views.agenda),
(r'^agenda/edit$', views.edit_agenda),
(r'^requests.html$', RedirectView.as_view(url='/meeting/requests', permanent=True)),
(r'^requests$', views.meeting_requests),
(r'^agenda/agenda.ics$', views.ical_agenda),
(r'^agenda.ics$', views.ical_agenda),
(r'^agenda/week-view.html$', views.week_view),
(r'^agenda/room-view.html$', views.room_view),
(r'^week-view.html$', views.week_view),
(r'^room-view.html$', views.room_view),
(r'^(?P<num>\d+)/agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/edit$', views.edit_agenda),
(r'^(?P<num>\d+)/agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/details$', views.edit_agenda_properties),
(r'^(?P<num>\d+)/agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+).(?P<ext>.html)?/?$', views.agenda),
(r'^(?P<num>\d+)/agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/permissions$', ajax.agenda_permission_api),
(r'^(?P<num>\d+)/agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/session/(?P<assignment_id>\d+).json$', ajax.assignment_json),
(r'^(?P<num>\d+)/agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/sessions.json$', ajax.assignments_json),
(r'^(?P<num>\d+)/agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+).json$', ajax.agenda_infourl),
(r'^(?P<num>\d+)/agenda/edit$', views.edit_agenda),
(r'^(?P<num>\d+)/agenda(-utc)?(?P<ext>.html)?/?$', views.agenda),
(r'^(?P<num>\d+)/requests.html$', RedirectView.as_view(url='/meeting/%(num)s/requests', permanent=True)),
(r'^(?P<num>\d+)/requests$', views.meeting_requests),
(r'^(?P<num>\d+)/agenda(?P<ext>.txt)$', views.agenda),
(r'^(?P<num>\d+)/agenda.ics$', views.ical_agenda),
(r'^(?P<num>\d+)/agenda(?P<ext>.csv)$', views.agenda),
(r'^(?P<num>\d+)/agenda/by-room$', views.agenda_by_room),
(r'^(?P<num>\d+)/agenda/by-type$', views.agenda_by_type),
(r'^(?P<num>\d+)/agenda/by-type/(?P<type>[a-z]+)$', views.agenda_by_type),
(r'^(?P<num>\d+)/agenda/by-type/(?P<type>[a-z]+)/ics$', views.agenda_by_type_ics),
(r'^(?P<num>\d+)/agendas/edit$', views.edit_agendas),
(r'^(?P<num>\d+)/timeslots/edit$', views.edit_timeslots),
(r'^(?P<num>\d+)/rooms$', ajax.timeslot_roomsurl),
(r'^(?P<num>\d+)/room/(?P<roomid>\d+).json$', ajax.timeslot_roomurl),
(r'^(?P<num>\d+)/room/(?P<roomid>\d+).html$', views.edit_roomurl),
(r'^(?P<num>\d+)/timeslots$', ajax.timeslot_slotsurl),
(r'^(?P<num>\d+)/timeslots.json$', ajax.timeslot_slotsurl),
(r'^(?P<num>\d+)/timeslot/(?P<slotid>\d+).json$', ajax.timeslot_sloturl),
(r'^(?P<num>\d+)/agendas$', ajax.agenda_infosurl),
(r'^(?P<num>\d+)/agendas.json$', ajax.agenda_infosurl),
(r'^(?P<num>\d+)/week-view.html$', views.week_view),
(r'^(?P<num>\d+)/room-view.html$', views.room_view),
(r'^(?P<num>\d+)/agenda/week-view.html$', views.week_view),
(r'^(?P<num>\d+)/agenda/room-view.html$', views.room_view),
(r'^(?P<num>\d+)/agenda/(?P<session>[A-Za-z0-9-]+)-drafts.pdf$', views.session_draft_pdf),
(r'^(?P<num>\d+)/agenda/(?P<session>[A-Za-z0-9-]+)-drafts.tgz$', views.session_draft_tarfile),
(r'^(?P<num>\d+)/agenda/(?P<session>[A-Za-z0-9-]+)/?$', views.session_agenda),
(r'^(?P<num>\d+)/sessions.json', ajax.sessions_json),
(r'^(?P<num>\d+)/session/(?P<sessionid>\d+).json', ajax.session_json),
(r'^(?P<num>\d+)/session/(?P<sessionid>\d+)/constraints.json', ajax.session_constraints),
safe_for_all_meeting_types = [
url(r'^session/(?P<acronym>[A-Za-z0-9_\-\+]+)/$', views.session_details),
]
(r'^(?P<num>\d+)/session/(?P<acronym>[A-Za-z0-9_\-\+]+)/$', views.session_details),
(r'^(?P<num>\d+)/session/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<seq>\d+)/$', views.session_details),
(r'^(?P<num>\d+)/session/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<week_day>[a-zA-Z]+)/$', views.session_details),
(r'^(?P<num>\d+)/session/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/$', views.session_details),
(r'^(?P<num>\d+)/session/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/(?P<seq>\d+)/$', views.session_details),
type_ietf_only_patterns = [
url(r'^agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/edit$', views.edit_agenda),
url(r'^agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/details$', views.edit_agenda_properties),
url(r'^agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+).(?P<ext>.html)?/?$', views.agenda),
url(r'^agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/permissions$', ajax.agenda_permission_api),
url(r'^agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/session/(?P<assignment_id>\d+).json$', ajax.assignment_json),
url(r'^agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/sessions.json$', ajax.assignments_json),
url(r'^agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+).json$', ajax.agenda_infourl),
url(r'^agenda/by-room$', views.agenda_by_room),
url(r'^agenda/by-type$', views.agenda_by_type),
url(r'^agenda/by-type/(?P<type>[a-z]+)$', views.agenda_by_type),
url(r'^agenda/by-type/(?P<type>[a-z]+)/ics$', views.agenda_by_type_ics),
url(r'^agendas/edit$', views.edit_agendas),
url(r'^timeslots/edit$', views.edit_timeslots),
url(r'^rooms$', ajax.timeslot_roomsurl),
url(r'^room/(?P<roomid>\d+).json$', ajax.timeslot_roomurl),
url(r'^room/(?P<roomid>\d+).html$', views.edit_roomurl),
url(r'^timeslots$', ajax.timeslot_slotsurl),
url(r'^timeslots.json$', ajax.timeslot_slotsurl),
url(r'^timeslot/(?P<slotid>\d+).json$', ajax.timeslot_sloturl),
url(r'^agendas$', ajax.agenda_infosurl),
url(r'^agendas.json$', ajax.agenda_infosurl),
url(r'^agenda/(?P<session>[A-Za-z0-9-]+)-drafts.pdf$', views.session_draft_pdf),
url(r'^agenda/(?P<session>[A-Za-z0-9-]+)-drafts.tgz$', views.session_draft_tarfile),
url(r'^agenda/(?P<session>[A-Za-z0-9-]+)/?$', views.session_agenda),
url(r'^sessions.json', ajax.sessions_json),
url(r'^session/(?P<sessionid>\d+).json', ajax.session_json),
url(r'^session/(?P<sessionid>\d+)/constraints.json', ajax.session_constraints),
url(r'^constraint/(?P<constraintid>\d+).json', ajax.constraint_json),
url(r'^json$', ajax.meeting_json),
]
(r'^(?P<num>\d+)/constraint/(?P<constraintid>\d+).json', ajax.constraint_json),
(r'^(?P<num>\d+).json$', ajax.meeting_json),
(r'^$', views.current_materials),
)
type_ietf_only_patterns_id_optional = [
url(r'^agenda(-utc)?(?P<ext>.html)?/?$', views.agenda),
url(r'^agenda(?P<ext>.txt)$', views.agenda),
url(r'^agenda(?P<ext>.csv)$', views.agenda),
url(r'^agenda/edit$', views.edit_agenda),
url(r'^requests$', views.meeting_requests),
url(r'^agenda/agenda.ics$', views.ical_agenda),
url(r'^agenda.ics$', views.ical_agenda),
url(r'^agenda/week-view.html$', views.week_view),
url(r'^agenda/room-view.html$', views.room_view),
url(r'^week-view.html$', views.week_view),
url(r'^room-view.html$', views.room_view),
]
urlpatterns = [
# TODO - views.material should take num instead of meeting_num so it can move into one of the above lists
url(r'^(?P<meeting_num>\d+)/materials.html$', views.materials),
url(r'^requests.html$', RedirectView.as_view(url='/meeting/requests', permanent=True)),
url(r'^(?P<num>\d+)/requests.html$', RedirectView.as_view(url='/meeting/%(num)s/requests', permanent=True)),
url(r'^(?P<num>[A-Za-z0-9._+-]+)/', include(safe_for_all_meeting_types)),
# The optionals have to go first, otherwise the agenda/(owner)/(name)/ patterns match things they shouldn't
url(r'^(?:(?P<num>\d+)/)?', include(type_ietf_only_patterns_id_optional)),
url(r'^(?P<num>\d+)/', include(type_ietf_only_patterns)),
url(r'^$', views.current_materials),
]

View file

@ -825,30 +825,13 @@ def meeting_requests(request, num=None):
{"meeting": meeting, "sessions":sessions,
"groups_not_meeting": groups_not_meeting})
def session_details(request, num, acronym, date=None, week_day=None, seq=None):
meeting = get_meeting(num)
def session_details(request, num, acronym ):
meeting = get_meeting(num=num,type_in=None)
sessions = Session.objects.filter(meeting=meeting,group__acronym=acronym,type__in=['session','plenary','other'])
if not sessions:
sessions = Session.objects.filter(meeting=meeting,short=acronym)
if date:
if len(date)==15:
start = datetime.datetime.strptime(date,"%Y-%m-%d-%H%M")
sessions = sessions.filter(timeslotassignments__schedule=meeting.agenda,timeslotassignments__timeslot__time=start)
else:
start = datetime.datetime.strptime(date,"%Y-%m-%d").date()
end = start+datetime.timedelta(days=1)
sessions = sessions.filter(timeslotassignments__schedule=meeting.agenda,timeslotassignments__timeslot__time__range=(start,end))
if week_day:
try:
dow = ['sun','mon','tue','wed','thu','fri','sat'].index(week_day.lower()[:3]) + 1
except ValueError:
raise Http404
sessions = sessions.filter(timeslotassignments__schedule=meeting.agenda,timeslotassignments__timeslot__time__week_day=dow)
def sort_key(session):
official_sessions = session.timeslotassignments.filter(schedule=session.meeting.agenda)
if official_sessions:
@ -858,34 +841,24 @@ def session_details(request, num, acronym, date=None, week_day=None, seq=None):
sessions = sorted(sessions,key=sort_key)
if seq:
iseq = int(seq) - 1
if not iseq in range(0,len(sessions)):
raise Http404
else:
sessions= [sessions[iseq]]
if not sessions:
raise Http404
if len(sessions)==1:
session = sessions[0]
scheduled_time = "Not yet scheduled"
for session in sessions:
ss = session.timeslotassignments.filter(schedule=meeting.agenda).order_by('timeslot__time')
if ss:
scheduled_time = ','.join(x.timeslot.time.strftime("%A %b-%d %H%M") for x in ss)
session.time = ', '.join(x.timeslot.time.strftime("%A %b-%d-%Y %H%M") for x in ss)
elif session.meeting.type_id=='interim':
session.time = session.meeting.date.strftime("%A %b-%d-%Y")
else:
session.time = 'Not yet scheduled'
# TODO FIXME Deleted materials shouldn't be in the sessionpresentation_set
filtered_sessionpresentation_set = [p for p in session.sessionpresentation_set.all() if p.document.get_state_slug(p.document.type_id)!='deleted']
return render(request, "meeting/session_details.html",
{ 'session':sessions[0] ,
'meeting' :meeting ,
'acronym' :acronym,
'time': scheduled_time,
'filtered_sessionpresentation_set': filtered_sessionpresentation_set
})
else:
return render(request, "meeting/session_list.html",
{ 'sessions':sessions ,
'meeting' :meeting ,
'acronym' :acronym,
})
session.filtered_sessionpresentation_set = [p for p in session.sessionpresentation_set.all() if p.document.get_state_slug(p.document.type_id)!='deleted']
return render(request, "meeting/session_details.html",
{ 'sessions':sessions ,
'meeting' :meeting ,
'acronym' :acronym,
})

View file

@ -76,6 +76,8 @@ def create_recording(session,meeting,group,url):
rev='00',
type_id='recording')
doc.set_state(State.objects.get(type='recording', slug='active'))
doc.docalias_set.create(name=name)
# create DocEvent
NewRevisionDocEvent.objects.create(type='new_revision',

View file

@ -445,9 +445,9 @@ def approvals(request):
'days': days })
@role_required("Secretariat", "WG Chair", "RG Chair")
@role_required("Secretariat", "Area Director", "WG Chair", "RG Chair")
def add_preapproval(request):
groups = Group.objects.filter(type__in=("wg", "rg")).exclude(state="conclude").order_by("acronym").distinct()
groups = Group.objects.filter(type__in=("wg", "rg")).exclude(state__in=["conclude","bof-conc"]).order_by("acronym").distinct()
if not has_role(request.user, "Secretariat"):
groups = groups.filter(role__person__user=request.user,role__name__in=['ad','chair','delegate','secr'])

View file

@ -10,19 +10,18 @@ Chairs:
{% endif %}{% if secr %}
Secretaries:
{% for r in secr %} {{ r.person.plain_name }} <{{r.email.address}}>
{% endfor %}{% endif %}{% if charter.group.type_id != "rg" %}{% if ads %}
Area Directors:
{% endfor %}{% endif %}{% if charter.group.type_id != "rg" %}
Assigned Area Director{{ads|length|pluralize}}:{% if ads %}
{% for r in ads %} {{ r.person.plain_name }} <{{r.email.address}}>
{% endfor %}{% else %}
Area Directors:
TBD
{% endif %}{% endif %}{% if techadv %}
{% endif %}{% if parent_ads %}
{{group.parent.name}} Directors:
{% for r in parent_ads %} {{ r.person.plain_name }} <{{r.email.address }}>
{% endfor %}{% endif %}{% endif %}{% if techadv %}
Technical advisors:
{% for r in techadv %} {{ r.person.plain_name }} <{{r.email.address}}>
{% endfor %}{% endif %}{% if group.ad_role %}
Assigned Area Director:
{{ group.ad_role.person.plain_name }} <{{ group.ad_role.email.address }}>
{% endif %}{% if group.list_email %}
{% endfor %}{% endif %} {% if group.list_email %}
Mailing list:
Address: {{ group.list_email }}
To subscribe: {{ group.list_subscribe }}

View file

@ -0,0 +1,27 @@
<table class="table table-condensed table-striped">
<thead>
<tr>
<th class="col-md-2"></th>
<th class="col-md-2"></th>
<th class="col-md-1"></th>
<th class="col-md-1"></th>
<th class="col-md-6"></th>
</tr>
</thead>
<tbody>
{% for s in sessions %}
<tr>
<td>{% ifchanged s.meeting %}{% if s.meeting.type.slug == 'ietf' %}IETF{% endif %}{{s.meeting.number}}{% endifchanged %}</td>
<td>
{% if s.status.slug == "sched" %}
{% if s.meeting.type.slug == 'ietf' %}{{s.time|date:"D M d, Y Hi"}}{% else %}{{s.time|date:"D M d, Y"}}{% endif %}
{% else %}
{{s.status}}
{% endif %}
</td>
<td>{% if s.minutes %}<a href="{{ s.minutes.get_absolute_url }}">Minutes</a>{% endif %}</td>
<td>{% if s.agenda %}<a href="{{ s.agenda.get_absolute_url }}">Agenda</a>{% endif %}</td>
<td><a href="{% url 'ietf.meeting.views.session_details' num=s.meeting.number acronym=s.group.acronym %}">Materials</a></td>
{% endfor %}
</tbody>
</table>

View file

@ -0,0 +1,50 @@
{% extends "group/group_base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %}
{% block title %}Meetings{% if group %} for {{group.acronym}}{% endif %}{% endblock %}
{% block group_content %}
{% origin %}
{% if in_progress %}
<div class="panel panel-default" id="inprogressmeets">
<div class="panel-heading">
Meetings in progress
</div>
<div class="panel-body">
{% with in_progress as sessions %}
{% include "group/meetings-row.html" %}
{% endwith %}
</div>
</div>
{% endif %}
{% if future %}
<div class="panel panel-default" id="futuremeets">
<div class="panel-heading">
Future Meetings
</div>
<div class="panel-body">
{% with future as sessions %}
{% include "group/meetings-row.html" %}
{% endwith %}
</div>
</div>
{% endif %}
{% if past %}
<div class="panel panel-default" id="pastmeets">
<div class="panel-heading">
Past Meetings
</div>
<div class="panel-body">
{% with past as sessions %}
{% include "group/meetings-row.html" %}
{% endwith %}
</div>
</div>
{% endif %}
<div>This page shows meetings within the last four years. For earlier meetings, please see the proceedings.</div>
{% endblock %}

View file

@ -6,20 +6,27 @@
{% block content %}
{% origin %}
<h1>{{ meeting }} : {{ acronym }} : {{ time }} </h1>
<h1>{{ meeting }} : {{ acronym }}</h1>
{% if session.name %}
<h2>{{ session.name }}</h2>
{% endif %}
{% for session in sessions %}
<h2>{{ session.time }}{% if session.name %} : {{ session.name }}{% endif %}</h2>
{% if filtered_sessionpresentation_set %}
<p>Materials:</p>
{% if session.filtered_sessionpresentation_set %}
<p>Materials:</p>
<ul>
{% for pres in filtered_sessionpresentation_set %}
<li><a href="{% url 'doc_view' name=pres.document.name rev=pres.rev%}">{{ pres.document.name }}-{{ pres.rev }}</a></li>
{% endfor %}
</ul>
{% endif %}
<table class="table table-condensed table-striped">
{% for pres in session.filtered_sessionpresentation_set %}
{% if pres.document.type_id != 'bluesheets' and pres.document.type_id != 'recording' %}
<tr>
<td>
<a href="{% url 'doc_view' name=pres.document.name rev=pres.rev%}">{{pres.document.title}} ({{ pres.document.name }}-{{ pres.rev }})
</a>
</td>
</tr>
{% endif %}
{% endfor %}
</table>
{% endif %}
{% endfor %}
{% endblock %}

View file

@ -1,16 +0,0 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %}
{% block title %}{{ meeting }} : {{ acronym }}{% endblock %}
{% block content %}
{% origin %}
<h1>{{ meeting }} : {{ acronym }}</h1>
<ul>
{% for session in sessions %}
<li> <a href="{{ forloop.counter }}/">{{session}}</a></li>
{% endfor %}
</ul>
{% endblock %}

View file

@ -351,5 +351,8 @@ def make_test_data():
other_doc_factory('agenda','agenda-42-mars')
other_doc_factory('minutes','minutes-42-mars')
other_doc_factory('slides','slides-42-mars-1')
# TODO: add
#other_doc_factory('bluesheets','bluesheets-42-mars-1')
#other_doc_factory('recording','recording-42-mars-1-00')
return draft