Add "material package" to the attachment module
[cds-indico.git] / indico / modules / attachments / controllers / event_package.py
blob9d54c61c42d40c5716d5a3d68904f7a15d704260
1 # This file is part of Indico.
2 # Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
4 # Indico is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3 of the
7 # License, or (at your option) any later version.
9 # Indico is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with Indico; if not, see <http://www.gnu.org/licenses/>.
17 from __future__ import unicode_literals
19 import os
20 import tempfile
21 from zipfile import ZipFile
23 from flask import session
24 from sqlalchemy import cast, Date
25 from werkzeug.utils import secure_filename
27 from indico.web.flask.util import send_file
28 from indico.modules.attachments.forms import MaterialsPackageForm
29 from indico.modules.attachments.models.attachments import Attachment, AttachmentFile, AttachmentType
30 from indico.modules.attachments.models.folders import AttachmentFolder
33 class MaterialsPackageMixin:
35 def _process(self):
36 form = self._prepare_form()
37 if form.validate_on_submit():
38 return self._generate_zip_file(self._filter_attachments(form))
40 return self.wp.render_template('generate_package.html', self._conf, form=form)
42 def _prepare_form(self):
43 form = MaterialsPackageForm()
44 form.sessions.choices = self._load_session_data()
45 form.contributions.choices = self._load_contribution_data()
46 return form
48 def _load_session_data(self):
49 sessions = self._conf.getSessionList()
50 return [(session.getId(), session.getTitle()) for session in sessions]
52 def _load_contribution_data(self):
53 return [(contrib.getId(), contrib.getTitle()) for contrib in self._conf.getContributionList()]
55 def _filter_attachments(self, form):
56 attachments = []
57 added_since = form.added_since.data
58 attachments.extend(self._filter_protected(self._filter_top_level_attachments(added_since)))
59 if form.sessions.data:
60 attachments.extend(self._filter_protected(self._filter_by_sessions(form.sessions.data, added_since)))
61 if form.contributions.data:
62 attachments.extend(self._filter_protected(self._filter_by_contributions(form.contributions.data, added_since)))
63 return attachments
65 def _filter_protected(self, attachments):
66 return [attachment for attachment in attachments if attachment.can_access(session.user)]
68 def _filter_top_level_attachments(self, added_since):
69 query = self._build_base_query().filter(AttachmentFolder.linked_object == self._conf)
71 if added_since:
72 query = self._filter_by_date(query, added_since)
74 return query.all()
76 def _build_base_query(self):
77 return Attachment.find(Attachment.type == AttachmentType.file, ~AttachmentFolder.is_deleted,
78 ~Attachment.is_deleted, AttachmentFolder.event_id == int(self._conf.getId()),
79 _join=AttachmentFolder)
81 def _filter_by_sessions(self, session_ids, added_since):
82 query = self._build_base_query().filter(AttachmentFolder.session_id.in_(session_ids))
84 if added_since:
85 query = self._filter_by_date(query, added_since)
87 return query.all()
89 def _filter_by_contributions(self, contribution_ids, added_since):
90 query = self._build_base_query().filter(AttachmentFolder.contribution_id.in_(contribution_ids))
92 if added_since:
93 query = self._filter_by_date(query, added_since)
95 return query.all()
97 def _filter_by_date(self, query, added_since):
98 return query.filter(cast(AttachmentFile.created_dt, Date) >= added_since)
100 def _generate_zip_file(self, attachments):
101 temp_file = tempfile.NamedTemporaryFile('w')
102 with ZipFile(temp_file.name, 'w', allowZip64=True) as zip_handler:
103 for attachment in attachments:
104 if not attachment.folder.is_default:
105 name = os.path.join(os.path.join(secure_filename(attachment.folder.title), attachment.file.filename))
106 else:
107 name = attachment.file.filename
109 with attachment.file.storage.get_local_path(attachment.file.storage_file_id) as filepath:
110 zip_handler.write(filepath, name)
112 return send_file('attachments.zip', temp_file.name, 'application/zip', inline=False)