Skip to content

Commit 6f05b23

Browse files
committed
Merged in [11778] from rjsparks@nostrum.com:
Enabled and refined document_main view for bluesheets. Improved migration for 95 and 96 bluesheets, adding DocAlias and DocEvent creation. Added bluesheet upload to the session details view. Moved a function out of secr/proceedings/views into its own util.py file to allow reusing it in other modules without introducing circular imports. - Legacy-Id: 11811 Note: SVN reference [11778] has been migrated to Git commit 0611444
1 parent 3fee46c commit 6f05b23

9 files changed

Lines changed: 186 additions & 37 deletions

File tree

ietf/doc/views_doc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ def document_main(request, name, rev=None):
521521

522522
# TODO : Add "recording", and "bluesheets" here when those documents are appropriately
523523
# created and content is made available on disk
524-
if doc.type_id in ("slides", "agenda", "minutes"):
524+
if doc.type_id in ("slides", "agenda", "minutes", "bluesheets",):
525525
can_manage_material = can_manage_materials(request.user, doc.group)
526526
presentations = doc.future_presentations()
527527
if doc.meeting_related():
@@ -540,7 +540,7 @@ def document_main(request, name, rev=None):
540540
for g in globs:
541541
extension = os.path.splitext(g)[1]
542542
t = os.path.splitext(g)[1].lstrip(".")
543-
url = doc.href()
543+
url = doc.get_absolute_url() if doc.type_id=='bluesheets' else doc.href()
544544
urlbase, urlext = os.path.splitext(url)
545545
if not url.endswith("/") and not url.endswith(extension):
546546
url = urlbase + extension

ietf/meeting/migrations/0032_reconstruct_bluesheet_docs_95through96.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def official_time(session):
1212

1313
def forward(apps, schema_editor):
1414
Document = apps.get_model('doc','Document')
15+
NewRevisionDocEvent = apps.get_model('doc','NewRevisionDocEvent')
1516
State = apps.get_model('doc','State')
1617
Group = apps.get_model('group','Group')
1718
Meeting = apps.get_model('meeting', 'Meeting')
@@ -46,12 +47,14 @@ def forward(apps, schema_editor):
4647
doc = Document.objects.create(
4748
name=bs[n][:-4],
4849
type_id='bluesheets',
49-
title='Bluesheets IETF%d : %s : %s ' % (num,acronym,official_time(sess[n]).timeslot.time.strftime('%a %H:%M')),
50+
title='Bluesheets IETF%d : %s : %s' % (num,acronym,official_time(sess[n]).timeslot.time.strftime('%a %H:%M')),
5051
group=group,
5152
rev='00',
5253
external_url=bs[n],
5354
)
5455
doc.states.add(active)
56+
doc.docalias_set.create(name=doc.name)
57+
NewRevisionDocEvent.objects.create(doc=doc,time=doc.time,by_id=1,type='new_revision',desc='New revision available: %s'%doc.rev,rev=doc.rev)
5558
sess[n].sessionpresentation_set.create(document=doc,rev='00')
5659

5760
def reverse(apps, schema_editor):

ietf/meeting/tests_views.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from django.contrib.auth.models import User
1313

1414
from pyquery import PyQuery
15+
from StringIO import StringIO
1516

1617
from ietf.doc.models import Document
1718
from ietf.group.models import Group
@@ -1198,3 +1199,45 @@ def test_finalize_proceedings(self):
11981199
self.assertEqual(meeting.proceedings_final,True)
11991200
self.assertEqual(meeting.session_set.filter(group__acronym="mars").first().sessionpresentation_set.filter(document__type="draft").first().rev,'00')
12001201

