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 0611444b36bc071e8db068a093cc1ad93bb69659
This commit is contained in:
Henrik Levkowetz 2016-08-17 18:28:02 +00:00
parent 3fee46cafb
commit 6f05b23837
9 changed files with 186 additions and 37 deletions

View file

@ -521,7 +521,7 @@ def document_main(request, name, rev=None):
# 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"):
if doc.type_id in ("slides", "agenda", "minutes", "bluesheets",):
can_manage_material = can_manage_materials(request.user, doc.group)
presentations = doc.future_presentations()
if doc.meeting_related():
@ -540,7 +540,7 @@ def document_main(request, name, rev=None):
for g in globs:
extension = os.path.splitext(g)[1]
t = os.path.splitext(g)[1].lstrip(".")
url = doc.href()
url = doc.get_absolute_url() if doc.type_id=='bluesheets' else doc.href()
urlbase, urlext = os.path.splitext(url)
if not url.endswith("/") and not url.endswith(extension):
url = urlbase + extension

View file

@ -12,6 +12,7 @@ def official_time(session):
def forward(apps, schema_editor):
Document = apps.get_model('doc','Document')
NewRevisionDocEvent = apps.get_model('doc','NewRevisionDocEvent')
State = apps.get_model('doc','State')
Group = apps.get_model('group','Group')
Meeting = apps.get_model('meeting', 'Meeting')
@ -46,12 +47,14 @@ def forward(apps, schema_editor):
doc = Document.objects.create(
name=bs[n][:-4],
type_id='bluesheets',
title='Bluesheets IETF%d : %s : %s ' % (num,acronym,official_time(sess[n]).timeslot.time.strftime('%a %H:%M')),
title='Bluesheets IETF%d : %s : %s' % (num,acronym,official_time(sess[n]).timeslot.time.strftime('%a %H:%M')),
group=group,
rev='00',
external_url=bs[n],
)
doc.states.add(active)
doc.docalias_set.create(name=doc.name)
NewRevisionDocEvent.objects.create(doc=doc,time=doc.time,by_id=1,type='new_revision',desc='New revision available: %s'%doc.rev,rev=doc.rev)
sess[n].sessionpresentation_set.create(document=doc,rev='00')
def reverse(apps, schema_editor):

View file

@ -12,6 +12,7 @@ from django.conf import settings
from django.contrib.auth.models import User
from pyquery import PyQuery
from StringIO import StringIO
from ietf.doc.models import Document
from ietf.group.models import Group
@ -1198,3 +1199,45 @@ class FinalizeProceedingsTests(TestCase):
self.assertEqual(meeting.proceedings_final,True)
self.assertEqual(meeting.session_set.filter(group__acronym="mars").first().sessionpresentation_set.filter(document__type="draft").first().rev,'00')
class BluesheetsTests(TestCase):
def test_upload_blusheets(self):
session = SessionFactory(meeting__type_id='ietf')
url = urlreverse('ietf.meeting.views.upload_session_bluesheets',kwargs={'num':session.meeting.number,'session_id':session.id})
login_testing_unauthorized(self,"secretary",url)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertFalse(q("div.alert"))
self.assertFalse(session.sessionpresentation_set.exists())
test_file = StringIO('this is some text for a test')
test_file.name = "not_really.pdf"
r = self.client.post(url,dict(file=test_file))
self.assertEqual(r.status_code, 302)
bs_doc = session.sessionpresentation_set.filter(document__type_id='bluesheets').first().document
self.assertEqual(bs_doc.rev,'00')
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(q("div.alert"))
test_file = StringIO('this is some different text for a test')
test_file.name = "also_not_really.pdf"
r = self.client.post(url,dict(file=test_file))
self.assertEqual(r.status_code, 302)
bs_doc = Document.objects.get(pk=bs_doc.pk)
self.assertEqual(bs_doc.rev,'01')
def test_upload_bluesheets_interim(self):
session=SessionFactory(meeting__type_id='interim')
url = urlreverse('ietf.meeting.views.upload_session_bluesheets',kwargs={'num':session.meeting.number,'session_id':session.id})
login_testing_unauthorized(self,"secretary",url)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertFalse(q("div.alert"))
self.assertFalse(session.sessionpresentation_set.exists())
test_file = StringIO('this is some text for a test')
test_file.name = "not_really.pdf"
r = self.client.post(url,dict(file=test_file))
self.assertEqual(r.status_code, 302)
bs_doc = session.sessionpresentation_set.filter(document__type_id='bluesheets').first().document
self.assertEqual(bs_doc.rev,'00')

