0001-backoffice-make-it-possible-to-submit-forms-from-the.patch
tests/test_admin_pages.py | ||
---|---|---|
553 | 553 | |
554 | 554 |
app = login(get_app(pub)) |
555 | 555 |
resp = app.get('/backoffice/forms/1/') |
556 |
resp = resp.click('change', href='roles') |
|
556 |
resp = resp.click('change', href='roles', index=0)
|
|
557 | 557 |
resp = resp.forms[0].submit('cancel') |
558 | 558 | |
559 | 559 |
resp = app.get('/backoffice/forms/1/') |
560 |
resp = resp.click('change', href='roles') |
|
560 |
resp = resp.click('change', href='roles', index=0)
|
|
561 | 561 |
resp.forms[0]['roles$element0'].value = role.name |
562 | 562 |
resp = resp.forms[0].submit('submit') |
563 | 563 |
assert FormDef.get(1).roles == [role.id] |
... | ... | |
921 | 921 |
assert resp.forms[0]['workflow_id'].value |
922 | 922 | |
923 | 923 |
resp = app.get('/backoffice/forms/1/') |
924 |
resp = resp.click('change', href='roles') |
|
924 |
resp = resp.click('change', href='roles', index=0)
|
|
925 | 925 |
assert resp.forms[0]['roles$element0'].value == 'Logged Users' |
926 | 926 |
assert resp.forms[0]['roles$element1'].value == 'ZAB' |
927 | 927 |
tests/test_backoffice_pages.py | ||
---|---|---|
38 | 38 |
if pub.user_class.select(lambda x: x.name == 'admin'): |
39 | 39 |
user1 = pub.user_class.select(lambda x: x.name == 'admin')[0] |
40 | 40 |
user1.is_admin = is_admin |
41 |
user1.roles = [x.id for x in Role.select() if x.name == 'foobar'] |
|
41 | 42 |
user1.store() |
42 | 43 |
return user1 |
43 | 44 |
user1 = pub.user_class(name='admin') |
... | ... | |
453 | 454 |
resp.forms[0]['end'] = '2014-12-31' |
454 | 455 |
resp = resp.forms[0].submit() |
455 | 456 |
assert 'Total count: 20' in resp.body |
457 | ||
458 |
def test_backoffice_submission(pub): |
|
459 |
user = create_user(pub) |
|
460 |
create_environment(pub) |
|
461 | ||
462 |
app = login(get_app(pub)) |
|
463 |
resp = app.get('/backoffice/') |
|
464 |
assert 'Submission' in resp.body |
|
465 | ||
466 |
resp = resp.click('Submission', index=0) |
|
467 |
formdef = FormDef.select()[0] |
|
468 |
assert not formdef.url_name in resp.body |
|
469 | ||
470 |
formdef.backoffice_submission_roles = user.roles[:] |
|
471 |
formdef.store() |
|
472 |
resp = app.get('/backoffice/submission/') |
|
473 |
assert formdef.url_name in resp.body |
|
474 | ||
475 |
resp = resp.click(formdef.name) |
|
476 |
resp.form['f1'] = 'test submission' |
|
477 |
resp.form['f2'] = 'baz' |
|
478 |
resp.form['f3'] = 'C' |
|
479 |
resp = resp.form.submit('submit') |
|
480 |
assert 'Check values then click submit.' in resp.body |
|
481 | ||
482 |
# going back to first page, to check |
|
483 |
resp = resp.form.submit('previous') |
|
484 |
assert resp.form['f1'].value == 'test submission' |
|
485 |
resp = resp.form.submit('submit') |
|
486 | ||
487 |
# final submit |
|
488 |
resp = resp.form.submit('submit') |
|
489 | ||
490 |
formdata_no = resp.location.split('/')[-2] |
|
491 |
data_class = formdef.data_class() |
|
492 |
assert data_class.get(formdata_no).data['1'] == 'test submission' |
|
493 |
assert data_class.get(formdata_no).data['2'] == 'baz' |
|
494 |
assert data_class.get(formdata_no).status == 'wf-new' |
|
495 |
assert data_class.get(formdata_no).user is None |
|
496 | ||
497 |
resp = resp.follow() # get to the formdata page |
|
498 | ||
499 |
formdata_count = data_class.count() |
|
500 | ||
501 |
# test submission when agent is not receiver |
|
502 |
formdef.workflow_roles = {} |
|
503 |
formdef.store() |
|
504 |
resp = app.get('/backoffice/submission/') |
|
505 |
resp = resp.click(formdef.name) |
|
506 |
resp.form['f1'] = 'test submission' |
|
507 |
resp.form['f2'] = 'baz' |
|
508 |
resp.form['f3'] = 'C' |
|
509 |
resp = resp.form.submit('submit') # to validation screen |
|
510 |
resp = resp.form.submit('submit') # final submit |
|
511 |
assert resp.location == 'http://example.net/backoffice/submission/' |
|
512 |
resp = resp.follow() # should go back to submission screen |
|
513 | ||
514 |
assert data_class.count() == formdata_count + 1 |
|
515 | ||
516 |
def test_backoffice_submission_tracking_code(pub): |
|
517 |
user = create_user(pub) |
|
518 |
create_environment(pub) |
|
519 | ||
520 |
app = login(get_app(pub)) |
|
521 |
resp = app.get('/backoffice/') |
|
522 |
assert 'Submission' in resp.body |
|
523 | ||
524 |
resp = resp.click('Submission', index=0) |
|
525 |
formdef = FormDef.select()[0] |
|
526 |
assert not formdef.url_name in resp.body |
|
527 | ||
528 |
formdef.enable_tracking_codes = True |
|
529 |
formdef.backoffice_submission_roles = user.roles[:] |
|
530 |
formdef.store() |
|
531 |
data_class = formdef.data_class() |
|
532 |
data_class.wipe() |
|
533 |
resp = app.get('/backoffice/submission/') |
|
534 |
assert formdef.url_name in resp.body |
|
535 | ||
536 |
resp = resp.click(formdef.name) |
|
537 |
resp.form['f1'] = 'test submission' |
|
538 |
resp.form['f2'] = 'baz' |
|
539 |
resp.form['f3'] = 'C' |
|
540 |
resp = resp.form.submit('submit') |
|
541 |
assert 'Check values then click submit.' in resp.body |
|
542 | ||
543 |
# stop here, don't validate, let user finish it. |
|
544 |
assert data_class.count() == 1 |
|
545 |
formdata_no = data_class.select()[0].id |
|
546 |
tracking_code = data_class.select()[0].tracking_code |
|
547 | ||
548 |
assert data_class.get(formdata_no).data['1'] == 'test submission' |
|
549 |
assert data_class.get(formdata_no).data['2'] == 'baz' |
|
550 |
assert data_class.get(formdata_no).status == 'draft' |
|
551 |
assert data_class.get(formdata_no).user is None |
|
552 | ||
553 |
resp = get_app(pub).get('/code/%s/load' % data_class.select()[0].tracking_code) |
|
554 |
resp = resp.follow() |
|
555 |
assert resp.location.startswith('http://example.net/form-title/?mt=') |
|
556 |
resp = resp.follow() |
|
557 |
assert 'Check values then click submit.' in resp.body |
|
558 |
assert 'test submission' in resp.body |
wcs/admin/forms.py | ||
---|---|---|
290 | 290 |
('workflow-status-remapping', 'workflow_status_remapping'), |
291 | 291 |
'roles', 'title', 'options', ('acl-read', 'acl_read'), |
292 | 292 |
'overwrite', 'qrcode', 'information', |
293 |
('public-url', 'public_url')] |
|
293 |
('public-url', 'public_url'), |
|
294 |
('backoffice-submission-roles', 'backoffice_submission_roles'),] |
|
294 | 295 | |
295 | 296 |
def __init__(self, component): |
296 | 297 |
try: |
... | ... | |
415 | 416 |
r += htmltext('</ul>') |
416 | 417 |
r += htmltext('</li>') |
417 | 418 | |
418 |
r += htmltext('<li>%s ') % _('User Roles:') |
|
419 |
if self.formdef.roles: |
|
420 |
roles = [] |
|
421 |
for x in self.formdef.roles: |
|
422 |
if x == logged_users_role().id: |
|
423 |
roles.append(logged_users_role().name) |
|
424 |
else: |
|
425 |
try: |
|
426 |
roles.append(htmltext('<a href="../../roles/%s/">%s</a>') % (x, Role.get(x).name)) |
|
427 |
except KeyError: |
|
428 |
# removed role ? |
|
429 |
roles.append(htmltext('<em>%s</em>') % _('Unknown role (%s)') % role_id) |
|
430 |
r += htmltext(', ').join(roles) |
|
431 |
else: |
|
432 |
r += '-' |
|
433 |
r += ' ' |
|
434 |
r += htmltext('(<a href="roles" rel="popup">%s</a>)') % _('change') |
|
435 |
r += htmltext('</li>') |
|
419 |
r += self._display_roles(_('User Roles:'), 'roles', 'roles') |
|
420 |
r += self._display_roles(_('Backoffice Submission Roles:'), |
|
421 |
'backoffice_submission_roles', |
|
422 |
'backoffice-submission-roles') |
|
436 | 423 | |
437 | 424 |
r += htmltext('<li>%s ') % _('Read Access:') |
438 | 425 |
r += '%s' % {'none': _('None'), |
... | ... | |
498 | 485 |
r += htmltext('</div>') |
499 | 486 |
return r.getvalue() |
500 | 487 | |
488 |
def _display_roles(self, title, attribute, change_url): |
|
489 |
r = TemplateIO(html=True) |
|
490 |
r += htmltext('<li>%s ') % title |
|
491 |
if getattr(self.formdef, attribute): |
|
492 |
roles = [] |
|
493 |
for x in getattr(self.formdef, attribute): |
|
494 |
if x == logged_users_role().id: |
|
495 |
roles.append(logged_users_role().name) |
|
496 |
else: |
|
497 |
try: |
|
498 |
roles.append(htmltext('<a href="../../roles/%s/">%s</a>') % (x, Role.get(x).name)) |
|
499 |
except KeyError: |
|
500 |
# removed role ? |
|
501 |
roles.append(htmltext('<em>%s</em>') % _('Unknown role (%s)') % role_id) |
|
502 |
r += htmltext(', ').join(roles) |
|
503 |
else: |
|
504 |
r += '-' |
|
505 |
r += ' ' |
|
506 |
r += htmltext('(<a href="%s" rel="popup">%s</a>)') % ( |
|
507 |
change_url, _('change')) |
|
508 |
r += htmltext('</li>') |
|
509 |
return r.getvalue() |
|
510 | ||
501 | 511 |
def get_sidebar(self): |
502 | 512 |
r = TemplateIO(html=True) |
503 | 513 |
r += htmltext('<ul id="sidebar-actions">') |
... | ... | |
613 | 623 |
attribute='roles', |
614 | 624 |
description=_('Select the roles that can access this form.')) |
615 | 625 | |
626 |
def backoffice_submission_roles(self): |
|
627 |
return self._roles_selection( |
|
628 |
title=_('Backoffice Submission Roles'), |
|
629 |
attribute='backoffice_submission_roles', |
|
630 |
include_logged_users_role=False, |
|
631 |
description=_('Select the roles that will be allowed to ' |
|
632 |
'fill out forms of this kind in the backoffice.')) |
|
633 | ||
616 | 634 |
def title(self): |
617 | 635 |
form = Form(enctype='multipart/form-data') |
618 | 636 |
form.add(StringWidget, 'name', title=_('Form Title'), required=True, |
wcs/backoffice/root.py | ||
---|---|---|
39 | 39 |
import wcs.admin.users |
40 | 40 |
import wcs.admin.workflows |
41 | 41 | |
42 |
from . import submission |
|
42 | 43 |
from . import management |
43 | 44 | |
44 | 45 | |
... | ... | |
54 | 55 |
users = wcs.admin.users.UsersDirectory() |
55 | 56 |
workflows = wcs.admin.workflows.WorkflowsDirectory() |
56 | 57 |
management = management.ManagementDirectory() |
58 |
submission = submission.SubmissionDirectory() |
|
57 | 59 | |
58 | 60 |
menu_items = [ |
59 | 61 |
('management/', N_('Management')), |
62 |
('submission/', N_('Submission')), |
|
60 | 63 |
('forms/', N_('Forms Workshop')), |
61 | 64 |
('workflows/', N_('Workflows Workshop')), |
62 | 65 |
('users/', N_('Users')), |
... | ... | |
104 | 107 | |
105 | 108 |
# for some subdirectories, the user needs to be part of a role allowed |
106 | 109 |
# to go in the backoffice |
107 |
if subdirectory in ('management',): |
|
110 |
if subdirectory in ('management', 'submission'):
|
|
108 | 111 |
return get_request().user.can_go_in_backoffice() |
109 | 112 | |
110 | 113 |
# for the other directories, an extra level is required, the user needs |
... | ... | |
272 | 275 |
'slug': slug, |
273 | 276 |
'url': backoffice_url + k}) |
274 | 277 |
if slug in ('home', 'forms', 'workflows', 'users', 'roles', |
275 |
'categories', 'settings', 'management'): |
|
278 |
'categories', 'settings', 'management', 'submission'):
|
|
276 | 279 |
menu_items[-1]['icon'] = k.strip('/') |
277 | 280 |
return menu_items |
wcs/backoffice/submission.py | ||
---|---|---|
1 |
# w.c.s. - web application for online forms |
|
2 |
# Copyright (C) 2005-2015 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or modify |
|
5 |
# it under the terms of the GNU General Public License as published by |
|
6 |
# the Free Software Foundation; either version 2 of the License, or |
|
7 |
# (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU General Public License |
|
15 |
# along with this program; if not, see <http://www.gnu.org/licenses/>. |
|
16 | ||
17 |
from quixote import get_publisher, get_request, get_response, get_session, redirect |
|
18 |
from quixote.directory import Directory |
|
19 |
from quixote.html import TemplateIO, htmltext |
|
20 | ||
21 |
from qommon.backoffice.menu import html_top |
|
22 |
from qommon import errors |
|
23 | ||
24 |
from wcs.formdef import FormDef |
|
25 |
from wcs.categories import Category |
|
26 |
from wcs.forms.root import FormPage as PublicFormFillPage |
|
27 | ||
28 | ||
29 |
class FormFillPage(PublicFormFillPage): |
|
30 |
def html_top(self, *args, **kwargs): |
|
31 |
return html_top('submission', *args, **kwargs) |
|
32 | ||
33 |
def check_role(self): |
|
34 |
if not self.formdef.backoffice_submission_roles: |
|
35 |
raise errors.AccessUnauthorizedError() |
|
36 |
for role in get_request().user.roles or []: |
|
37 |
if role in self.formdef.backoffice_submission_roles: |
|
38 |
break |
|
39 |
else: |
|
40 |
raise errors.AccessUnauthorizedError() |
|
41 | ||
42 |
def get_sidebar(self, data): |
|
43 |
r = TemplateIO(html=True) |
|
44 | ||
45 |
if self.formdef.enable_tracking_codes: |
|
46 |
draft_formdata_id = data.get('draft_formdata_id') |
|
47 |
r += htmltext('<h3>%s</h3>') % _('Tracking Code') |
|
48 |
tracking_code = None |
|
49 |
if draft_formdata_id: |
|
50 |
formdata = self.formdef.data_class().get(draft_formdata_id) |
|
51 |
if formdata.tracking_code: |
|
52 |
tracking_code = formdata.tracking_code |
|
53 |
if tracking_code: |
|
54 |
r += htmltext('<p>%s</p>') % tracking_code |
|
55 |
else: |
|
56 |
r += htmltext('<p>-</p>') |
|
57 | ||
58 |
return r.getvalue() |
|
59 | ||
60 |
def form_side(self, step_no, page_no=0, log_detail=None, data=None, editing=None): |
|
61 |
r = TemplateIO(html=True) |
|
62 |
get_response().filter['sidebar'] = self.get_sidebar(data) |
|
63 |
r += htmltext('<div id="side">') |
|
64 |
r += self.step(step_no, page_no, log_detail, data=data, editing=editing) |
|
65 |
r += htmltext('</div> <!-- #side -->') |
|
66 |
return r.getvalue() |
|
67 | ||
68 |
def submitted(self, form, *args): |
|
69 |
filled = self.formdef.data_class()() |
|
70 |
filled.just_created() |
|
71 |
filled.data = self.formdef.get_data(form) |
|
72 |
filled.store() |
|
73 | ||
74 |
self.keep_tracking_code(filled) |
|
75 |
get_session().remove_magictoken(get_request().form.get('magictoken')) |
|
76 | ||
77 |
url = filled.perform_workflow() |
|
78 |
if not url: |
|
79 |
url = filled.get_url(backoffice=True) |
|
80 | ||
81 |
if not self.formdef.is_of_concern_for_user(self.user, filled): |
|
82 |
# if the agent is not allowed to see the submitted formdef, |
|
83 |
# redirect to the submission homepage |
|
84 |
return redirect(get_publisher().get_backoffice_url() + '/submission/') |
|
85 | ||
86 |
return redirect(url) |
|
87 | ||
88 |
def save_draft(self, data, page_no): |
|
89 |
formdata = super(FormFillPage, self).save_draft(data, page_no) |
|
90 |
formdata.user_id = None |
|
91 |
formdata.store() |
|
92 |
return formdata |
|
93 | ||
94 | ||
95 |
class SubmissionDirectory(Directory): |
|
96 |
_q_exports = [''] |
|
97 | ||
98 |
def _q_index(self): |
|
99 |
get_response().breadcrumb.append(('submission/', _('Submission'))) |
|
100 |
html_top('submission', _('Submission')) |
|
101 |
user = get_request().user |
|
102 | ||
103 |
list_forms = [] |
|
104 |
for formdef in FormDef.select(order_by='name', ignore_errors=True): |
|
105 |
if formdef.is_disabled(): |
|
106 |
continue |
|
107 |
if not formdef.backoffice_submission_roles: |
|
108 |
continue |
|
109 |
for role in user.roles or []: |
|
110 |
if role in formdef.backoffice_submission_roles: |
|
111 |
break |
|
112 |
else: |
|
113 |
continue |
|
114 |
list_forms.append(formdef) |
|
115 | ||
116 |
r = TemplateIO(html=True) |
|
117 | ||
118 |
cats = Category.select() |
|
119 |
Category.sort_by_position(cats) |
|
120 |
one = False |
|
121 |
for c in cats: |
|
122 |
l2 = [x for x in list_forms if str(x.category_id) == str(c.id)] |
|
123 |
if l2: |
|
124 |
r += self.form_list(l2, title=c.name) |
|
125 |
one = True |
|
126 | ||
127 |
l2 = [x for x in list_forms if not x.category] |
|
128 |
if l2: |
|
129 |
if one: |
|
130 |
title = _('Misc') |
|
131 |
else: |
|
132 |
title = None |
|
133 |
r += self.form_list(l2, title=title) |
|
134 | ||
135 |
return r.getvalue() |
|
136 | ||
137 |
def form_list(self, formdefs, title=None): |
|
138 |
r = TemplateIO(html=True) |
|
139 |
r += htmltext('<div class="bo-block">') |
|
140 |
if title: |
|
141 |
r += htmltext('<h2>%s</h2>') % title |
|
142 | ||
143 |
r += htmltext('<ul class="biglist">') |
|
144 |
for formdef in formdefs: |
|
145 |
r += htmltext('<li>') |
|
146 |
r += htmltext('<strong class="label"><a href="%s/">%s</a></strong>') % ( |
|
147 |
formdef.url_name, formdef.name) |
|
148 |
r += htmltext('</li>') |
|
149 |
r += htmltext('</ul>') |
|
150 |
r += htmltext('</div>') |
|
151 |
return r.getvalue() |
|
152 | ||
153 |
def _q_lookup(self, component): |
|
154 |
get_response().breadcrumb.append(('submission/', _('Submission'))) |
|
155 |
return FormFillPage(component) |
wcs/formdef.py | ||
---|---|---|
67 | 67 |
workflow_options = None |
68 | 68 |
workflow_roles = None |
69 | 69 |
roles = None |
70 |
backoffice_submission_roles = None |
|
70 | 71 |
discussion = False |
71 | 72 |
confirmation = True |
72 | 73 |
detailed_emails = True |
wcs/forms/root.py | ||
---|---|---|
222 | 222 |
self.user = get_request().user |
223 | 223 |
get_response().breadcrumb.append( (component + '/', self.formdef.name) ) |
224 | 224 | |
225 |
def html_top(self, *args, **kwargs): |
|
226 |
html_top(*args, **kwargs) |
|
227 | ||
225 | 228 |
def get_substitution_variables(self): |
226 | 229 |
return self.substvars |
227 | 230 | |
... | ... | |
375 | 378 |
v = data[k] |
376 | 379 |
elif field.prefill: |
377 | 380 |
v = field.get_prefill_value() |
381 |
if get_request().get_path().startswith('/backoffice/') and ( |
|
382 |
field.prefill and field.prefill.get('type') in ('user', 'geoloc')): |
|
383 |
# turn off prefilling from user and geolocation |
|
384 |
# attributes if the form is filled from the backoffice |
|
385 |
v = None |
|
378 | 386 |
if v: |
379 | 387 |
prefilled = True |
380 | 388 |
form.get_widget('f%s' % k).set_message( |
... | ... | |
395 | 403 |
if not one: |
396 | 404 |
req.form = {} |
397 | 405 | |
398 |
html_top(self.formdef.name) |
|
406 |
self.html_top(self.formdef.name)
|
|
399 | 407 |
r += self.form_side(0, page_no, log_detail=log_detail, data=data, editing=editing) |
400 | 408 | |
401 | 409 |
form.add_hidden('step', '0') |
... | ... | |
505 | 513 |
if data.has_key('page_no'): |
506 | 514 |
page_no = int(data['page_no']) |
507 | 515 |
del data['page_no'] |
508 |
if page_no == -1: |
|
516 |
if page_no == -1 or page_no >= self.page_number:
|
|
509 | 517 |
req = get_request() |
510 | 518 |
for k, v in data.items(): |
511 | 519 |
req.form['f%s' % k] = v |
... | ... | |
799 | 807 |
except AttributeError: |
800 | 808 |
filled.user_id = get_request().user.id |
801 | 809 | |
810 |
if get_request().get_path().startswith('/backoffice/'): |
|
811 |
filled.user_id = None |
|
812 | ||
802 | 813 |
if self.formdef.only_allow_one: |
803 | 814 |
# this is already checked in _q_index but it's done a second time |
804 | 815 |
# just before a new form is to be stored. |
... | ... | |
819 | 830 |
get_session().mark_anonymous_formdata(filled) |
820 | 831 | |
821 | 832 |
if not url: |
822 |
url = filled.get_url() |
|
833 |
if get_request().get_path().startswith('/backoffice/'): |
|
834 |
url = filled.get_url(backoffice=True) |
|
835 |
else: |
|
836 |
url = filled.get_url() |
|
823 | 837 |
return redirect(url) |
824 | 838 | |
825 | 839 |
def keep_tracking_code(self, formdata): |
... | ... | |
869 | 883 |
return get_session().get_tempfile_content(t).get_file_pointer().read() |
870 | 884 | |
871 | 885 |
def validating(self, data): |
872 |
html_top(self.formdef.name) |
|
886 |
self.html_top(self.formdef.name)
|
|
873 | 887 |
r = TemplateIO(html=True) |
874 | 888 |
r += htmltext('<div class="form-validation">') |
875 | 889 |
r += self.form_side(step_no=1, data=data) |
... | ... | |
892 | 906 |
return r.getvalue() |
893 | 907 | |
894 | 908 |
def error(self, msg): |
895 |
html_top(self.formdef.name) |
|
909 |
self.html_top(self.formdef.name)
|
|
896 | 910 |
homepage = get_publisher().get_root_url() |
897 | 911 |
r = TemplateIO(html=True) |
898 | 912 |
r += htmltext('<div class="errornotice">%s</div>') % msg |
... | ... | |
903 | 917 |
if not self.formdef.is_user_allowed_read(get_request().user): |
904 | 918 |
raise errors.AccessForbiddenError() |
905 | 919 |
get_response().breadcrumb.append( ('listing', _('Listing')) ) |
906 |
html_top('%s - %s' % (_('Listing'), self.formdef.name)) |
|
920 |
self.html_top('%s - %s' % (_('Listing'), self.formdef.name))
|
|
907 | 921 |
r = TemplateIO(html=True) |
908 | 922 | |
909 | 923 |
fields = [] |
wcs/qommon/static/css/dc2/admin.css | ||
---|---|---|
864 | 864 |
li.zone-home a { background-image: url(icons/home.large.png); } |
865 | 865 |
li.zone-home a:hover { background-image: url(icons/home.large-hover.png); } |
866 | 866 | |
867 |
li.zone-submission a { background-image: url(icons/submission.large.png); } |
|
868 |
li.zone-submission a:hover { background-image: url(icons/submission.large-hover.png); } |
|
869 | ||
867 | 870 |
ul.apps li.zone-no-icon a { |
868 | 871 |
height: 29px; |
869 | 872 |
padding-top: 24px; |
870 |
- |