0005-remove-support-for-strongbox-37967.patch
auquotidien/auquotidien.py | ||
---|---|---|
8 | 8 |
from modules import backoffice |
9 | 9 |
from modules import categories_admin |
10 | 10 |
from modules import payments_ui |
11 |
from modules import strongbox_ui |
|
12 | 11 |
from modules import formpage |
13 | 12 |
from modules import template |
14 | 13 |
from modules import root |
... | ... | |
28 | 27 |
rdb.register_directory('payments', payments_ui.PaymentsDirectory()) |
29 | 28 |
rdb.register_menu_item('payments/', _('Payments')) |
30 | 29 | |
31 |
rdb.register_directory('strongbox', strongbox_ui.StrongboxDirectory()) |
|
32 |
rdb.register_menu_item('strongbox/', _('Strongbox')) |
|
33 | ||
34 | 30 |
rdb.register_directory('settings', admin.SettingsDirectory()) |
35 | 31 | |
36 | 32 |
import wcs.admin.forms |
auquotidien/modules/admin.py | ||
---|---|---|
22 | 22 | |
23 | 23 | |
24 | 24 |
class PanelDirectory(Directory): |
25 |
_q_exports = ['', 'update', 'permissions', |
|
26 |
'strongbox', 'domino'] |
|
25 |
_q_exports = ['', 'update', 'permissions', 'domino'] |
|
27 | 26 |
label = N_('Control Panel') |
28 | 27 | |
29 | 28 |
domino = AbeliumDominoDirectory() |
... | ... | |
47 | 46 |
form.add(SingleSelectWidget, 'payments', title = _('Admin role for payments'), |
48 | 47 |
value = permissions_cfg.get('payments', None), |
49 | 48 |
options = [(None, _('Nobody'), None)] + get_user_roles()) |
50 |
if get_publisher().has_site_option('auquotidien-strongbox'): |
|
51 |
form.add(SingleSelectWidget, 'strongbox', title = _('Admin role for strongbox'), |
|
52 |
value = permissions_cfg.get('strongbox', None), |
|
53 |
options = [(None, _('Nobody'), None)] + get_user_roles()) |
|
54 | 49 |
form.add_submit('submit', _('Submit')) |
55 | 50 |
form.add_submit('cancel', _('Cancel')) |
56 | 51 | |
... | ... | |
66 | 61 |
return r.getvalue() |
67 | 62 |
else: |
68 | 63 |
from wcs.admin.settings import cfg_submit |
69 |
cfg_submit(form, 'aq-permissions', |
|
70 |
('forms', 'payments', 'strongbox')) |
|
71 |
return redirect('..') |
|
72 | ||
73 |
def strongbox(self): |
|
74 |
if not get_publisher().has_site_option('strongbox'): |
|
75 |
raise errors.TraversalError() |
|
76 |
misc_cfg = get_cfg('misc', {}) |
|
77 |
form = Form(enctype='multipart/form-data') |
|
78 |
form.add(CheckboxWidget, 'aq-strongbox', title=_('Strongbox Support'), |
|
79 |
value=misc_cfg.get('aq-strongbox'), required=False) |
|
80 | ||
81 |
form.add_submit('submit', _('Submit')) |
|
82 |
form.add_submit('cancel', _('Cancel')) |
|
83 | ||
84 |
if form.get_widget('cancel').parse(): |
|
85 |
return redirect('..') |
|
86 | ||
87 |
if not form.is_submitted() or form.has_errors(): |
|
88 |
get_response().breadcrumb.append(('aq/strongbox', _('Strongbox Support'))) |
|
89 |
html_top('settings', _('Strongbox Support')) |
|
90 |
r = TemplateIO(html=True) |
|
91 |
r += htmltext('<h2>%s</h2>') % _('Strongbox Support') |
|
92 |
r += form.render() |
|
93 |
return r.getvalue() |
|
94 |
else: |
|
95 |
from wcs.admin.settings import cfg_submit |
|
96 |
cfg_submit(form, 'misc', ('aq-strongbox',)) |
|
64 |
cfg_submit(form, 'aq-permissions', ('forms', 'payments')) |
|
97 | 65 |
return redirect('..') |
98 | 66 | |
99 | 67 | |
100 | 68 |
class SettingsDirectory(wcs.admin.settings.SettingsDirectory): |
101 | 69 |
def _q_index(self): |
102 |
if not (get_publisher().has_site_option('auquotidien-payments') or |
|
103 |
get_publisher().has_site_option('auquotidien-strongvox')): |
|
70 |
if not get_publisher().has_site_option('auquotidien-payments'): |
|
104 | 71 |
return super(SettingsDirectory, self)._q_index() |
105 | 72 |
r = TemplateIO(html=True) |
106 | 73 |
r += htmltext(super(SettingsDirectory, self)._q_index()) |
... | ... | |
109 | 76 |
r += htmltext('<h2>%s</h2>') % _('Extra Options') |
110 | 77 |
r += htmltext('<ul>') |
111 | 78 |
r += htmltext('<li><a href="aq/permissions">%s</a></li>') % _('Permissions') |
112 |
if get_publisher().has_site_option('strongbox'): |
|
113 |
r += htmltext('<li><a href="aq/strongbox">%s</a></li>') % _('Strongbox Support') |
|
114 | 79 |
if get_publisher().has_site_option('domino'): |
115 | 80 |
r += htmltext('<li><a href="aq/domino">%s</a></li>') % _('Abelium Domino Integration') |
116 | 81 |
r += htmltext('</ul>') |
auquotidien/modules/backoffice.py | ||
---|---|---|
28 | 28 |
target = target.strip('/') |
29 | 29 |
if target == 'management': |
30 | 30 |
target = 'forms' |
31 |
if target == 'strongbox': |
|
32 |
if not get_publisher().has_site_option(target): |
|
33 |
# strongbox disabled in site-options.cfg |
|
34 |
return False |
|
35 |
if not get_cfg('misc', {}).get('aq-strongbox'): |
|
36 |
# strongbox disabled in settings panel |
|
37 |
return False |
|
38 | 31 |
admin_role = get_cfg('aq-permissions', {}).get(target, None) |
39 | 32 |
if not admin_role: |
40 | 33 |
return False |
auquotidien/modules/myspace.py | ||
---|---|---|
25 | 25 |
from wcs.formdef import FormDef |
26 | 26 |
import wcs.myspace |
27 | 27 | |
28 |
from .strongbox import StrongboxItem, StrongboxType |
|
29 | 28 |
from .payments import Invoice, Regie, is_payment_supported |
30 | 29 | |
31 | 30 |
class MyInvoicesDirectory(Directory): |
... | ... | |
108 | 107 |
return r.getvalue() |
109 | 108 | |
110 | 109 | |
111 |
class StrongboxDirectory(Directory): |
|
112 |
_q_exports = ['', 'add', 'download', 'remove', 'pick', 'validate'] |
|
113 | ||
114 |
def _q_traverse(self, path): |
|
115 |
if not get_cfg('misc', {}).get('aq-strongbox'): |
|
116 |
raise errors.TraversalError() |
|
117 |
get_response().breadcrumb.append(('strongbox/', _('Strongbox'))) |
|
118 |
return Directory._q_traverse(self, path) |
|
119 | ||
120 |
def get_form(self): |
|
121 |
types = [(x.id, x.label) for x in StrongboxType.select()] |
|
122 |
form = Form(action='add', enctype='multipart/form-data') |
|
123 |
form.add(StringWidget, 'description', title=_('Description'), size=60) |
|
124 |
form.add(FileWidget, 'file', title=_('File'), required=True) |
|
125 |
form.add(SingleSelectWidget, 'type_id', title=_('Document Type'), |
|
126 |
options = [(None, _('Not specified'))] + types) |
|
127 |
form.add(DateWidget, 'date_time', title = _('Document Date')) |
|
128 |
form.add_submit('submit', _('Upload')) |
|
129 |
return form |
|
130 | ||
131 |
def _q_index(self): |
|
132 |
template.html_top(_('Strongbox')) |
|
133 |
r = TemplateIO(html=True) |
|
134 | ||
135 |
# TODO: a paragraph of explanations here could be useful |
|
136 | ||
137 |
sffiles = list(StrongboxItem.get_with_indexed_value( |
|
138 |
str('user_id'), str(get_request().user.id))) |
|
139 |
if sffiles: |
|
140 |
r += htmltext('<table id="strongbox-items">') |
|
141 |
r += htmltext('<tr><th></th><th>%s</th><th>%s</th><th></th></tr>') % ( |
|
142 |
_('Type'), _('Expiration')) |
|
143 |
else: |
|
144 |
r += htmltext('<p>') |
|
145 |
r += _('There is currently nothing in your strongbox.') |
|
146 |
r += htmltext('</p>') |
|
147 |
has_items_to_validate = False |
|
148 |
for i, sffile in enumerate(sffiles): |
|
149 |
expired = False |
|
150 |
if not sffile.validated_time: |
|
151 |
has_items_to_validate = True |
|
152 |
continue |
|
153 |
if sffile.expiration_time and sffile.expiration_time < time.localtime(): |
|
154 |
expired = True |
|
155 |
if i%2: |
|
156 |
classnames = ['odd'] |
|
157 |
else: |
|
158 |
classnames = ['even'] |
|
159 |
if expired: |
|
160 |
classnames.append('expired') |
|
161 |
r += htmltext('<tr class="%s">') % ' '.join(classnames) |
|
162 |
r += htmltext('<td class="label">') |
|
163 |
r += sffile.get_display_name() |
|
164 |
r += htmltext('</td>') |
|
165 |
if sffile.type_id: |
|
166 |
r += htmltext('<td class="type">%s</td>') % StrongboxType.get(sffile.type_id).label |
|
167 |
else: |
|
168 |
r += htmltext('<td class="type">-</td>') |
|
169 |
if sffile.expiration_time: |
|
170 |
r += htmltext('<td class="expiration">%s') % strftime(misc.date_format(), sffile.expiration_time) |
|
171 |
if expired: |
|
172 |
r += ' (%s)' % _('expired') |
|
173 |
r += htmltext('</td>') |
|
174 |
else: |
|
175 |
r += htmltext('<td class="expiration">-</td>') |
|
176 |
r += htmltext('<td class="actions">') |
|
177 |
r += htmltext(' [<a href="download?id=%s">%s</a>] ') % (sffile.id, _('download')) |
|
178 |
r += htmltext('[<a rel="popup" href="remove?id=%s">%s</a>] ') % (sffile.id, _('remove')) |
|
179 |
r += htmltext('</td>') |
|
180 |
r += htmltext('</tr>') |
|
181 | ||
182 |
if has_items_to_validate: |
|
183 |
r += htmltext('<tr><td colspan="4"><h3>%s</h3></td></tr>') % _('Proposed Items') |
|
184 |
for sffile in sffiles: |
|
185 |
if sffile.validated_time: |
|
186 |
continue |
|
187 |
if sffile.expiration_time and sffile.expiration_time < time.localtime(): |
|
188 |
expired = True |
|
189 |
if i%2: |
|
190 |
classnames = ['odd'] |
|
191 |
else: |
|
192 |
classnames = ['even'] |
|
193 |
if expired: |
|
194 |
classnames.append('expired') |
|
195 |
r += htmltext('<tr class="%s">') % ' '.join(classnames) |
|
196 | ||
197 |
r += htmltext('<td class="label">') |
|
198 |
r += sffile.get_display_name() |
|
199 |
r += htmltext('</td>') |
|
200 |
if sffile.type_id: |
|
201 |
r += htmltext('<td class="type">%s</td>') % StrongboxType.get(sffile.type_id).label |
|
202 |
else: |
|
203 |
r += htmltext('<td class="type">-</td>') |
|
204 | ||
205 |
if sffile.expiration_time: |
|
206 |
r += htmltext('<td class="expiration">%s') % strftime(misc.date_format(), sffile.expiration_time) |
|
207 |
if expired: |
|
208 |
r += ' (%s)' % _('expired') |
|
209 |
r += htmltext('</td>') |
|
210 |
else: |
|
211 |
r += htmltext('<td class="expiration">-</td>') |
|
212 |
r += htmltext('<td class="actions">') |
|
213 |
r += htmltext(' [<a href="download?id=%s">%s</a>] ') % (sffile.id, _('download')) |
|
214 |
r += htmltext(' [<a href="validate?id=%s">%s</a>] ') % (sffile.id, _('validate')) |
|
215 |
r += htmltext(' [<a href="remove?id=%s">%s</a>] ') % (sffile.id, _('reject')) |
|
216 |
r += htmltext('</td>') |
|
217 |
r += htmltext('</tr>') |
|
218 |
if sffiles: |
|
219 |
r += htmltext('</table>') |
|
220 | ||
221 |
r += htmltext('<h3>%s</h3>') % _('Add a file to the strongbox') |
|
222 |
form = self.get_form() |
|
223 |
r += form.render() |
|
224 |
return r.getvalue() |
|
225 | ||
226 |
def add(self): |
|
227 |
form = self.get_form() |
|
228 |
if not form.is_submitted(): |
|
229 |
if get_request().form.get('mode') == 'pick': |
|
230 |
return redirect('pick') |
|
231 |
else: |
|
232 |
return redirect('.') |
|
233 | ||
234 |
sffile = StrongboxItem() |
|
235 |
sffile.user_id = get_request().user.id |
|
236 |
sffile.description = form.get_widget('description').parse() |
|
237 |
sffile.validated_time = time.localtime() |
|
238 |
sffile.type_id = form.get_widget('type_id').parse() |
|
239 |
v = form.get_widget('date_time').parse() |
|
240 |
sffile.set_expiration_time_from_date(v) |
|
241 |
sffile.store() |
|
242 |
sffile.set_file(form.get_widget('file').parse()) |
|
243 |
sffile.store() |
|
244 |
if get_request().form.get('mode') == 'pick': |
|
245 |
return redirect('pick') |
|
246 |
else: |
|
247 |
return redirect('.') |
|
248 | ||
249 |
def download(self): |
|
250 |
id = get_request().form.get('id') |
|
251 |
if not id: |
|
252 |
raise errors.TraversalError() |
|
253 |
try: |
|
254 |
sffile = StrongboxItem.get(id) |
|
255 |
except KeyError: |
|
256 |
raise errors.TraversalError() |
|
257 |
if str(sffile.user_id) != str(get_request().user.id): |
|
258 |
raise errors.TraversalError() |
|
259 | ||
260 |
filename = sffile.file.filename |
|
261 |
fd = file(filename) |
|
262 |
size = os.path.getsize(filename) |
|
263 |
response = get_response() |
|
264 |
response.set_content_type('application/octet-stream') |
|
265 |
response.set_header('content-disposition', 'attachment; filename="%s"' % sffile.file.base_filename) |
|
266 |
return FileStream(fd, size) |
|
267 | ||
268 |
def validate(self): |
|
269 |
id = get_request().form.get('id') |
|
270 |
if not id: |
|
271 |
raise errors.TraversalError() |
|
272 |
try: |
|
273 |
sffile = StrongboxItem.get(id) |
|
274 |
except KeyError: |
|
275 |
raise errors.TraversalError() |
|
276 |
if str(sffile.user_id) != str(get_request().user.id): |
|
277 |
raise errors.TraversalError() |
|
278 |
sffile.validated_time = time.time() |
|
279 |
sffile.store() |
|
280 |
return redirect('.') |
|
281 | ||
282 |
def remove(self): |
|
283 |
id = get_request().form.get('id') |
|
284 |
if not id: |
|
285 |
raise errors.TraversalError() |
|
286 |
try: |
|
287 |
sffile = StrongboxItem.get(id) |
|
288 |
except KeyError: |
|
289 |
raise errors.TraversalError() |
|
290 |
if str(sffile.user_id) != str(get_request().user.id): |
|
291 |
raise errors.TraversalError() |
|
292 | ||
293 |
r = TemplateIO(html=True) |
|
294 |
form = Form(enctype='multipart/form-data') |
|
295 |
form.add_hidden('id', get_request().form.get('id')) |
|
296 |
form.widgets.append(HtmlWidget('<p>%s</p>' % _( |
|
297 |
'You are about to irrevocably delete this item from your strongbox.'))) |
|
298 |
form.add_submit('submit', _('Submit')) |
|
299 |
form.add_submit('cancel', _('Cancel')) |
|
300 |
if form.get_submit() == 'cancel': |
|
301 |
return redirect('.') |
|
302 |
if not form.is_submitted() or form.has_errors(): |
|
303 |
if sffile.type_id: |
|
304 |
r += htmltext('<h2>%s</h2>') % _('Deleting %(filetype)s: %(filename)s') % { |
|
305 |
'filetype': StrongboxType.get(sffile.type_id).label, |
|
306 |
'filename': sffile.get_display_name() |
|
307 |
} |
|
308 |
else: |
|
309 |
r += htmltext('<h2>%s</h2>') % _('Deleting %(filename)s') % {'filename': sffile.get_display_name()} |
|
310 |
r += form.render() |
|
311 |
return r.getvalue() |
|
312 |
else: |
|
313 |
sffile.remove_self() |
|
314 |
sffile.remove_file() |
|
315 |
return redirect('.') |
|
316 | ||
317 |
def picked_file(self): |
|
318 |
get_response().set_content_type('application/json') |
|
319 |
sffile = StrongboxItem.get(get_request().form.get('val')) |
|
320 |
sffile.file.fp = file(sffile.file.filename) |
|
321 |
if sffile.user_id != get_request().user.id: |
|
322 |
raise errors.TraversalError() |
|
323 |
# XXX: this will copy the file, it would be quite nice if it was |
|
324 |
# possible to just make it a symlink to the sffile |
|
325 |
token = get_session().add_tempfile(sffile.file) |
|
326 |
return json.dumps({'token': token, 'filename': sffile.file.base_filename}) |
|
327 | ||
328 |
def pick(self): |
|
329 |
if get_request().form.get('select') == 'true': |
|
330 |
return self.picked_file() |
|
331 |
r = TemplateIO(html=True) |
|
332 |
root_url = get_publisher().get_root_url() |
|
333 |
sffiles = list(StrongboxItem.get_with_indexed_value( |
|
334 |
str('user_id'), str(get_request().user.id))) |
|
335 |
r += htmltext('<h2>%s</h2>') % _('Pick a file') |
|
336 | ||
337 |
if not sffiles: |
|
338 |
r += htmltext('<p>') |
|
339 |
r += _('You do not have any file in your strongbox at the moment.') |
|
340 |
r += htmltext('</p>') |
|
341 |
r += htmltext('<div class="buttons">') |
|
342 |
r += htmltext('<a href="%smyspace/strongbox/" target="_blank">%s</a>') % (root_url, |
|
343 |
_('Open Strongbox Management')) |
|
344 |
r += htmltext('</div>') |
|
345 |
else: |
|
346 |
r += htmltext('<form id="strongbox-pick">') |
|
347 |
r += htmltext('<ul>') |
|
348 |
for sffile in sffiles: |
|
349 |
r += htmltext('<li><label><input type="radio" name="file" value="%s"/>%s</label>') % ( |
|
350 |
sffile.id, sffile.get_display_name()) |
|
351 |
r += htmltext(' [<a href="%smyspace/strongbox/download?id=%s">%s</a>] ') % ( |
|
352 |
root_url, sffile.id, _('view')) |
|
353 |
r += htmltext('</li>') |
|
354 |
r += htmltext('</ul>') |
|
355 | ||
356 |
r += htmltext('<div class="buttons">') |
|
357 |
r += htmltext('<input name="cancel" type="button" value="%s"/>') % _('Cancel') |
|
358 |
r += ' ' |
|
359 |
r += htmltext('<input name="pick" type="button" value="%s"/>') % _('Pick') |
|
360 |
r += htmltext('</div>') |
|
361 |
r += htmltext('</form>') |
|
362 |
return r.getvalue() |
|
363 | ||
364 | ||
365 | 110 |
class JsonDirectory(Directory): |
366 | 111 |
'''Export of several lists in json, related to the current user or the |
367 | 112 |
SAMLv2 NameID we'd get in the URL''' |
... | ... | |
410 | 155 | |
411 | 156 |
class MyspaceDirectory(wcs.myspace.MyspaceDirectory): |
412 | 157 |
_q_exports = ['', 'profile', 'new', 'password', 'remove', 'drafts', 'forms', |
413 |
'strongbox', 'invoices', 'json']
|
|
158 |
'invoices', 'json'] |
|
414 | 159 | |
415 |
strongbox = StrongboxDirectory() |
|
416 | 160 |
invoices = MyInvoicesDirectory() |
417 | 161 |
json = JsonDirectory() |
418 | 162 | |
... | ... | |
457 | 201 |
profile_links.append('<a href="#my-profile">%s</a>' % _('My Profile')) |
458 | 202 |
if user_forms: |
459 | 203 |
profile_links.append('<a href="#my-forms">%s</a>' % _('My Forms')) |
460 |
if get_cfg('misc', {}).get('aq-strongbox'): |
|
461 |
profile_links.append('<a href="strongbox/">%s</a>' % _('My Strongbox')) |
|
462 | 204 |
if is_payment_supported(): |
463 | 205 |
profile_links.append('<a href="invoices/">%s</a>' % _('My Invoices')) |
464 | 206 |
auquotidien/modules/strongbox.py | ||
---|---|---|
1 |
import os |
|
2 |
import time |
|
3 | ||
4 |
from quixote import get_publisher |
|
5 |
from wcs.qommon.storage import StorableObject |
|
6 |
from wcs.qommon import misc |
|
7 | ||
8 |
class StrongboxType(StorableObject): |
|
9 |
_names = 'strongbox-types' |
|
10 | ||
11 |
id = None |
|
12 |
label = None |
|
13 |
validation_months = 0 |
|
14 | ||
15 | ||
16 |
class StrongboxFile(): |
|
17 |
id = None |
|
18 |
orig_filename = None |
|
19 |
base_filename = None |
|
20 |
content_type = None |
|
21 |
charset = None |
|
22 | ||
23 |
def __init__(self, id, f): |
|
24 |
self.id = id |
|
25 |
self.orig_filename = f.orig_filename |
|
26 |
self.base_filename = f.base_filename |
|
27 |
self.content_type = f.content_type |
|
28 |
self.charset = f.charset |
|
29 |
self.fp = f.fp |
|
30 | ||
31 |
def __getstate__(self): |
|
32 |
odict = self.__dict__.copy() |
|
33 |
if not odict.has_key('fp'): |
|
34 |
return odict |
|
35 | ||
36 |
# XXX: add some locking |
|
37 |
del odict['fp'] |
|
38 |
dirname = os.path.join(get_publisher().app_dir, 'strongbox-files') |
|
39 |
if not os.path.exists(dirname): |
|
40 |
os.mkdir(dirname) |
|
41 |
odict['filename'] = os.path.join(dirname, str(self.id)) |
|
42 |
self.fp.seek(0) |
|
43 |
fd = file(odict['filename'], 'w') |
|
44 |
fd.write(self.fp.read()) |
|
45 |
fd.close() |
|
46 |
return odict |
|
47 | ||
48 | ||
49 |
class StrongboxItem(StorableObject): |
|
50 |
_names = 'strongbox-items' |
|
51 |
_hashed_indexes = ['user_id'] |
|
52 | ||
53 |
user_id = None |
|
54 |
description = None |
|
55 |
file = None |
|
56 |
type_id = None |
|
57 |
expiration_time = None |
|
58 |
proposed_by = None |
|
59 |
proposed_time = None |
|
60 |
validated_time = None |
|
61 | ||
62 |
def get_display_name(self): |
|
63 |
if self.description: |
|
64 |
return self.description |
|
65 |
return self.file.base_filename |
|
66 | ||
67 |
def set_file(self, file): |
|
68 |
self.file = StrongboxFile(self.id, file) |
|
69 | ||
70 |
def remove_file(self): |
|
71 |
os.unlink(self.file.filename) |
|
72 | ||
73 |
def set_expiration_time_from_date(self, value): |
|
74 |
if not value: |
|
75 |
self.expiration_time = None |
|
76 |
return |
|
77 |
if not StrongboxType.has_key(self.type_id): |
|
78 |
return |
|
79 | ||
80 |
if not StrongboxType.get(self.type_id).validation_months: |
|
81 |
self.expiration_time = None |
|
82 |
return |
|
83 | ||
84 |
date = time.strptime(value, misc.date_format()) |
|
85 |
year, month, day = date[:3] |
|
86 |
month += StrongboxType.get(self.type_id).validation_months |
|
87 |
while month > 12: |
|
88 |
year += 1 |
|
89 |
month -= 12 |
|
90 |
while True: |
|
91 |
try: |
|
92 |
self.expiration_time = time.strptime( |
|
93 |
'%04d-%02d-%02d' % (year, month, day), '%Y-%m-%d') |
|
94 |
except ValueError: |
|
95 |
day -= 1 |
|
96 |
continue |
|
97 |
break |
|
98 |
auquotidien/modules/strongbox_ui.py | ||
---|---|---|
1 |
import time |
|
2 | ||
3 |
from quixote import get_request, get_response, get_session, redirect |
|
4 |
from quixote.directory import Directory, AccessControlled |
|
5 |
from quixote.html import TemplateIO, htmltext |
|
6 | ||
7 |
import wcs |
|
8 |
import wcs.admin.root |
|
9 | ||
10 |
from wcs.qommon import _ |
|
11 |
from wcs.qommon import errors, misc |
|
12 |
from wcs.qommon.form import * |
|
13 |
from wcs.qommon.backoffice.menu import html_top |
|
14 |
from wcs.qommon import get_cfg |
|
15 | ||
16 |
from .strongbox import StrongboxType, StrongboxItem |
|
17 | ||
18 | ||
19 | ||
20 |
class StrongboxTypeDirectory(Directory): |
|
21 |
_q_exports = ['', 'edit', 'delete'] |
|
22 | ||
23 |
def __init__(self, strongboxtype): |
|
24 |
self.strongboxtype = strongboxtype |
|
25 | ||
26 |
def _q_index(self): |
|
27 |
html_top('strongbox', title = _('Item Type: %s') % self.strongboxtype.label) |
|
28 |
r = TemplateIO(html=True) |
|
29 |
r += htmltext('<h2>%s</h2>') % _('Item Type: %s') % self.strongboxtype.label |
|
30 |
get_response().filter['sidebar'] = self.get_sidebar() |
|
31 |
r += get_session().display_message() |
|
32 | ||
33 |
if self.strongboxtype.validation_months: |
|
34 |
r += htmltext('<div class="bo-block">') |
|
35 |
r += htmltext('<ul>') |
|
36 |
r += htmltext('<li>') |
|
37 |
r += _('Number of months of validity:') |
|
38 |
r += ' ' |
|
39 |
r += self.strongboxtype.validation_months |
|
40 |
r += htmltext('</li>') |
|
41 |
r += htmltext('</ul>') |
|
42 |
r += htmltext('</div>') |
|
43 | ||
44 |
return r.getvalue() |
|
45 | ||
46 |
def get_sidebar(self): |
|
47 |
r = TemplateIO(html=True) |
|
48 |
r += htmltext('<ul>') |
|
49 |
r += htmltext('<li><a href="edit">%s</a></li>') % _('Edit') |
|
50 |
r += htmltext('<li><a href="delete">%s</a></li>') % _('Delete') |
|
51 |
r += htmltext('</ul>') |
|
52 |
return r.getvalue() |
|
53 | ||
54 |
def edit(self): |
|
55 |
form = self.form() |
|
56 |
if form.get_submit() == 'cancel': |
|
57 |
return redirect('.') |
|
58 | ||
59 |
if form.is_submitted() and not form.has_errors(): |
|
60 |
self.submit(form) |
|
61 |
return redirect('..') |
|
62 | ||
63 |
html_top('strongbox', title = _('Edit Item Type: %s') % self.strongboxtype.label) |
|
64 |
r = TemplateIO(html=True) |
|
65 |
r += htmltext('<h2>%s</h2>') % _('Edit Item Type: %s') % self.strongboxtype.label |
|
66 |
r += form.render() |
|
67 |
return r.getvalue() |
|
68 | ||
69 |
def form(self): |
|
70 |
form = Form(enctype='multipart/form-data') |
|
71 |
form.add(StringWidget, 'label', title = _('Label'), required = True, |
|
72 |
value = self.strongboxtype.label) |
|
73 |
form.add(IntWidget, 'validation_months', title=_('Number of months of validity'), |
|
74 |
value=self.strongboxtype.validation_months, |
|
75 |
hint=_('Use 0 if there is no expiration')) |
|
76 |
form.add_submit('submit', _('Submit')) |
|
77 |
form.add_submit('cancel', _('Cancel')) |
|
78 |
return form |
|
79 | ||
80 |
def submit(self, form): |
|
81 |
for k in ('label', 'validation_months'): |
|
82 |
widget = form.get_widget(k) |
|
83 |
if widget: |
|
84 |
setattr(self.strongboxtype, k, widget.parse()) |
|
85 |
self.strongboxtype.store() |
|
86 | ||
87 |
def delete(self): |
|
88 |
form = Form(enctype='multipart/form-data') |
|
89 |
form.widgets.append(HtmlWidget('<p>%s</p>' % _( |
|
90 |
'You are about to irrevocably delete this item type.'))) |
|
91 |
form.add_submit('submit', _('Submit')) |
|
92 |
form.add_submit('cancel', _('Cancel')) |
|
93 |
if form.get_submit() == 'cancel': |
|
94 |
return redirect('..') |
|
95 |
if not form.is_submitted() or form.has_errors(): |
|
96 |
get_response().breadcrumb.append(('delete', _('Delete'))) |
|
97 |
html_top('strongbox', title = _('Delete Item Type')) |
|
98 |
r = TemplateIO(html=True) |
|
99 |
r += htmltext('<h2>%s</h2>') % _('Deleting Item Type: %s') % self.strongboxtype.label |
|
100 |
r += form.render() |
|
101 |
return r.getvalue() |
|
102 |
else: |
|
103 |
self.strongboxtype.remove_self() |
|
104 |
return redirect('..') |
|
105 | ||
106 | ||
107 |
class StrongboxTypesDirectory(Directory): |
|
108 |
_q_exports = ['', 'new'] |
|
109 | ||
110 |
def _q_traverse(self, path): |
|
111 |
get_response().breadcrumb.append(('types/', _('Item Types'))) |
|
112 |
return Directory._q_traverse(self, path) |
|
113 | ||
114 |
def _q_index(self): |
|
115 |
return redirect('..') |
|
116 | ||
117 |
def new(self): |
|
118 |
type_ui = StrongboxTypeDirectory(StrongboxType()) |
|
119 | ||
120 |
form = type_ui.form() |
|
121 |
if form.get_submit() == 'cancel': |
|
122 |
return redirect('.') |
|
123 | ||
124 |
if form.is_submitted() and not form.has_errors(): |
|
125 |
type_ui.submit(form) |
|
126 |
return redirect('%s/' % type_ui.strongboxtype.id) |
|
127 | ||
128 |
get_response().breadcrumb.append(('new', _('New Item Type'))) |
|
129 |
html_top('strongbox', title = _('New Item Type')) |
|
130 |
r = TemplateIO(html=True) |
|
131 |
r += htmltext('<h2>%s</h2>') % _('New Item Type') |
|
132 |
r += form.render() |
|
133 |
return r.getvalue() |
|
134 | ||
135 |
def _q_lookup(self, component): |
|
136 |
try: |
|
137 |
strongboxtype = StrongboxType.get(component) |
|
138 |
except KeyError: |
|
139 |
raise errors.TraversalError() |
|
140 |
get_response().breadcrumb.append((str(strongboxtype.id), strongboxtype.label)) |
|
141 |
return StrongboxTypeDirectory(strongboxtype) |
|
142 | ||
143 | ||
144 |
class StrongboxDirectory(AccessControlled, Directory): |
|
145 |
_q_exports = ['', 'types', 'add', 'add_to'] |
|
146 |
label = N_('Strongbox') |
|
147 | ||
148 |
types = StrongboxTypesDirectory() |
|
149 | ||
150 |
def is_accessible(self, user): |
|
151 |
from .backoffice import check_visibility |
|
152 |
return check_visibility('strongbox', user) |
|
153 | ||
154 |
def _q_access(self): |
|
155 |
user = get_request().user |
|
156 |
if not user: |
|
157 |
raise errors.AccessUnauthorizedError() |
|
158 | ||
159 |
if not self.is_accessible(user): |
|
160 |
raise errors.AccessForbiddenError( |
|
161 |
public_msg = _('You are not allowed to access Strongbox Management'), |
|
162 |
location_hint = 'backoffice') |
|
163 | ||
164 |
get_response().breadcrumb.append(('strongbox/', _('Strongbox'))) |
|
165 | ||
166 | ||
167 |
def _q_index(self): |
|
168 |
html_top('strongbox', _('Strongbox')) |
|
169 |
r = TemplateIO(html=True) |
|
170 |
get_response().filter['sidebar'] = self.get_sidebar() |
|
171 | ||
172 |
r += get_session().display_message() |
|
173 | ||
174 |
r += htmltext('<div class="splitcontent-left">') |
|
175 |
r += htmltext('<div class="bo-block">') |
|
176 |
r += htmltext('<h2>%s</h2>') % _('Propose a file to a user') |
|
177 |
form = Form(enctype='multipart/form-data') |
|
178 |
form.add(StringWidget, 'q', title = _('User'), required=True) |
|
179 |
form.add_submit('search', _('Search')) |
|
180 |
r += form.render() |
|
181 |
if form.is_submitted() and not form.has_errors(): |
|
182 |
q = form.get_widget('q').parse() |
|
183 |
users = self.search_for_users(q) |
|
184 |
if users: |
|
185 |
if len(users) == 1: |
|
186 |
return redirect('add_to?user_id=%s' % users[0].id) |
|
187 |
if len(users) < 50: |
|
188 |
r += _('(first 50 users only)') |
|
189 |
r += htmltext('<ul>') |
|
190 |
for u in users: |
|
191 |
r += htmltext('<li><a href="add_to?user_id=%s">%s</a></li>') % (u.id, u.display_name) |
|
192 |
r += htmltext('</ul>') |
|
193 |
else: |
|
194 |
r += _('No user found.') |
|
195 |
r += htmltext('</div>') |
|
196 |
r += htmltext('</div>') |
|
197 | ||
198 |
r += htmltext('<div class="splitcontent-right">') |
|
199 |
r += htmltext('<div class="bo-block">') |
|
200 |
types = StrongboxType.select() |
|
201 |
r += htmltext('<h2>%s</h2>') % _('Item Types') |
|
202 |
if not types: |
|
203 |
r += htmltext('<p>') |
|
204 |
r += _('There is no item types defined at the moment.') |
|
205 |
r += htmltext('</p>') |
|
206 | ||
207 |
r += htmltext('<ul class="biglist" id="strongbox-list">') |
|
208 |
for l in types: |
|
209 |
type_id = l.id |
|
210 |
r += htmltext('<li class="biglistitem" id="itemId_%s">') % type_id |
|
211 |
r += htmltext('<strong class="label"><a href="types/%s/">%s</a></strong>') % (type_id, l.label) |
|
212 |
r += htmltext('</li>') |
|
213 |
r += htmltext('</ul>') |
|
214 |
r += htmltext('</div>') |
|
215 |
r += htmltext('</div>') |
|
216 |
return r.getvalue() |
|
217 | ||
218 |
def get_sidebar(self): |
|
219 |
r = TemplateIO(html=True) |
|
220 |
r += htmltext('<ul id="sidebar-actions">') |
|
221 |
r += htmltext(' <li><a class="new-item" href="types/new">%s</a></li>') % _('New Item Type') |
|
222 |
r += htmltext('</ul>') |
|
223 |
return r.getvalue() |
|
224 | ||
225 |
def search_for_users(self, q): |
|
226 |
if hasattr(get_publisher().user_class, 'search'): |
|
227 |
return get_publisher().user_class.search(q) |
|
228 |
if q: |
|
229 |
users = [x for x in get_publisher().user_class.select() |
|
230 |
if q in (x.name or '') or q in (x.email or '')] |
|
231 |
return users |
|
232 |
else: |
|
233 |
return [] |
|
234 | ||
235 |
def get_form(self): |
|
236 |
types = [(x.id, x.label) for x in StrongboxType.select()] |
|
237 |
form = Form(action='add', enctype='multipart/form-data') |
|
238 |
form.add(StringWidget, 'description', title=_('Description'), size=60) |
|
239 |
form.add(FileWidget, 'file', title=_('File'), required=True) |
|
240 |
form.add(SingleSelectWidget, 'type_id', title=_('Document Type'), |
|
241 |
options = [(None, _('Not specified'))] + types) |
|
242 |
form.add(DateWidget, 'date_time', title = _('Document Date')) |
|
243 |
form.add_submit('submit', _('Upload')) |
|
244 |
return form |
|
245 | ||
246 |
def add(self): |
|
247 |
form = self.get_form() |
|
248 |
form.add(StringWidget, 'user_id', title=_('User')) |
|
249 |
if not form.is_submitted(): |
|
250 |
return redirect('.') |
|
251 | ||
252 |
sffile = StrongboxItem() |
|
253 |
sffile.user_id = form.get_widget('user_id').parse() |
|
254 |
sffile.description = form.get_widget('description').parse() |
|
255 |
sffile.proposed_time = time.localtime() |
|
256 |
sffile.proposed_id = get_request().user.id |
|
257 |
sffile.type_id = form.get_widget('type_id').parse() |
|
258 |
v = form.get_widget('date_time').parse() |
|
259 |
sffile.set_expiration_time_from_date(v) |
|
260 |
sffile.store() |
|
261 |
sffile.set_file(form.get_widget('file').parse()) |
|
262 |
sffile.store() |
|
263 |
return redirect('.') |
|
264 | ||
265 |
def add_to(self): |
|
266 |
form = Form(enctype='multipart/form-data', action='add_to') |
|
267 |
form.add(StringWidget, 'user_id', title = _('User'), required=True) |
|
268 |
try: |
|
269 |
user_id = form.get_widget('user_id').parse() |
|
270 |
user = get_publisher().user_class.get(user_id) |
|
271 |
except: |
|
272 |
return redirect('.') |
|
273 |
if not user: |
|
274 |
return redirect('.') |
|
275 |
get_request().form = {} |
|
276 |
get_request().environ['REQUEST_METHOD'] = 'GET' |
|
277 | ||
278 |
html_top('strongbox', _('Strongbox')) |
|
279 |
r = TemplateIO(html=True) |
|
280 |
r += htmltext('<h2>%s %s</h2>') % (_('Propose a file to:'), user.display_name) |
|
281 |
form = self.get_form() |
|
282 |
form.add(HiddenWidget, 'user_id', title=_('User'), value=user.id) |
|
283 |
r += form.render() |
|
284 |
return r.getvalue() |
|
285 |
- |