1202+
class BluesheetsTests(TestCase):
1203+
def test_upload_blusheets(self):
1204+
session = SessionFactory(meeting__type_id='ietf')
1205+
url = urlreverse('ietf.meeting.views.upload_session_bluesheets',kwargs={'num':session.meeting.number,'session_id':session.id})
1206+
login_testing_unauthorized(self,"secretary",url)
1207+
r = self.client.get(url)
1208+
self.assertEqual(r.status_code, 200)
1209+
q = PyQuery(r.content)
1210+
self.assertFalse(q("div.alert"))
1211+
self.assertFalse(session.sessionpresentation_set.exists())
1212+
test_file = StringIO('this is some text for a test')
1213+
test_file.name = "not_really.pdf"
1214+
r = self.client.post(url,dict(file=test_file))
1215+
self.assertEqual(r.status_code, 302)
1216+
bs_doc = session.sessionpresentation_set.filter(document__type_id='bluesheets').first().document
1217+
self.assertEqual(bs_doc.rev,'00')
1218+
r = self.client.get(url)
1219+
self.assertEqual(r.status_code, 200)
1220+
q = PyQuery(r.content)
1221+
self.assertTrue(q("div.alert"))
1222+
test_file = StringIO('this is some different text for a test')
1223+
test_file.name = "also_not_really.pdf"
1224+
r = self.client.post(url,dict(file=test_file))
1225+
self.assertEqual(r.status_code, 302)
1226+
bs_doc = Document.objects.get(pk=bs_doc.pk)
1227+
self.assertEqual(bs_doc.rev,'01')
1228+
1229+
def test_upload_bluesheets_interim(self):
1230+
session=SessionFactory(meeting__type_id='interim')
1231+
url = urlreverse('ietf.meeting.views.upload_session_bluesheets',kwargs={'num':session.meeting.number,'session_id':session.id})
1232+
login_testing_unauthorized(self,"secretary",url)
1233+
r = self.client.get(url)
1234+
self.assertEqual(r.status_code, 200)
1235+
q = PyQuery(r.content)
1236+
self.assertFalse(q("div.alert"))
1237+
self.assertFalse(session.sessionpresentation_set.exists())
1238+
test_file = StringIO('this is some text for a test')
1239+
test_file.name = "not_really.pdf"
1240+
r = self.client.post(url,dict(file=test_file))
1241+
self.assertEqual(r.status_code, 302)
1242+
bs_doc = session.sessionpresentation_set.filter(document__type_id='bluesheets').first().document
1243+
self.assertEqual(bs_doc.rev,'00')

ietf/meeting/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
safe_for_all_meeting_types = [
1010
url(r'^session/(?P<acronym>[-a-z0-9]+)/?$', views.session_details),
1111
url(r'^session/(?P<session_id>\d+)/drafts$', views.add_session_drafts),
12+
url(r'^session/(?P<session_id>\d+)/bluesheets$', views.upload_session_bluesheets),
1213
]
1314

1415
type_ietf_only_patterns = [

ietf/meeting/views.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
from ietf.meeting.helpers import send_interim_approval_request
5252
from ietf.meeting.helpers import send_interim_announcement_request
5353
from ietf.meeting.utils import finalize
54+
from ietf.person.models import Person
55+
from ietf.secr.proceedings.utils import handle_upload_file
5456
from ietf.utils.mail import send_mail_message
5557
from ietf.utils.pipe import pipe
5658
from ietf.utils.pdf import pdf_pages
@@ -1085,6 +1087,67 @@ def add_session_drafts(request, session_id, num):
10851087
'form': form,
10861088
})
10871089