View file

@ -9,6 +9,7 @@ from ietf.meeting import ajax
safe_for_all_meeting_types = [
url(r'^session/(?P<acronym>[-a-z0-9]+)/?$', views.session_details),
url(r'^session/(?P<session_id>\d+)/drafts$', views.add_session_drafts),
url(r'^session/(?P<session_id>\d+)/bluesheets$', views.upload_session_bluesheets),
]
type_ietf_only_patterns = [

View file

@ -51,6 +51,8 @@ from ietf.meeting.helpers import send_interim_cancellation_notice
from ietf.meeting.helpers import send_interim_approval_request
from ietf.meeting.helpers import send_interim_announcement_request
from ietf.meeting.utils import finalize
from ietf.person.models import Person
from ietf.secr.proceedings.utils import handle_upload_file
from ietf.utils.mail import send_mail_message
from ietf.utils.pipe import pipe
from ietf.utils.pdf import pdf_pages
@ -1085,6 +1087,67 @@ def add_session_drafts(request, session_id, num):
'form': form,
})
class UploadBlueSheetForm(forms.Form):
file = forms.FileField(label='Bluesheet scan to upload')
@role_required('Secretariat')
def upload_session_bluesheets(request, session_id, num):
# num is redundant, but we're dragging it along an artifact of where we are in the current URL structure
session = get_object_or_404(Session,pk=session_id)
session_number = None
sessions = get_sessions(session.meeting.number,session.group.acronym)
if len(sessions) > 1:
session_number = 1 + sessions.index(session)
bluesheet_sp = session.sessionpresentation_set.filter(document__type='bluesheets').first()
if request.method == 'POST':
form = UploadBlueSheetForm(request.POST,request.FILES)
if form.is_valid():
file = request.FILES['file']
_, ext = os.path.splitext(file.name)
if bluesheet_sp:
doc = bluesheet_sp.document
doc.rev = '%02d' % (int(doc.rev)+1)
else:
sess_time = session.official_timeslotassignment().timeslot.time
if session.meeting.type_id=='ietf':
name = 'bluesheets-%s-%s-%s' % (session.meeting.number,
session.group.acronym,
sess_time.strftime("%Y%m%d%H%M"))
title = 'Bluesheets IETF%s: %s : %s' % (session.meeting.number,
session.group.acronym,
sess_time.strftime("%a %H:%M"))
else:
name = 'bluesheets-%s-%s' % (session.meeting.number, sess_time.strftime("%Y%m%d%H%M"))
title = 'Bluesheets %s: %s' % (session.meeting.number, sess_time.strftime("%a %H:%M"))
doc = Document.objects.create(
name = name,
type_id = 'bluesheets',
title = title,
group = session.group,
rev = '00',
)
doc.states.add(State.objects.get(type_id='bluesheets',slug='active'))
doc.docalias_set.create(name=doc.name)
session.sessionpresentation_set.create(document=doc,rev='00')
filename = '%s-%s%s'% ( doc.name, doc.rev, ext)
doc.external_url = filename
doc.save()
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)
handle_upload_file(file, filename, session.meeting, 'bluesheets')
return redirect('ietf.meeting.views.session_details',num=num,acronym=session.group.acronym)
else:
form = UploadBlueSheetForm()
return render(request, "meeting/upload_session_bluesheets.html",
{'session': session,
'session_number': session_number,
'bluesheet_sp' : bluesheet_sp,
'form': form,
})
@role_required('Secretariat')
def make_schedule_official(request, num, owner, name):

View file

