Add folder_updated signal
[cds-indico.git] / indico / modules / attachments / controllers / management / base.py
blobb1e4ef7f0384b1f4f19973b9aedf3ca26e3754a2
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 from flask import flash, request, session
20 from werkzeug.utils import secure_filename
22 from indico.core.db import db
23 from indico.core import signals
24 from indico.modules.attachments import logger
25 from indico.modules.attachments.controllers.util import SpecificAttachmentMixin, SpecificFolderMixin
26 from indico.modules.attachments.forms import (AddAttachmentFilesForm, AttachmentLinkForm, AttachmentFolderForm,
27 EditAttachmentFileForm)
28 from indico.modules.attachments.models.folders import AttachmentFolder
29 from indico.modules.attachments.models.attachments import Attachment, AttachmentFile, AttachmentType
30 from indico.modules.attachments.util import get_attached_items
31 from indico.util.i18n import _, ngettext
32 from indico.web.flask.templating import get_template_module
33 from indico.web.flask.util import url_for
34 from indico.web.forms.base import FormDefaults
35 from indico.web.util import jsonify_template, jsonify_data
38 def _render_attachment_list(linked_object):
39 tpl = get_template_module('attachments/_attachments.html')
40 return tpl.render_attachments(attachments=get_attached_items(linked_object), linked_object=linked_object)
43 class ManageAttachmentsMixin:
44 """Shows the attachment management page"""
45 wp = None
47 def _process(self):
48 return self.wp.render_template('attachments.html', self.object, linked_object=self.object,
49 linked_object_type=self.object_type, attachments=get_attached_items(self.object))
52 class AddAttachmentFilesMixin:
53 """Upload file attachments"""
55 def _process(self):
56 form = AddAttachmentFilesForm(linked_object=self.object)
57 if form.validate_on_submit():
58 files = request.files.getlist('file')
59 folder = form.folder.data or AttachmentFolder.get_or_create_default(linked_object=self.object)
60 for f in files:
61 filename = secure_filename(f.filename) or 'attachment'
62 attachment = Attachment(folder=folder, user=session.user, title=f.filename, type=AttachmentType.file,
63 protection_mode=form.protection_mode.data)
64 attachment.file = AttachmentFile(user=session.user, filename=filename, content_type=f.mimetype)
65 attachment.file.save(f.file)
66 db.session.add(attachment)
67 logger.info('File attachment {} added by {}'.format(attachment, session.user))
68 signals.attachments.attachment_created.send(attachment, user=session.user)
69 flash(ngettext("The attachment has been uploaded", "%(num)d attachments have been uploaded", len(files)),
70 'success')
71 return jsonify_data(attachment_list=_render_attachment_list(self.object))
72 return jsonify_template('attachments/upload.html', form=form, action=url_for('.upload', self.object))
75 class AddAttachmentLinkMixin:
76 """Add link attachment"""
78 def _process(self):
79 form = AttachmentLinkForm(linked_object=self.object)
80 if form.validate_on_submit():
81 folder = form.folder.data or AttachmentFolder.get_or_create_default(linked_object=self.object)
82 link = Attachment(user=session.user, type=AttachmentType.link)
83 form.populate_obj(link, skip={'acl'})
84 link.folder = folder
85 if link.is_protected:
86 link.acl = form.acl.data
88 logger.info('Link attachment {} added by {}'.format(link, session.user))
89 signals.attachments.attachment_created.send(link, user=session.user)
90 flash(_("The link has been added"), 'success')
91 return jsonify_data(attachment_list=_render_attachment_list(self.object))
92 return jsonify_template('attachments/add_link.html', form=form)
95 class EditAttachmentMixin(SpecificAttachmentMixin):
96 """Edit an attachment"""
98 def _process(self):
99 defaults = FormDefaults(self.attachment, protected=self.attachment.is_protected)
100 form_cls = EditAttachmentFileForm if self.attachment.type == AttachmentType.file else AttachmentLinkForm
101 form = form_cls(linked_object=self.object, obj=defaults)
102 if form.validate_on_submit():
103 folder = form.folder.data or AttachmentFolder.get_or_create_default(linked_object=self.object)
104 logger.info('Edited attachment {} by {}'.format(self.attachment, session.user))
105 form.populate_obj(self.attachment, skip={'acl'})
106 self.attachment.folder = folder
107 if self.attachment.is_protected:
108 self.attachment.acl = form.acl.data
109 # files need special handling; links are already updated in `populate_obj`
110 if self.attachment.type == AttachmentType.file:
111 file = request.files['file'] if request.files else None
112 if file:
113 self.attachment.file = AttachmentFile(user=session.user, filename=secure_filename(file.filename),
114 content_type=file.mimetype)
115 self.attachment.file.save(file.file)
117 signals.attachments.attachment_updated.send(self.attachment, user=session.user)
118 flash(_("The attachment has been updated"), 'success')
119 return jsonify_data(attachment_list=_render_attachment_list(self.object))
121 template = ('attachments/upload.html' if self.attachment.type == AttachmentType.file else
122 'attachments/add_link.html')
123 return jsonify_template(template, form=form, existing_attachment=self.attachment,
124 action=url_for('.modify_attachment', self.attachment))
127 class CreateFolderMixin:
128 """Create a new empty folder"""
130 def _process(self):
131 form = AttachmentFolderForm(obj=FormDefaults(is_always_visible=True))
132 if form.validate_on_submit():
133 folder = AttachmentFolder(linked_object=self.object)
134 form.populate_obj(folder, skip={'acl'})
135 if folder.is_protected:
136 folder.acl = form.acl.data
137 db.session.add(folder)
138 logger.info('Folder {} created by {}'.format(folder, session.user))
139 signals.attachments.folder_created.send(folder, user=session.user)
140 flash(_("Folder \"{name}\" created").format(name=folder.title), 'success')
141 return jsonify_data(attachment_list=_render_attachment_list(self.object))
142 return jsonify_template('attachments/create_folder.html', form=form)
145 class EditFolderMixin(SpecificFolderMixin):
146 """Edit a folder"""
148 def _process(self):
149 defaults = FormDefaults(self.folder, protected=self.folder.is_protected)
150 form = AttachmentFolderForm(obj=defaults)
151 if form.validate_on_submit():
152 form.populate_obj(self.folder, skip={'acl'})
153 if self.folder.is_protected:
154 self.folder.acl = form.acl.data
155 logger.info('Folder {} updated by {}'.format(self.folder, session.user))
156 signals.attachments.folder_updated.send(self.folder, user=session.user)
157 flash(_("Folder \"{name}\" updated").format(name=self.folder.title), 'success')
158 return jsonify_data(attachment_list=_render_attachment_list(self.object))
159 return jsonify_template('attachments/create_folder.html', form=form)
162 class DeleteFolderMixin(SpecificFolderMixin):
163 """Delete a folder"""
165 def _process(self):
166 self.folder.is_deleted = True
167 logger.info('Folder {} deleted by {}'.format(self.folder, session.user))
168 signals.attachments.folder_deleted.send(self.folder, user=session.user)
169 flash(_("Folder \"{name}\" deleted").format(name=self.folder.title), 'success')
170 return jsonify_data(attachment_list=_render_attachment_list(self.object))
173 class DeleteAttachmentMixin(SpecificAttachmentMixin):
174 """Delete an attachment"""
176 def _process(self):
177 self.attachment = Attachment.get_one(request.view_args['attachment_id'])
178 self.attachment.is_deleted = True
179 logger.info('Deleted attachment {} by {}'.format(self.attachment, session.user))
180 signals.attachments.attachment_deleted.send(self.attachment, user=session.user)
181 flash(_("Attachment \"{name}\" deleted").format(name=self.attachment.title), 'success')
182 return jsonify_data(attachment_list=_render_attachment_list(self.object))