1090+
class UploadBlueSheetForm(forms.Form):
1091+
file = forms.FileField(label='Bluesheet scan to upload')
1092+
1093+
@role_required('Secretariat')
1094+
def upload_session_bluesheets(request, session_id, num):
1095+
# num is redundant, but we're dragging it along an artifact of where we are in the current URL structure
1096+
session = get_object_or_404(Session,pk=session_id)
1097+
1098+
session_number = None
1099+
sessions = get_sessions(session.meeting.number,session.group.acronym)
1100+
if len(sessions) > 1:
1101+
session_number = 1 + sessions.index(session)
1102+
1103+
bluesheet_sp = session.sessionpresentation_set.filter(document__type='bluesheets').first()
1104+
1105+
if request.method == 'POST':
1106+
form = UploadBlueSheetForm(request.POST,request.FILES)
1107+
if form.is_valid():
1108+
file = request.FILES['file']
1109+
_, ext = os.path.splitext(file.name)
1110+
if bluesheet_sp:
1111+
doc = bluesheet_sp.document
1112+
doc.rev = '%02d' % (int(doc.rev)+1)
1113+
else:
1114+
sess_time = session.official_timeslotassignment().timeslot.time
1115+
if session.meeting.type_id=='ietf':
1116+
name = 'bluesheets-%s-%s-%s' % (session.meeting.number,
1117+
session.group.acronym,
1118+
sess_time.strftime("%Y%m%d%H%M"))
1119+
title = 'Bluesheets IETF%s: %s : %s' % (session.meeting.number,
1120+
session.group.acronym,
1121+
sess_time.strftime("%a %H:%M"))
1122+
else:
1123+
name = 'bluesheets-%s-%s' % (session.meeting.number, sess_time.strftime("%Y%m%d%H%M"))
1124+
title = 'Bluesheets %s: %s' % (session.meeting.number, sess_time.strftime("%a %H:%M"))
1125+
doc = Document.objects.create(
1126+
name = name,
1127+
type_id = 'bluesheets',
1128+
title = title,
1129+
group = session.group,
1130+
rev = '00',
1131+
)
1132+
doc.states.add(State.objects.get(type_id='bluesheets',slug='active'))
1133+
doc.docalias_set.create(name=doc.name)
1134+
session.sessionpresentation_set.create(document=doc,rev='00')
1135+
filename = '%s-%s%s'% ( doc.name, doc.rev, ext)
1136+
doc.external_url = filename
1137+
doc.save()
1138+
NewRevisionDocEvent.objects.create(doc=doc,time=doc.time,by=Person.objects.get(name='(System)'),type='new_revision',desc='New revision available: %s'%doc.rev,rev=doc.rev)
1139+
handle_upload_file(file, filename, session.meeting, 'bluesheets')
1140+
return redirect('ietf.meeting.views.session_details',num=num,acronym=session.group.acronym)
1141+
else:
1142+
form = UploadBlueSheetForm()
1143+
1144+
return render(request, "meeting/upload_session_bluesheets.html",
1145+
{'session': session,
1146+
'session_number': session_number,
1147+
'bluesheet_sp' : bluesheet_sp,
1148+
'form': form,
1149+
})
1150+
10881151
@role_required('Secretariat')
10891152
def make_schedule_official(request, num, owner, name):
10901153

ietf/secr/proceedings/utils.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import glob
2+
import os
3+
4+
import debug # pyflakes:ignore
5+
6+
def handle_upload_file(file,filename,meeting,subdir):
7+
'''
8+
This function takes a file object, a filename and a meeting object and subdir as string.
9+
It saves the file to the appropriate directory, get_materials_path() + subdir.
10+
If the file is a zip file, it creates a new directory in 'slides', which is the basename of the
11+
zip file and unzips the file in the new directory.
12+
'''
13+
base, extension = os.path.splitext(filename)
14+
15+
if extension == '.zip':
16+
path = os.path.join(meeting.get_materials_path(),subdir,base)
17+
if not os.path.exists(path):
18+
os.mkdir(path)
19+
else:
20+
path = os.path.join(meeting.get_materials_path(),subdir)
21+
if not os.path.exists(path):
22+
os.makedirs(path)
23+
24+
# agendas and minutes can only have one file instance so delete file if it already exists
25+
if subdir in ('agenda','minutes'):
26+
old_files = glob.glob(os.path.join(path,base) + '.*')
27+
for f in old_files:
28+
os.remove(f)
29+
30+
destination = open(os.path.join(path,filename), 'wb+')
31+
for chunk in file.chunks():
32+
destination.write(chunk)
33+
destination.close()
34+
35+
# unzip zipfile
36+
if extension == '.zip':
37+
os.chdir(path)
38+
os.system('unzip %s' % filename)
39+

ietf/secr/proceedings/views.py

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from ietf.secr.proceedings.proc_utils import ( gen_acknowledgement, gen_agenda, gen_areas,
3232
gen_attendees, gen_group_pages, gen_index, gen_irtf, gen_overview, gen_plenaries,
3333
gen_progress, gen_research, gen_training, create_proceedings, create_recording )
34+
from ietf.secr.proceedings.utils import handle_upload_file
3435
from ietf.utils.log import log
3536