@ -0,0 +1,39 @@
import glob
import os
import debug # pyflakes:ignore
def handle_upload_file(file,filename,meeting,subdir):
'''
This function takes a file object, a filename and a meeting object and subdir as string.
It saves the file to the appropriate directory, get_materials_path() + subdir.
If the file is a zip file, it creates a new directory in 'slides', which is the basename of the
zip file and unzips the file in the new directory.
'''
base, extension = os.path.splitext(filename)
if extension == '.zip':
path = os.path.join(meeting.get_materials_path(),subdir,base)
if not os.path.exists(path):
os.mkdir(path)
else:
path = os.path.join(meeting.get_materials_path(),subdir)
if not os.path.exists(path):
os.makedirs(path)
# agendas and minutes can only have one file instance so delete file if it already exists
if subdir in ('agenda','minutes'):
old_files = glob.glob(os.path.join(path,base) + '.*')
for f in old_files:
os.remove(f)
destination = open(os.path.join(path,filename), 'wb+')
for chunk in file.chunks():
destination.write(chunk)
destination.close()
# unzip zipfile
if extension == '.zip':
os.chdir(path)
os.system('unzip %s' % filename)

View file

@ -31,6 +31,7 @@ from ietf.secr.proceedings.forms import EditSlideForm, RecordingForm, RecordingE
from ietf.secr.proceedings.proc_utils import ( gen_acknowledgement, gen_agenda, gen_areas,
gen_attendees, gen_group_pages, gen_index, gen_irtf, gen_overview, gen_plenaries,
gen_progress, gen_research, gen_training, create_proceedings, create_recording )
from ietf.secr.proceedings.utils import handle_upload_file
from ietf.utils.log import log
# -------------------------------------------------
@ -138,40 +139,6 @@ def get_next_order_num(session):
return max_order + 1 if max_order else 1
def handle_upload_file(file,filename,meeting,subdir):
'''
This function takes a file object, a filename and a meeting object and subdir as string.
It saves the file to the appropriate directory, get_materials_path() + subdir.
If the file is a zip file, it creates a new directory in 'slides', which is the basename of the
zip file and unzips the file in the new directory.
'''
base, extension = os.path.splitext(filename)
if extension == '.zip':
path = os.path.join(meeting.get_materials_path(),subdir,base)
if not os.path.exists(path):
os.mkdir(path)
else:
path = os.path.join(meeting.get_materials_path(),subdir)
if not os.path.exists(path):
os.makedirs(path)
# agendas and minutes can only have one file instance so delete file if it already exists
if subdir in ('agenda','minutes'):
old_files = glob.glob(os.path.join(path,base) + '.*')
for f in old_files:
os.remove(f)
destination = open(os.path.join(path,filename), 'wb+')
for chunk in file.chunks():
destination.write(chunk)
destination.close()
# unzip zipfile
if extension == '.zip':
os.chdir(path)
os.system('unzip %s' % filename)
def parsedate(d):
'''
This function takes a date object and returns a tuple of year,month,day

View file

@ -23,6 +23,9 @@
<a class="btn btn-default" href="{% url 'ietf.meeting.views.add_session_drafts' session_id=session.pk num=session.meeting.number %}">
Link additional drafts to session
</a>
{% if user|has_role:"Secretariat" %}
<a class="btn btn-default" href="{% url 'ietf.meeting.views.upload_session_bluesheets' session_id=session.pk num=session.meeting.number %}">Upload Bluesheets</a>
{% endif %}
{% if not type_counter.agenda %}
<span class="label label-warning">This session does not yet have an agenda</span>
{% endif %}

View file

@ -0,0 +1,30 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin staticfiles bootstrap3 %}
{% block title %}Upload Bluesheets for {{ session.meeting }} : {{ session.group.acronym }}{% endblock %}
{% block content %}
{% origin %}
<h1>Upload Bluesheets for {{ session.meeting }} : {{ session.group.acronym }}{% if session.name %} : {{session.name}}{% endif %}</h1>
{% if session_number %}<h2> Session {{session_number}} : {{session.official_timeslotassignment.timeslot.time|date:"D M-d-Y Hi"}}</h2>{% endif %}
{% if bluesheet_sp %}
<div class="alert alert-warning">
Bluesheets have alrady been uploaded for this session.
See <a href="{% url 'ietf.doc.views_doc.document_main' name=bluesheet_sp.document.name %}">{{bluesheet_sp.document.name}}-{{bluesheet_sp.document.rev}}</a>.
Continue with this upload to provide an updated version of that document.
</div>
{% endif %}
<form enctype="multipart/form-data" method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">Upload</button>
{% endbuttons %}
</form>
{% endblock %}