3637
# -------------------------------------------------
@@ -138,40 +139,6 @@ def get_next_order_num(session):
138139

139140
return max_order + 1 if max_order else 1
140141

141-
def handle_upload_file(file,filename,meeting,subdir):
142-
'''
143-
This function takes a file object, a filename and a meeting object and subdir as string.
144-
It saves the file to the appropriate directory, get_materials_path() + subdir.
145-
If the file is a zip file, it creates a new directory in 'slides', which is the basename of the
146-
zip file and unzips the file in the new directory.
147-
'''
148-
base, extension = os.path.splitext(filename)
149-
150-
if extension == '.zip':
151-
path = os.path.join(meeting.get_materials_path(),subdir,base)
152-
if not os.path.exists(path):
153-
os.mkdir(path)
154-
else:
155-
path = os.path.join(meeting.get_materials_path(),subdir)
156-
if not os.path.exists(path):
157-
os.makedirs(path)
158-
159-
# agendas and minutes can only have one file instance so delete file if it already exists
160-
if subdir in ('agenda','minutes'):
161-
old_files = glob.glob(os.path.join(path,base) + '.*')
162-
for f in old_files:
163-
os.remove(f)
164-
165-
destination = open(os.path.join(path,filename), 'wb+')
166-
for chunk in file.chunks():
167-
destination.write(chunk)
168-
destination.close()
169-
170-
# unzip zipfile
171-
if extension == '.zip':
172-
os.chdir(path)
173-
os.system('unzip %s' % filename)
174-
175142
def parsedate(d):
176143
'''
177144
This function takes a date object and returns a tuple of year,month,day

ietf/templates/meeting/session_details.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ <h2>{% if sessions|length > 1 %}Session {{ forloop.counter }} : {% endif %}{{ se
2323
<a class="btn btn-default" href="{% url 'ietf.meeting.views.add_session_drafts' session_id=session.pk num=session.meeting.number %}">
2424
Link additional drafts to session
2525
</a>
26+
{% if user|has_role:"Secretariat" %}
27+
<a class="btn btn-default" href="{% url 'ietf.meeting.views.upload_session_bluesheets' session_id=session.pk num=session.meeting.number %}">Upload Bluesheets</a>
28+
{% endif %}
2629
{% if not type_counter.agenda %}
2730
<span class="label label-warning">This session does not yet have an agenda</span>
2831
{% endif %}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{% extends "base.html" %}
2+
{# Copyright The IETF Trust 2015, All Rights Reserved #}
3+
{% load origin staticfiles bootstrap3 %}
4+
5+
{% block title %}Upload Bluesheets for {{ session.meeting }} : {{ session.group.acronym }}{% endblock %}
6+
7+
{% block content %}
8+
{% origin %}
9+
10+
<h1>Upload Bluesheets for {{ session.meeting }} : {{ session.group.acronym }}{% if session.name %} : {{session.name}}{% endif %}</h1>
11+
{% if session_number %}<h2> Session {{session_number}} : {{session.official_timeslotassignment.timeslot.time|date:"D M-d-Y Hi"}}</h2>{% endif %}
12+
13+
{% if bluesheet_sp %}
14+
<div class="alert alert-warning">
15+
Bluesheets have alrady been uploaded for this session.
16+
See <a href="{% url 'ietf.doc.views_doc.document_main' name=bluesheet_sp.document.name %}">{{bluesheet_sp.document.name}}-{{bluesheet_sp.document.rev}}</a>.
17+
Continue with this upload to provide an updated version of that document.
18+
</div>
19+
{% endif %}
20+
21+
<form enctype="multipart/form-data" method="post">
22+
{% csrf_token %}
23+
{% bootstrap_form form %}
24+
{% buttons %}
25+
<button type="submit" class="btn btn-primary">Upload</button>
26+
{% endbuttons %}
27+
</form>
28+
29+
30+
{% endblock %}

0 commit comments

Comments
 (0)