Forget about the all storage thing, use sqlobject to store everything,
currently defaulting to SQLite. Everything old is imported and new again.
This commit is contained in:
parent
5e275d0bc6
commit
e4a72346a7
|
@ -1,3 +1,15 @@
|
|||
wcs (0.3.9cvs-0) unstable; urgency=low
|
||||
|
||||
* CVS snapshot; now using SQLObject.
|
||||
|
||||
-- Frederic Peters <fpeters@debian.org> Mon, 22 Aug 2005 15:20:12 +0200
|
||||
|
||||
wcs (0.1.9cvs-0) unstable; urgency=low
|
||||
|
||||
* CVS snapshot.
|
||||
|
||||
-- Frederic Peters <fpeters@debian.org> Thu, 4 Aug 2005 10:51:42 +0200
|
||||
|
||||
wcs (0.0.0-0) unstable; urgency=low
|
||||
|
||||
* Initial package.
|
||||
|
|
|
@ -7,7 +7,7 @@ Standards-Version: 3.6.5.0
|
|||
|
||||
Package: wcs
|
||||
Architecture: all
|
||||
Depends: python2.3, quixote (>= 2.0), libapache2-mod-scgi | libapache-mod-scgi, python2.3-scgi
|
||||
Depends: python2.3, quixote (>= 2.0), libapache2-mod-scgi | libapache-mod-scgi, python2.3-scgi, python2.3-sqlobject, python2.3-sqlite
|
||||
Description: w.c.s. (1st draft)
|
||||
.
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ import os
|
|||
import lasso
|
||||
import __builtin__
|
||||
|
||||
import storage
|
||||
from sqlobject import *
|
||||
|
||||
import gettext, locale
|
||||
|
||||
gettext.install('wcs')
|
||||
|
@ -26,6 +27,22 @@ import misc
|
|||
import errors
|
||||
import sessions
|
||||
|
||||
import anonylink
|
||||
import categories
|
||||
import consultationdef
|
||||
import formdata
|
||||
import formdef
|
||||
import roles
|
||||
import users
|
||||
|
||||
sqlobject_classes = [anonylink.AnonymityLink, categories.Category,
|
||||
roles.RoleEmail, roles.Role, users.NameIdentifier, users.User,
|
||||
formdef.FormField, formdef.FormDef,
|
||||
consultationdef.ConsultationField, consultationdef.Consultation,
|
||||
formdata.FormDataEvolution, formdata.FormData,
|
||||
sessions.SqlSession,
|
||||
]
|
||||
|
||||
from root import RootDirectory
|
||||
|
||||
class WcsPublisher(Publisher):
|
||||
|
@ -41,6 +58,16 @@ class WcsPublisher(Publisher):
|
|||
self.config.display_exceptions = debug_cfg.get('display_exceptions')
|
||||
self.config.form_tokens = True
|
||||
|
||||
def set_connection(self):
|
||||
self.conn = connectionForURI('sqlite://%s/wcs.db' % self.app_dir)
|
||||
for klass in sqlobject_classes:
|
||||
klass.setConnection(self.conn)
|
||||
if not self.conn.tableExists(klass._table):
|
||||
klass.createTable()
|
||||
if hasattr(klass, 'initTable'):
|
||||
klass.initTable()
|
||||
if hasattr(klass, 'migrateOldData'):
|
||||
klass.migrateOldData()
|
||||
|
||||
class WcsVHostPublisher(WcsPublisher):
|
||||
def try_publish(self, request):
|
||||
|
@ -48,6 +75,7 @@ class WcsVHostPublisher(WcsPublisher):
|
|||
if not os.path.exists(self.app_dir):
|
||||
os.mkdir(self.app_dir)
|
||||
self.set_config()
|
||||
self.set_connection()
|
||||
return WcsPublisher.try_publish(self, request)
|
||||
|
||||
|
||||
|
@ -59,8 +87,9 @@ def create_publisher(publisher_class = WcsPublisher):
|
|||
publisher.data_dir = DATA_DIR
|
||||
if not os.path.exists(publisher.app_dir):
|
||||
os.mkdir(publisher.app_dir)
|
||||
publisher.set_session_manager(sessions.StorageSessionManager())
|
||||
publisher.set_session_manager(sessions.SqlSessionManager())
|
||||
publisher.set_config()
|
||||
publisher.set_connection()
|
||||
return publisher
|
||||
|
||||
def create_vhost_publisher():
|
||||
|
|
|
@ -14,24 +14,15 @@ class CategoryUI:
|
|||
|
||||
def form_new(self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
auto_id = misc.cfg.get('misc', {}).get('auto-id', False)
|
||||
if not auto_id:
|
||||
form.add(StringWidget, "id", title = _('Category Id'), required = True, size=30,
|
||||
value = self.category.id)
|
||||
form.add(StringWidget, "name", title = _('Category Name'), required = True, size=30,
|
||||
value = self.category.name)
|
||||
form.add(StringWidget, "name", title = _('Category Name'), required = True, size=30)
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
return form
|
||||
|
||||
def form_edit(self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
auto_id = misc.cfg.get('misc', {}).get('auto-id', False)
|
||||
if auto_id:
|
||||
form.add_hidden("id", value = self.category.id)
|
||||
else:
|
||||
form.add(StringWidget, "id", title = _('Category Id'), required = False, size=30,
|
||||
value = self.category.id, readonly = 'readonly')
|
||||
form.add(StringWidget, "id", title = _('Category Id'), required = False, size=30,
|
||||
value = self.category.id, readonly = 'readonly')
|
||||
form.add(StringWidget, "name", title = _('Category Name'), required = True, size=30,
|
||||
value = self.category.name)
|
||||
form.add_submit("submit", _("Submit"))
|
||||
|
@ -39,20 +30,10 @@ class CategoryUI:
|
|||
return form
|
||||
|
||||
def submit_form(self, form):
|
||||
for f in ('name',):
|
||||
setattr(self.category, f, form.get_widget(f).parse())
|
||||
if not hasattr(self.category, 'id') or not self.category.id:
|
||||
auto_id = misc.cfg.get('misc', {}).get('auto-id', False)
|
||||
if auto_id:
|
||||
new_id = base_id = misc.simplify(self.category.name)
|
||||
existing_ids = storage.get_storage().keys('formdefs')
|
||||
i = 1
|
||||
while new_id in existing_ids:
|
||||
new_id = '%s-%d' % (base_id, i)
|
||||
i += 1
|
||||
self.category.id = new_id
|
||||
else:
|
||||
self.category.id = form.get_widget('id').parse()
|
||||
if self.category:
|
||||
self.category.name = form.get_widget('name').parse()
|
||||
else:
|
||||
category = Category(name = form.get_widget('name').parse())
|
||||
|
||||
|
||||
|
||||
|
@ -60,7 +41,7 @@ class CategoryPage(Directory):
|
|||
_q_exports = ["edit", "delete"]
|
||||
|
||||
def __init__(self, component):
|
||||
self.category = storage.get_storage().retrieve('categories', component)
|
||||
self.category = Category.get(component)
|
||||
self.category_ui = CategoryUI(self.category)
|
||||
|
||||
def edit [html] (self):
|
||||
|
@ -75,7 +56,6 @@ class CategoryPage(Directory):
|
|||
html_foot()
|
||||
else:
|
||||
self.category_ui.submit_form(form)
|
||||
storage.get_storage().store(self.category)
|
||||
return redirect('..')
|
||||
|
||||
def delete [html] (self):
|
||||
|
@ -92,7 +72,7 @@ class CategoryPage(Directory):
|
|||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
storage.get_storage().remove_id('categories', self.category.id)
|
||||
self.category.destroySelf()
|
||||
return redirect('..')
|
||||
|
||||
|
||||
|
@ -113,20 +93,18 @@ class CategoriesDirectory(Directory):
|
|||
</ul>""" % _('New Category')
|
||||
|
||||
'<div class="biglist">'
|
||||
for k in storage.get_storage().keys('categories'):
|
||||
category = storage.get_storage().retrieve('categories', k)
|
||||
for category in Category.select(orderBy = Category.q.name):
|
||||
"""<div class="biglist-item">"""
|
||||
"<h3>%s</h3>" % category.name
|
||||
"""<p><span class="cmds"> [ """
|
||||
"""<a href="%s/edit">%s</a> - """ % (k, _('Edit'))
|
||||
"""<a href="%s/delete">%s</a> """ % (k, _('Delete'))
|
||||
"""<a href="%s/edit">%s</a> - """ % (category.id, _('Edit'))
|
||||
"""<a href="%s/delete">%s</a> """ % (category.id, _('Delete'))
|
||||
"]</span></p></div>"
|
||||
'</div>'
|
||||
html_foot()
|
||||
|
||||
def new [html] (self):
|
||||
category = Category()
|
||||
category_ui = CategoryUI(category)
|
||||
category_ui = CategoryUI(None)
|
||||
form = category_ui.form_new()
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('.')
|
||||
|
@ -138,7 +116,6 @@ class CategoriesDirectory(Directory):
|
|||
html_foot()
|
||||
else:
|
||||
category_ui.submit_form(form)
|
||||
storage.get_storage().store(category)
|
||||
return redirect('.')
|
||||
|
||||
def _q_lookup(self, component):
|
||||
|
|
|
@ -4,31 +4,35 @@ from quixote.directory import Directory
|
|||
from menu import html_top, html_foot, error_page
|
||||
|
||||
from wcs import misc
|
||||
from wcs import storage
|
||||
from wcs.errors import *
|
||||
from wcs.form import *
|
||||
from wcs.consultationdef import Consultation
|
||||
from wcs.consultationdef import Consultation, ConsultationField
|
||||
from wcs.formdata import FormData
|
||||
from wcs.users import User
|
||||
from wcs.categories import Category
|
||||
from wcs.roles import Role
|
||||
|
||||
def ellipsize(s, length = 30):
|
||||
if not s or len(s) < length:
|
||||
return s
|
||||
return s[:length-5] + ' (...)'
|
||||
|
||||
def get_user_roles():
|
||||
l = []
|
||||
for role in storage.get_storage().values('roles'):
|
||||
l.append( (role.id, role.name) )
|
||||
return l
|
||||
def get_user_roles(include_system = False):
|
||||
r = []
|
||||
for x in Role.select():
|
||||
if x.system:
|
||||
if include_system:
|
||||
r.append( (x.id, _(x.name)) )
|
||||
else:
|
||||
r.append( (x.id, x.name) )
|
||||
return r
|
||||
|
||||
def get_categories():
|
||||
l = []
|
||||
for category in storage.get_storage().values('categories'):
|
||||
l.append( (category.id, category.name) )
|
||||
return l
|
||||
return [(x.id, x.name) for x in Category.select()]
|
||||
|
||||
|
||||
|
||||
question_types = [ ('string', _('Text (line)')),
|
||||
field_types = [ ('string', _('Text (line)')),
|
||||
('text', _('Text (block)')),
|
||||
('email', _('Email Address')),
|
||||
('bool', _('Check Box')),
|
||||
|
@ -41,29 +45,31 @@ question_types = [ ('string', _('Text (line)')),
|
|||
]
|
||||
|
||||
class QuestionWidget(CompositeWidget):
|
||||
def __init__(self, name, value=None, **kwargs):
|
||||
def __init__(self, name, value=None, consultation = None, **kwargs):
|
||||
CompositeWidget.__init__(self, name, value, **kwargs)
|
||||
if not value:
|
||||
value = {}
|
||||
self.value = value
|
||||
self.add(TextWidget, 'question', value.get('question', ''), render_br = False,
|
||||
if self.value is None:
|
||||
self.value = {}
|
||||
self.add(HiddenWidget, 'id', self.value.get('id'))
|
||||
self.add(TextWidget, 'label', self.value.get('label', ''), render_br = False,
|
||||
cols = 70, rows = 3)
|
||||
self.add(SingleSelectWidget, 'answer', value.get('answer', ''), required=True,
|
||||
options = question_types, render_br = False)
|
||||
self.add(SingleSelectWidget, 'type', self.value.get('type'), required=True,
|
||||
options = field_types)
|
||||
|
||||
def render_content [html] (self):
|
||||
question_widget = self.get_widget('question')
|
||||
question_widget.render()
|
||||
_("Answer")
|
||||
answer_widget = self.get_widget('answer')
|
||||
answer_widget.render()
|
||||
id_widget = self.get_widget('id')
|
||||
id_widget.render()
|
||||
label_widget = self.get_widget('label')
|
||||
label_widget.render()
|
||||
_("Type")
|
||||
type_widget = self.get_widget('type')
|
||||
type_widget.render()
|
||||
'<hr />'
|
||||
|
||||
def _parse(self, request):
|
||||
for k in ('question', 'answer'):
|
||||
self.value[k] = self.get(k)
|
||||
if not self.value.has_key('required'):
|
||||
self.value['required'] = True
|
||||
self.value['id'] = self.get('id')
|
||||
self.value['label'] = self.get('label')
|
||||
self.value['type'] = self.get('type')
|
||||
|
||||
|
||||
class ConsultationUI:
|
||||
|
@ -72,80 +78,104 @@ class ConsultationUI:
|
|||
|
||||
def edit_form_ui(self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
auto_id = misc.cfg.get('misc', {}).get('auto-id', False)
|
||||
if not auto_id:
|
||||
form.add(StringWidget, "id", title = _('Consultation Id'), required = True, size=30,
|
||||
value = self.consultation.id)
|
||||
form.add(StringWidget, "name", title = _('Consultation Name'), required = True, size=30,
|
||||
value = self.consultation.name)
|
||||
value = self.consultation and self.consultation.name)
|
||||
if self.consultation and self.consultation.fields:
|
||||
fields_list = [{'label': x.label, 'type': x.type, 'id': x.id} \
|
||||
for x in self.consultation.fields]
|
||||
else:
|
||||
fields_list = []
|
||||
form.add(WidgetList, 'questions', title = _('Questions'), element_type = QuestionWidget,
|
||||
value = self.consultation.questions, add_element_label = _('Add Question'),
|
||||
element_kwargs = {'render_br': False})
|
||||
value = fields_list, add_element_label = _('Add Field'),
|
||||
element_kwargs = {'render_br': False, 'consultation': self.consultation})
|
||||
form.add(SingleSelectWidget, 'receiver', title = _('Recipient'), required = True,
|
||||
value = self.consultation.receiver, options = get_user_roles())
|
||||
value = self.consultation and self.consultation.receiverID,
|
||||
options = get_user_roles())
|
||||
form.add(WidgetList, 'roles', title = _('Roles'), element_type = SingleSelectWidget,
|
||||
hint = _('Only show this consultation to the given roles.'),
|
||||
value = self.consultation.roles, add_element_label = _('Add Role'),
|
||||
value = self.consultation and [x.id for x in self.consultation.roles],
|
||||
add_element_label = _('Add Role'),
|
||||
element_kwargs = {'render_br': False,
|
||||
'options': [('', '---'), ('logged-users', _('Logged Users'))] + get_user_roles()})
|
||||
'options': [('', '---')] + get_user_roles(include_system = True)})
|
||||
form.add(SingleSelectWidget, 'category', title = _('Category'),
|
||||
value = self.consultation.category,
|
||||
value = self.consultation and self.consultation.categoryID,
|
||||
options = [('', '---')] + get_categories())
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
return form
|
||||
|
||||
def submit_form(self, form):
|
||||
for f in ('name', 'questions', 'receiver', 'category'):
|
||||
setattr(self.consultation, f, form.get_widget(f).parse())
|
||||
if self.consultation:
|
||||
consultation = self.consultation
|
||||
else:
|
||||
consultation = Consultation(name = form.get_widget('name').parse())
|
||||
|
||||
if not hasattr(self.consultation, 'id') or not self.consultation.id:
|
||||
auto_id = misc.cfg.get('misc', {}).get('auto-id', False)
|
||||
if auto_id:
|
||||
new_id = base_id = misc.simplify(self.consultation.name)
|
||||
existing_ids = storage.get_storage().keys('consultations')
|
||||
i = 1
|
||||
while new_id in existing_ids:
|
||||
new_id = '%s-%d' % (base_id, i)
|
||||
i += 1
|
||||
self.consultation.id = new_id
|
||||
for f in ('name', ):
|
||||
setattr(consultation, f, form.get_widget(f).parse())
|
||||
|
||||
receiver = form.get_widget('receiver').parse()
|
||||
if receiver:
|
||||
consultation.receiver = Role.get(receiver)
|
||||
category = form.get_widget('category').parse()
|
||||
if category:
|
||||
consultation.category = Role.get(category)
|
||||
|
||||
for field in form.get_widget('fields').parse():
|
||||
if not field['label']:
|
||||
if field['id']:
|
||||
FormField.delete(field['id'])
|
||||
continue
|
||||
if field['id']:
|
||||
form_field = ConsultationField.get(field['id'])
|
||||
form_field.set(label = field['label'], type = field['type'])
|
||||
else:
|
||||
self.consultation.id = form.get_widget('id').parse()
|
||||
self.consultation.questions = [x for x in self.consultation.questions if x['question']] # remove empty questions
|
||||
self.consultation.roles = [x for x in form.get_widget('roles').parse() if x]
|
||||
form_field = ConsultationField(label = field['label'], type = field['type'],
|
||||
consultation = self.consultation)
|
||||
|
||||
class ConsultationFieldPage(Directory):
|
||||
new_roles = [x for x in form.get_widget('roles').parse() if x]
|
||||
for role in consultation.roles or []:
|
||||
if not role.id in new_roles:
|
||||
consultation.removeRole(role)
|
||||
for role_id in new_roles:
|
||||
if not role_id in [x.id for x in consultation.roles]:
|
||||
consultation.addRole(Role.get(role_id))
|
||||
|
||||
return consultation
|
||||
|
||||
|
||||
|
||||
class FieldDefPage(Directory):
|
||||
_q_exports = ['', 'delete', 'down', 'up']
|
||||
|
||||
def __init__(self, consultation, question_no):
|
||||
self.consultation = consultation
|
||||
self.question_no = question_no
|
||||
def __init__(self, field_id):
|
||||
self.field = ConsultationField.get(field_id)
|
||||
|
||||
def form(self):
|
||||
value = self.consultation.questions[self.question_no]
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add(TextWidget, 'question', title = _('Question'), value = value.get('question', ''),
|
||||
readonly = "readonly", cols = 70, rows = 3)
|
||||
form.add(SingleSelectWidget, 'answer', title = _('Answer'),
|
||||
value = value.get('answer', ''), required=True,
|
||||
options = question_types)
|
||||
form.add(TextWidget, 'label', title = _('Label'), value = self.field.label,
|
||||
cols = 70, rows = 3, required = True)
|
||||
form.add(SingleSelectWidget, 'type', title = _('Type'),
|
||||
value = self.field.type, required=True,
|
||||
options = field_types)
|
||||
form.add(CheckboxWidget, 'required', title = _('Required'),
|
||||
value = value.get('required', False))
|
||||
value = self.field.required)
|
||||
|
||||
if value.get('answer') == 'item':
|
||||
current_type = form.get_widget('type').parse()
|
||||
|
||||
if current_type == 'item':
|
||||
form.add(WidgetList, 'items', title = _('Items'), element_type = StringWidget,
|
||||
value = value.get('items', []), required = True,
|
||||
value = self.field.extra.get('items', []), required = True,
|
||||
element_kwargs = {'render_br': False})
|
||||
form.add(CheckboxWidget, 'show-as-radio', title = _('Show as radio buttons'),
|
||||
value = value.get('show-as-radio', False))
|
||||
elif value.get('answer') == 'text':
|
||||
value = self.field.extra.get('show-as-radio', False))
|
||||
elif current_type == 'text':
|
||||
form.add(StringWidget, 'cols', title = _('Line length'),
|
||||
value = value.get('cols', ''))
|
||||
value = self.field.extra.get('cols', ''))
|
||||
form.add(StringWidget, 'rows', title = _('Number of rows'),
|
||||
value = value.get('rows', ''))
|
||||
elif value.get('answer') == 'string':
|
||||
value = self.field.extra.get('rows', ''))
|
||||
elif current_type == 'string':
|
||||
form.add(StringWidget, 'size', title = _('Line length'),
|
||||
value = value.get('size', ''))
|
||||
value = self.field.extra.get('size', ''))
|
||||
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
|
@ -153,39 +183,41 @@ class ConsultationFieldPage(Directory):
|
|||
return form
|
||||
|
||||
def _q_index [html] (self):
|
||||
value = self.consultation.questions[self.question_no]
|
||||
form = self.form()
|
||||
redo = False
|
||||
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('../questions')
|
||||
return redirect('../../%s/fields' % self.field.consultationID)
|
||||
|
||||
if form.get_widget('items') and form.get_widget('items').get_widget('add_element').parse():
|
||||
form.clear_errors()
|
||||
redo = True
|
||||
if form.get_widget('items') and form.get_widget('type').parse() != 'list':
|
||||
form.clear_errors()
|
||||
redo = True
|
||||
|
||||
if redo or not form.is_submitted() or form.has_errors():
|
||||
html_top('consultations', '%s - %s' % (_('Consultation'), self.consultation.name))
|
||||
'<h2>%s - %s</h2>' % (self.consultation.name, value['question'])
|
||||
html_top('consultations', '%s - %s' % (
|
||||
_('Consultation'), self.field.consultation.name))
|
||||
'<h2>%s - %s</h2>' % (self.field.consultation.name, self.field.label)
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
self.submit(form)
|
||||
if form.get_widget('items') is None and value['answer'] == 'item':
|
||||
if form.get_widget('items') is None and self.field.type == 'item':
|
||||
return redirect('.')
|
||||
return redirect('../questions')
|
||||
return redirect('../../%s/fields' % self.field.consultationID)
|
||||
|
||||
def submit(self, form):
|
||||
value = self.consultation.questions[self.question_no]
|
||||
for f in ('question', 'answer', 'required', 'items', 'show-as-radio',
|
||||
'rows', 'cols', 'size'):
|
||||
for f in ('label', 'type', 'required'):
|
||||
setattr(self.field, f, form.get_widget(f).parse())
|
||||
extra = {}
|
||||
for f in ('items', 'show-as-radio', 'rows', 'cols', 'size'):
|
||||
w = form.get_widget(f)
|
||||
if not w:
|
||||
if value.has_key(f):
|
||||
del value[f]
|
||||
continue
|
||||
value[f] = w.parse()
|
||||
storage.get_storage().store(self.consultation)
|
||||
extra[f] = w.parse()
|
||||
self.field.extra = extra
|
||||
|
||||
def delete [html] (self):
|
||||
value = self.consultation.questions[self.question_no]
|
||||
|
@ -202,114 +234,82 @@ class ConsultationFieldPage(Directory):
|
|||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
del self.consultation.questions[self.question_no]
|
||||
storage.get_storage().store(self.consultation)
|
||||
return redirect('../questions')
|
||||
pos = self.field.position
|
||||
consultation = self.field.consultation
|
||||
self.field.destroySelf()
|
||||
for field in consultation.fields:
|
||||
if field.position > pos:
|
||||
field.position = field.position - 1
|
||||
return redirect('../../%s/fields' % self.field.consultationID)
|
||||
|
||||
def down(self):
|
||||
t = self.consultation.questions[self.question_no]
|
||||
self.consultation.questions[self.question_no] = self.consultation.questions[self.question_no+1]
|
||||
self.consultation.questions[self.question_no+1] = t
|
||||
storage.get_storage().store(self.consultation)
|
||||
return redirect('../questions')
|
||||
next = [x for x in self.field.consultation.fields if x.position == self.field.position+1][0]
|
||||
self.field.position = self.field.position+1
|
||||
next.position = next.position-1
|
||||
return redirect('../../%s/fields' % self.field.consultationID)
|
||||
|
||||
def up(self):
|
||||
t = self.consultation.questions[self.question_no]
|
||||
self.consultation.questions[self.question_no] = self.consultation.questions[self.question_no-1]
|
||||
self.consultation.questions[self.question_no-1] = t
|
||||
storage.get_storage().store(self.consultation)
|
||||
return redirect('../questions')
|
||||
prev = [x for x in self.field.consultation.fields if x.position == self.field.position-1][0]
|
||||
self.field.position = self.field.position-1
|
||||
prev.position = prev.position+1
|
||||
return redirect('../../%s/fields' % self.field.consultationID)
|
||||
|
||||
|
||||
|
||||
class ConsultationPage(Directory):
|
||||
_q_exports = ["questions", "edit", "delete", "listing", "csv", "duplicate"]
|
||||
_q_exports = ["fields", "edit", "delete", "duplicate"]
|
||||
|
||||
def __init__(self, component):
|
||||
self.consultation = storage.get_storage().retrieve('consultations', component)
|
||||
try:
|
||||
self.consultation = Consultation.get(component)
|
||||
except SQLObjectNotFound:
|
||||
raise TraversalError()
|
||||
self.consultationui = ConsultationUI(self.consultation)
|
||||
|
||||
def questions [html] (self):
|
||||
def fields [html] (self):
|
||||
html_top('consultations', '%s - %s' % (_('Consultation'), self.consultation.name))
|
||||
'<h2>%s</h2>' % self.consultation.name
|
||||
'<table>'
|
||||
for i, question in enumerate(self.consultation.questions):
|
||||
for i, field in enumerate(self.consultation.fields):
|
||||
'<tr>'
|
||||
if question['answer'] in ('subtitle', 'title', 'comment'):
|
||||
label = question['question']
|
||||
if field.type in ('subtitle', 'title', 'comment'):
|
||||
label = field.label
|
||||
if len(label) > 40:
|
||||
label = label[:35] + ' (...)'
|
||||
if question['answer'] in ('subtitle', 'title'):
|
||||
if field.type in ('subtitle', 'title'):
|
||||
'<td colspan="4"><strong>%s</strong></td>' % label
|
||||
else:
|
||||
'<td colspan="4">%s</td>' % label
|
||||
else:
|
||||
answer = [x[1] for x in question_types if x[0] == question['answer']][0]
|
||||
if question.has_key('required') and question['required']:
|
||||
type = [x[1] for x in field_types if x[0] == field.type][0]
|
||||
if field.required:
|
||||
required = ''
|
||||
else:
|
||||
required = _('optional')
|
||||
'<td>%s</td>' % question['question']
|
||||
'<td>%s</td>' % answer
|
||||
'<td>%s</td>' % field.label
|
||||
'<td>%s</td>' % type
|
||||
'<td>%s</td>' % required
|
||||
'<td><a href="question-%d">%s</a></td>' % (i, _('Edit'))
|
||||
'<td><a href="../fields/%d/">%s</a></td>' % (field.id, _('Edit'))
|
||||
|
||||
'<td><a href="question-%d/delete">%s</a></td>' % (i, _('Delete'))
|
||||
'<td><a href="../fields/%d/delete">%s</a></td>' % (field.id, _('Delete'))
|
||||
'<td>'
|
||||
if i != 0:
|
||||
'<a class="arrow" href="question-%d/up">%s</a>' % (i, '↑')
|
||||
'<a class="arrow" href="../fields/%d/up">%s</a>' % (field.id, '↑')
|
||||
'</td><td>'
|
||||
if i+1 != len(self.consultation.questions):
|
||||
'<a class="arrow" href="question-%d/down">%s</a>' % (i, '↓')
|
||||
if i+1 != len(self.consultation.fields):
|
||||
'<a class="arrow" href="../fields/%d/up">%s</a>' % (field.id, '↓')
|
||||
'</td>'
|
||||
'</tr>'
|
||||
'</table>'
|
||||
|
||||
html_foot()
|
||||
|
||||
def listing [html] (self):
|
||||
html_top('consultations', '%s - %s' % (_('Consultation'), self.consultation.name))
|
||||
names = 'consultation-' + self.consultation.id
|
||||
'<h2>%s</h2>' % self.consultation.name
|
||||
'<a href="csv">%s</a>' % _('Export to CSV format')
|
||||
'<table id="listing"><thead><tr>'
|
||||
for f in self.consultation.questions:
|
||||
if f['answer'] in ('title', 'subtitle'):
|
||||
continue
|
||||
"<th>%s</th>" % f['question']
|
||||
"</tr></thead>"
|
||||
"<tbody>"
|
||||
for k in storage.get_storage().keys(names):
|
||||
filled = storage.get_storage().retrieve(names, k)
|
||||
"<tr>"
|
||||
for f in self.consultation.questions:
|
||||
if f['answer'] in ('title', 'subtitle'):
|
||||
continue
|
||||
"<td>%s</td>" % filled.data.get(f['question'], '')
|
||||
"</tr>"
|
||||
"</tbody></table>"
|
||||
html_foot()
|
||||
|
||||
def csv [plain] (self):
|
||||
names = 'consultation-' + self.consultation.id
|
||||
|
||||
def fixcsv(s):
|
||||
if isinstance(s, basestring):
|
||||
return s.replace('\n', ' ').replace(';', ',')
|
||||
return str(s)
|
||||
|
||||
for k in storage.get_storage().keys(names):
|
||||
filled = storage.get_storage().retrieve(names, k)
|
||||
';'.join([fixcsv(filled.data.get(x['question'])) for x in self.consultation.questions]) + '\r\n'
|
||||
response = get_response()
|
||||
response.set_content_type('text/csv')
|
||||
|
||||
def edit [html] (self, duplicate = False):
|
||||
form = self.consultationui.edit_form_ui()
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('.')
|
||||
redo = False
|
||||
if form.get_widget('questions').get_widget('add_element').parse():
|
||||
if form.get_widget('fields').get_widget('add_element').parse():
|
||||
form.clear_errors()
|
||||
redo = True
|
||||
|
||||
|
@ -327,10 +327,9 @@ class ConsultationPage(Directory):
|
|||
html_foot()
|
||||
else:
|
||||
self.consultationui.submit_form(form)
|
||||
storage.get_storage().store(self.consultation)
|
||||
return redirect('..')
|
||||
|
||||
def duplicate [html] (self):
|
||||
def duplicate [html] (self): # XXX: FIXME for SQLObject
|
||||
self.consultationui.consultation.id = ''
|
||||
return self.edit(duplicate = True)
|
||||
|
||||
|
@ -348,30 +347,27 @@ class ConsultationPage(Directory):
|
|||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
storage.get_storage().remove_id('consultations', self.consultation.id)
|
||||
storage.get_storage().remove_all('consultation-%s' % self.consultation.id)
|
||||
for formdata in FormData.select(FormData.q.consultationID == self.consultation.id):
|
||||
formdata.destroySelf()
|
||||
self.consultation.destroySelf()
|
||||
return redirect('..')
|
||||
|
||||
|
||||
class FieldsDirectory(Directory):
|
||||
def _q_lookup(self, component):
|
||||
if not component.startswith('question-'):
|
||||
raise TraversalError()
|
||||
try:
|
||||
question_no = int(component[9:])
|
||||
except ValueError:
|
||||
raise TraversalError()
|
||||
return ConsultationFieldPage(self.consultation, question_no)
|
||||
|
||||
|
||||
return FieldDefPage(component)
|
||||
|
||||
class ConsultationsDirectory(Directory):
|
||||
|
||||
_q_exports = ["", "new"]
|
||||
_q_exports = ['', 'new', 'fields']
|
||||
|
||||
fields = FieldsDirectory()
|
||||
|
||||
def _q_index [html] (self):
|
||||
misc.reload_cfg()
|
||||
html_top('consultations', title = _('Consultations'))
|
||||
|
||||
if len(get_user_roles()) > 0:
|
||||
if Role.select().count > 1:
|
||||
"""<ul id="nav-consultations-admin">
|
||||
<li><a href="new">%s</a></li>
|
||||
</ul>""" % _('New Consultation')
|
||||
|
@ -379,23 +375,21 @@ class ConsultationsDirectory(Directory):
|
|||
"<p>%s</p>" % _('You first have to define roles.')
|
||||
|
||||
'<div class="biglist">'
|
||||
for k in storage.get_storage().keys('consultations'):
|
||||
consultation = storage.get_storage().retrieve('consultations', k)
|
||||
for consultation in Consultation.select():
|
||||
'<div class="biglist-item">'
|
||||
'<h3>%s</h3>' % consultation.name
|
||||
'<p><span class="data">%s</span>' % ellipsize(consultation.receiver, 50)
|
||||
'<p><span class="data">%s</span>' % ellipsize(consultation.receiver.name, 50)
|
||||
'<span class="cmds"> [ '
|
||||
'<a href="%s/edit">%s</a> - ' % (k, _('Edit'))
|
||||
'<a href="%s/questions">%s</a> - ' % (k, _('Questions'))
|
||||
'<a href="%s/delete">%s</a> - ' % (k, _('Delete'))
|
||||
'<a href="%s/duplicate">%s</a> - ' % (k, _('Duplicate'))
|
||||
'<a href="%s/listing">%s</a> ' % (k, _('Listing'))
|
||||
'<a href="%s/edit">%s</a> - ' % (consultation.id, _('Edit'))
|
||||
'<a href="%s/fields">%s</a> - ' % (consultation.id, _('Fields'))
|
||||
'<a href="%s/delete">%s</a> - ' % (consultation.id, _('Delete'))
|
||||
'<a href="%s/duplicate">%s</a> - ' % (consultation.id, _('Duplicate'))
|
||||
']</span></p></div>'
|
||||
'</div>'
|
||||
html_foot()
|
||||
|
||||
def new [html] (self):
|
||||
if len(get_user_roles()) == 0:
|
||||
if Role.select(Role.q.system == False).count() == 0:
|
||||
return error_page('consultations', _("You first have to define roles."))
|
||||
consultation = Consultation()
|
||||
consultationui = ConsultationUI(consultation)
|
||||
|
@ -403,7 +397,7 @@ class ConsultationsDirectory(Directory):
|
|||
if form.get_widget('cancel').parse():
|
||||
return redirect('.')
|
||||
redo = False
|
||||
if form.get_widget('questions').get_widget('add_element').parse():
|
||||
if form.get_widget('fields').get_widget('add_element').parse():
|
||||
form.clear_errors()
|
||||
redo = True
|
||||
|
||||
|
@ -413,9 +407,8 @@ class ConsultationsDirectory(Directory):
|
|||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
consultationui.submit_form(form)
|
||||
storage.get_storage().store(consultation)
|
||||
return redirect(consultation.id + '/questions')
|
||||
consultation = consultationui.submit_form(form)
|
||||
return redirect(str(consultation.id) + '/fields')
|
||||
|
||||
def _q_lookup(self, component):
|
||||
return ConsultationPage(component)
|
||||
|
|
|
@ -4,27 +4,31 @@ from quixote.directory import Directory
|
|||
from menu import html_top, html_foot, error_page
|
||||
|
||||
from wcs import misc
|
||||
from wcs import storage
|
||||
from wcs.errors import *
|
||||
from wcs.form import *
|
||||
from wcs.formdef import FormDef
|
||||
from wcs.formdata import FormData
|
||||
from wcs.formdef import FormDef, FormField
|
||||
from wcs.users import User
|
||||
from wcs.categories import Category
|
||||
from wcs.roles import Role
|
||||
|
||||
def ellipsize(s, length = 30):
|
||||
if not s or len(s) < length:
|
||||
return s
|
||||
return s[:length-5] + ' (...)'
|
||||
|
||||
def get_user_roles():
|
||||
l = []
|
||||
for role in storage.get_storage().values('roles'):
|
||||
l.append( (role.id, role.name) )
|
||||
return l
|
||||
def get_user_roles(include_system = False):
|
||||
r = []
|
||||
for x in Role.select():
|
||||
if x.system:
|
||||
if include_system:
|
||||
r.append( (x.id, _(x.name)) )
|
||||
else:
|
||||
r.append( (x.id, x.name) )
|
||||
return r
|
||||
|
||||
def get_categories():
|
||||
l = []
|
||||
for category in storage.get_storage().values('categories'):
|
||||
l.append( (category.id, category.name) )
|
||||
return l
|
||||
return [(x.id, x.name) for x in Category.select()]
|
||||
|
||||
|
||||
|
||||
|
@ -40,26 +44,28 @@ field_types = [ ('string', _('Text (line)')),
|
|||
]
|
||||
|
||||
class FieldWidget(CompositeWidget):
|
||||
def __init__(self, name, value=None, **kwargs):
|
||||
def __init__(self, name, value = None, formdef = None, **kwargs):
|
||||
CompositeWidget.__init__(self, name, value, **kwargs)
|
||||
if not value:
|
||||
value = {}
|
||||
self.value = value
|
||||
self.add(StringWidget, 'name', value.get('name', ''))
|
||||
self.add(SingleSelectWidget, 'type', value.get('type', ''), required=True,
|
||||
if self.value is None:
|
||||
self.value = {}
|
||||
self.add(HiddenWidget, 'id', self.value.get('id'))
|
||||
self.add(StringWidget, 'label', self.value.get('label'))
|
||||
self.add(SingleSelectWidget, 'type', self.value.get('type'), required=True,
|
||||
options = field_types)
|
||||
|
||||
def render_content [html] (self):
|
||||
name_widget = self.get_widget('name')
|
||||
name_widget.render()
|
||||
id_widget = self.get_widget('id')
|
||||
id_widget.render()
|
||||
label_widget = self.get_widget('label')
|
||||
label_widget.render()
|
||||
type_widget = self.get_widget('type')
|
||||
type_widget.render()
|
||||
|
||||
def _parse(self, request):
|
||||
for k in ('name', 'type'):
|
||||
self.value[k] = self.get(k)
|
||||
if not self.value.has_key('required'):
|
||||
self.value['required'] = True
|
||||
self.value['id'] = self.get('id')
|
||||
self.value['label'] = self.get('label')
|
||||
self.value['type'] = self.get('type')
|
||||
|
||||
|
||||
class FormDefUI:
|
||||
|
@ -68,92 +74,113 @@ class FormDefUI:
|
|||
|
||||
def edit_form_ui(self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
auto_id = misc.cfg.get('misc', {}).get('auto-id', False)
|
||||
if not auto_id:
|
||||
form.add(StringWidget, "id", title = _('Form Id'), required = True, size=30,
|
||||
value = self.formdef.id)
|
||||
form.add(StringWidget, "name", title = _('Form Name'), required = True, size=30,
|
||||
value = self.formdef.name)
|
||||
value = self.formdef and self.formdef.name)
|
||||
if self.formdef and self.formdef.fields:
|
||||
fields_list = [{'label': x.label, 'type': x.type, 'id': x.id} \
|
||||
for x in self.formdef.fields]
|
||||
else:
|
||||
fields_list = []
|
||||
form.add(WidgetList, 'fields', title = _('Fields'), element_type = FieldWidget,
|
||||
value = self.formdef.fields, add_element_label = _('Add Field'),
|
||||
element_kwargs = {'render_br': False})
|
||||
value = fields_list, add_element_label = _('Add Field'),
|
||||
element_kwargs = {'formdef': self.formdef, 'render_br': False})
|
||||
form.add(SingleSelectWidget, 'receiver', title = _('Recipient'), required = True,
|
||||
value = self.formdef.receiver, options = get_user_roles())
|
||||
value = self.formdef and self.formdef.receiverID,
|
||||
options = get_user_roles())
|
||||
form.add(WidgetList, 'roles', title = _('Roles'), element_type = SingleSelectWidget,
|
||||
hint = _('Only show this form to the given roles.'),
|
||||
value = self.formdef.roles, add_element_label = _('Add Role'),
|
||||
value = self.formdef and [x.id for x in self.formdef.roles],
|
||||
add_element_label = _('Add Role'),
|
||||
element_kwargs = {'render_br': False,
|
||||
'options': [('', '---'), ('logged-users', _('Logged Users'))] + get_user_roles()})
|
||||
'options': [('', '---')] + get_user_roles(include_system = True)})
|
||||
form.add(SingleSelectWidget, 'category', title = _('Category'),
|
||||
value = self.formdef.category,
|
||||
options = [('', '---')] + get_categories())
|
||||
value = self.formdef and self.formdef.categoryID,
|
||||
options = [(None, '---')] + get_categories())
|
||||
form.add(CheckboxWidget, 'confirmation', title = _('Include confirmation page'),
|
||||
value = self.formdef.confirmation)
|
||||
value = (self.formdef and self.formdef.confirmation) or True)
|
||||
form.add(CheckboxWidget, 'discussion', title = _('Allow discussion'),
|
||||
value = self.formdef.discussion)
|
||||
value = self.formdef and self.formdef.discussion)
|
||||
form.add(CheckboxWidget, 'public', title = _('Public Access'),
|
||||
hint = _('all forms viewable by anynone'),
|
||||
value = self.formdef.public)
|
||||
value = self.formdef and self.formdef.public)
|
||||
form.add(CheckboxWidget, 'detailed_emails', title = _('Send detailed notification emails'),
|
||||
value = self.formdef.detailed_emails)
|
||||
value = self.formdef and self.formdef.detailed_emails)
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
return form
|
||||
|
||||
def submit_form(self, form):
|
||||
for f in ('name', 'fields', 'receiver', 'category', 'confirmation',
|
||||
'discussion', 'public', 'detailed_emails'):
|
||||
setattr(self.formdef, f, form.get_widget(f).parse())
|
||||
if self.formdef:
|
||||
formdef = self.formdef
|
||||
else:
|
||||
formdef = FormDef(name = form.get_widget('name').parse())
|
||||
|
||||
if not hasattr(self.formdef, 'id') or not self.formdef.id:
|
||||
auto_id = misc.cfg.get('misc', {}).get('auto-id', False)
|
||||
if auto_id:
|
||||
new_id = base_id = misc.simplify(self.formdef.name)
|
||||
existing_ids = storage.get_storage().keys('formdefs')
|
||||
i = 1
|
||||
while new_id in existing_ids:
|
||||
new_id = '%s-%d' % (base_id, i)
|
||||
i += 1
|
||||
self.formdef.id = new_id
|
||||
for f in ('name', 'confirmation', 'discussion', 'public', 'detailed_emails'):
|
||||
setattr(formdef, f, form.get_widget(f).parse())
|
||||
|
||||
receiver = form.get_widget('receiver').parse()
|
||||
if receiver:
|
||||
formdef.receiver = Role.get(receiver)
|
||||
category = form.get_widget('category').parse()
|
||||
if category:
|
||||
formdef.category = Role.get(category)
|
||||
|
||||
for field in form.get_widget('fields').parse():
|
||||
if not field['label']:
|
||||
if field['id']:
|
||||
FormField.delete(field['id'])
|
||||
continue
|
||||
if field['id']:
|
||||
form_field = FormField.get(field['id'])
|
||||
form_field.set(label = field['label'], type = field['type'])
|
||||
else:
|
||||
self.formdef.id = form.get_widget('id').parse()
|
||||
self.formdef.fields = [x for x in self.formdef.fields if x['name']] # remove empty names
|
||||
self.formdef.roles = [x for x in form.get_widget('roles').parse() if x]
|
||||
form_field = FormField(label = field['label'], type = field['type'],
|
||||
formdef = self.formdef)
|
||||
|
||||
class FormDefFieldPage(Directory):
|
||||
new_roles = [x for x in form.get_widget('roles').parse() if x]
|
||||
for role in formdef.roles or []:
|
||||
if not role.id in new_roles:
|
||||
formdef.removeRole(role)
|
||||
for role_id in new_roles:
|
||||
if not role_id in [x.id for x in formdef.roles]:
|
||||
formdef.addRole(Role.get(role_id))
|
||||
|
||||
return formdef
|
||||
|
||||
class FieldDefPage(Directory):
|
||||
_q_exports = ['', 'delete', 'down', 'up']
|
||||
|
||||
def __init__(self, formdef, field_no):
|
||||
self.formdef = formdef
|
||||
self.field_no = field_no
|
||||
def __init__(self, field_id):
|
||||
self.field = FormField.get(field_id)
|
||||
|
||||
def form(self):
|
||||
value = self.formdef.fields[self.field_no]
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add(StringWidget, 'name', title = _('Name'), value = value.get('name', ''),
|
||||
readonly = "readonly")
|
||||
form.add(StringWidget, 'label', title = _('Label'), value = self.field.label,
|
||||
required = True)
|
||||
form.add(SingleSelectWidget, 'type', title = _('Type'),
|
||||
value = value.get('type', ''), required=True,
|
||||
value = self.field.type, required=True,
|
||||
options = field_types)
|
||||
form.add(CheckboxWidget, 'required', title = _('Required'),
|
||||
value = value.get('required', False))
|
||||
value = self.field.required)
|
||||
|
||||
if value.get('type') == 'item':
|
||||
current_type = form.get_widget('type').parse()
|
||||
|
||||
if current_type == 'item':
|
||||
form.add(WidgetList, 'items', title = _('Items'), element_type = StringWidget,
|
||||
value = value.get('items', []), required = True,
|
||||
value = self.field.extra.get('items', []), required = True,
|
||||
element_kwargs = {'render_br': False})
|
||||
form.add(CheckboxWidget, 'show-as-radio', title = _('Show as radio buttons'),
|
||||
value = value.get('show-as-radio', False))
|
||||
elif value.get('type') == 'text':
|
||||
value = self.field.extra.get('show-as-radio', False))
|
||||
elif current_type == 'text':
|
||||
form.add(StringWidget, 'cols', title = _('Line length'),
|
||||
value = value.get('cols', ''))
|
||||
value = self.field.extra.get('cols', ''))
|
||||
form.add(StringWidget, 'rows', title = _('Number of rows'),
|
||||
value = value.get('rows', ''))
|
||||
value = self.field.extra.get('rows', ''))
|
||||
form.add(CheckboxWidget, 'pre', title = _('Preformatted Text'),
|
||||
value = value.get('pre', False))
|
||||
elif value.get('type') == 'string':
|
||||
value = self.field.extra.get('pre', False))
|
||||
elif current_type == 'string':
|
||||
form.add(StringWidget, 'size', title = _('Line length'),
|
||||
value = value.get('size', ''))
|
||||
value = self.field.extra.get('size', ''))
|
||||
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
|
@ -161,42 +188,42 @@ class FormDefFieldPage(Directory):
|
|||
return form
|
||||
|
||||
def _q_index [html] (self):
|
||||
value = self.formdef.fields[self.field_no]
|
||||
form = self.form()
|
||||
redo = False
|
||||
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('../fields')
|
||||
return redirect('../../%s/fields' % self.field.formdefID)
|
||||
|
||||
if form.get_widget('items') and form.get_widget('items').get_widget('add_element').parse():
|
||||
form.clear_errors()
|
||||
redo = True
|
||||
if form.get_widget('items') and form.get_widget('type').parse() != 'list':
|
||||
form.clear_errors()
|
||||
redo = True
|
||||
|
||||
if redo or not form.is_submitted() or form.has_errors():
|
||||
html_top('forms', '%s - %s' % (_('Form'), self.formdef.name))
|
||||
'<h2>%s - %s</h2>' % (self.formdef.name, value['name'])
|
||||
html_top('forms', '%s - %s' % (_('Form'), self.field.formdef.name))
|
||||
'<h2>%s - %s</h2>' % (self.field.formdef.name, self.field.label)
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
self.submit(form)
|
||||
if form.get_widget('items') is None and value['type'] == 'item':
|
||||
if form.get_widget('items') is None and self.field.type == 'item':
|
||||
return redirect('.')
|
||||
return redirect('../fields')
|
||||
return redirect('../../%s/fields' % self.field.formdefID)
|
||||
|
||||
def submit(self, form):
|
||||
value = self.formdef.fields[self.field_no]
|
||||
for f in ('name', 'type', 'required', 'items', 'show-as-radio',
|
||||
'rows', 'cols', 'size', 'pre'):
|
||||
for f in ('label', 'type', 'required'):
|
||||
setattr(self.field, f, form.get_widget(f).parse())
|
||||
extra = {}
|
||||
for f in ('items', 'show-as-radio', 'rows', 'cols', 'size', 'pre'):
|
||||
w = form.get_widget(f)
|
||||
if not w:
|
||||
if value.has_key(f):
|
||||
del value[f]
|
||||
continue
|
||||
value[f] = w.parse()
|
||||
storage.get_storage().store(self.formdef)
|
||||
extra[f] = w.parse()
|
||||
self.field.extra = extra
|
||||
|
||||
def delete [html] (self):
|
||||
value = self.formdef.fields[self.field_no]
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.widgets.append(HtmlWidget('<p>%s</p>' % _(
|
||||
"You are about to remove a field.")))
|
||||
|
@ -206,35 +233,40 @@ class FormDefFieldPage(Directory):
|
|||
return redirect('../fields')
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top('forms', title = _('Delete Field'))
|
||||
'<h2>%s %s</h2>' % (_('Deleting Field:'), value['name'])
|
||||
'<h2>%s %s</h2>' % (_('Deleting Field:'), self.field.label)
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
del self.formdef.fields[self.field_no]
|
||||
storage.get_storage().store(self.formdef)
|
||||
return redirect('../fields')
|
||||
pos = self.field.position
|
||||
formdef = self.field.formdef
|
||||
self.field.destroySelf()
|
||||
for field in formdef.fields:
|
||||
if field.position > pos:
|
||||
field.position = field.position - 1
|
||||
return redirect('../../%s/fields' % self.field.formdefID)
|
||||
|
||||
def down(self):
|
||||
t = self.formdef.fields[self.field_no]
|
||||
self.formdef.fields[self.field_no] = self.formdef.fields[self.field_no+1]
|
||||
self.formdef.fields[self.field_no+1] = t
|
||||
storage.get_storage().store(self.formdef)
|
||||
return redirect('../fields')
|
||||
next = [x for x in self.field.formdef.fields if x.position == self.field.position+1][0]
|
||||
self.field.position = self.field.position+1
|
||||
next.position = next.position-1
|
||||
return redirect('../../%s/fields' % self.field.formdefID)
|
||||
|
||||
def up(self):
|
||||
t = self.formdef.fields[self.field_no]
|
||||
self.formdef.fields[self.field_no] = self.formdef.fields[self.field_no-1]
|
||||
self.formdef.fields[self.field_no-1] = t
|
||||
storage.get_storage().store(self.formdef)
|
||||
return redirect('../fields')
|
||||
prev = [x for x in self.field.formdef.fields if x.position == self.field.position-1][0]
|
||||
self.field.position = self.field.position-1
|
||||
prev.position = prev.position+1
|
||||
return redirect('../../%s/fields' % self.field.formdefID)
|
||||
|
||||
|
||||
|
||||
class FormDefPage(Directory):
|
||||
_q_exports = ["fields", "edit", "delete", "listing", "csv", "duplicate"]
|
||||
_q_exports = ["fields", "edit", "delete", "duplicate"]
|
||||
|
||||
def __init__(self, component):
|
||||
self.formdef = storage.get_storage().retrieve('formdefs', component)
|
||||
try:
|
||||
self.formdef = FormDef.get(component)
|
||||
except SQLObjectNotFound:
|
||||
raise TraversalError()
|
||||
self.formdefui = FormDefUI(self.formdef)
|
||||
|
||||
def fields [html] (self):
|
||||
|
@ -243,75 +275,38 @@ class FormDefPage(Directory):
|
|||
'<table>'
|
||||
for i, field in enumerate(self.formdef.fields):
|
||||
'<tr>'
|
||||
if field['type'] in ('subtitle', 'title', 'comment'):
|
||||
label = field['name']
|
||||
if field.type in ('subtitle', 'title', 'comment'):
|
||||
label = field.label
|
||||
if len(label) > 40:
|
||||
label = label[:35] + ' (...)'
|
||||
if field['type'] in ('subtitle', 'title'):
|
||||
if field.type in ('subtitle', 'title'):
|
||||
'<td colspan="4"><strong>%s</strong></td>' % label
|
||||
else:
|
||||
'<td colspan="4">%s</td>' % label
|
||||
else:
|
||||
type = [x[1] for x in field_types if x[0] == field['type']][0]
|
||||
if field.has_key('required') and field['required']:
|
||||
type = [x[1] for x in field_types if x[0] == field.type][0]
|
||||
if field.required:
|
||||
required = ''
|
||||
else:
|
||||
required = _('optional')
|
||||
'<td>%s</td>' % field['name']
|
||||
'<td>%s</td>' % field.label
|
||||
'<td>%s</td>' % type
|
||||
'<td>%s</td>' % required
|
||||
'<td><a href="field-%d">%s</a></td>' % (i, _('Edit'))
|
||||
'<td><a href="../fields/%d/">%s</a></td>' % (field.id, _('Edit'))
|
||||
|
||||
'<td><a href="field-%d/delete">%s</a></td>' % (i, _('Delete'))
|
||||
'<td><a href="../fields/%d/delete">%s</a></td>' % (field.id, _('Delete'))
|
||||
'<td>'
|
||||
if i != 0:
|
||||
'<a class="arrow" href="field-%d/up">%s</a>' % (i, '↑')
|
||||
'<a class="arrow" href="../fields/%d/up">%s</a>' % (field.id, '↑')
|
||||
'</td><td>'
|
||||
if i+1 != len(self.formdef.fields):
|
||||
'<a class="arrow" href="field-%d/down">%s</a>' % (i, '↓')
|
||||
'<a class="arrow" href="../fields/%d/down">%s</a>' % (field.id, '↓')
|
||||
'</td>'
|
||||
'</tr>'
|
||||
'</table>'
|
||||
|
||||
html_foot()
|
||||
|
||||
def listing [html] (self):
|
||||
html_top('forms', '%s - %s' % (_('Form'), self.formdef.name))
|
||||
names = 'form-' + self.formdef.id
|
||||
'<h2>%s</h2>' % self.formdef.name
|
||||
'<a href="csv">%s</a>' % _('Export to CSV format')
|
||||
'<table id="listing"><thead><tr>'
|
||||
for f in self.formdef.fields:
|
||||
if f['type'] in ('title', 'subtitle'):
|
||||
continue
|
||||
"<th>%s</th>" % f['name']
|
||||
"</tr></thead>"
|
||||
"<tbody>"
|
||||
for k in storage.get_storage().keys(names):
|
||||
filled = storage.get_storage().retrieve(names, k)
|
||||
"<tr>"
|
||||
for f in self.formdef.fields:
|
||||
if f['type'] in ('title', 'subtitle'):
|
||||
continue
|
||||
"<td>%s</td>" % filled.data.get(f['name'], '')
|
||||
"</tr>"
|
||||
"</tbody></table>"
|
||||
html_foot()
|
||||
|
||||
def csv [plain] (self):
|
||||
names = 'form-' + self.formdef.id
|
||||
|
||||
def fixcsv(s):
|
||||
if isinstance(s, basestring):
|
||||
return s.replace('\n', ' ').replace(';', ',')
|
||||
return str(s)
|
||||
|
||||
for k in storage.get_storage().keys(names):
|
||||
filled = storage.get_storage().retrieve(names, k)
|
||||
';'.join([fixcsv(filled.data.get(x['name'])) for x in self.formdef.fields]) + '\r\n'
|
||||
response = get_response()
|
||||
response.set_content_type('text/csv')
|
||||
|
||||
def edit [html] (self, duplicate = False):
|
||||
form = self.formdefui.edit_form_ui()
|
||||
if form.get_widget('cancel').parse():
|
||||
|
@ -335,10 +330,9 @@ class FormDefPage(Directory):
|
|||
html_foot()
|
||||
else:
|
||||
self.formdefui.submit_form(form)
|
||||
storage.get_storage().store(self.formdef)
|
||||
return redirect('..')
|
||||
|
||||
def duplicate [html] (self):
|
||||
def duplicate [html] (self): # XXX: FIXME for SQLObject
|
||||
self.formdefui.formdef.id = ''
|
||||
return self.edit(duplicate = True)
|
||||
|
||||
|
@ -356,30 +350,28 @@ class FormDefPage(Directory):
|
|||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
storage.get_storage().remove_id('formdefs', self.formdef.id)
|
||||
storage.get_storage().remove_all('form-%s' % self.formdef.id)
|
||||
for formdata in FormData.select(FormData.q.formdefID == self.formdef.id):
|
||||
formdata.destroySelf()
|
||||
self.formdef.destroySelf()
|
||||
return redirect('..')
|
||||
|
||||
def _q_lookup(self, component):
|
||||
if not component.startswith('field-'):
|
||||
raise TraversalError()
|
||||
try:
|
||||
field_no = int(component[6:])
|
||||
except ValueError:
|
||||
raise TraversalError()
|
||||
return FormDefFieldPage(self.formdef, field_no)
|
||||
|
||||
class FieldsDirectory(Directory):
|
||||
def _q_lookup(self, component):
|
||||
return FieldDefPage(component)
|
||||
|
||||
|
||||
class FormsDirectory(Directory):
|
||||
|
||||
_q_exports = ["", "new"]
|
||||
_q_exports = ['', 'new', 'fields']
|
||||
|
||||
fields = FieldsDirectory()
|
||||
|
||||
def _q_index [html] (self):
|
||||
misc.reload_cfg()
|
||||
html_top('forms', title = _('Forms'))
|
||||
|
||||
if len(get_user_roles()) > 0:
|
||||
if Role.select(Role.q.system == False).count():
|
||||
"""<ul id="nav-forms-admin">
|
||||
<li><a href="new">%s</a></li>
|
||||
</ul>""" % _('New Form')
|
||||
|
@ -387,27 +379,23 @@ class FormsDirectory(Directory):
|
|||
"<p>%s</p>" % _('You first have to define roles.')
|
||||
|
||||
'<div class="biglist">'
|
||||
for k in storage.get_storage().keys('formdefs'):
|
||||
formdef = storage.get_storage().retrieve('formdefs', k)
|
||||
for formdef in FormDef.select():
|
||||
'<div class="biglist-item">'
|
||||
"<h3>%s</h3>" % formdef.name
|
||||
'<p><span class="data">%s</span>' % ellipsize(
|
||||
storage.get_storage().retrieve('roles', formdef.receiver).name, 50)
|
||||
'<p><span class="data">%s</span>' % ellipsize(formdef.receiver.name, 50)
|
||||
'<span class="cmds"> [ '
|
||||
'<a href="%s/edit">%s</a> - ' % (k, _('Edit'))
|
||||
'<a href="%s/fields">%s</a> - ' % (k, _('Fields'))
|
||||
'<a href="%s/delete">%s</a> - ' % (k, _('Delete'))
|
||||
'<a href="%s/duplicate">%s</a> - ' % (k, _('Duplicate'))
|
||||
'<a href="%s/listing">%s</a> ' % (k, _('Listing'))
|
||||
'<a href="%s/edit">%s</a> - ' % (formdef.id, _('Edit'))
|
||||
'<a href="%s/fields">%s</a> - ' % (formdef.id, _('Fields'))
|
||||
'<a href="%s/delete">%s</a> - ' % (formdef.id, _('Delete'))
|
||||
'<a href="%s/duplicate">%s</a>' % (formdef.id, _('Duplicate'))
|
||||
']</span></p></div>'
|
||||
'</div>'
|
||||
html_foot()
|
||||
|
||||
def new [html] (self):
|
||||
if len(get_user_roles()) == 0:
|
||||
if Role.select(Role.q.system == False).count() == 0:
|
||||
return error_page('forms', _("You first have to define roles."))
|
||||
formdef = FormDef()
|
||||
formdefui = FormDefUI(formdef)
|
||||
formdefui = FormDefUI(None)
|
||||
form = formdefui.edit_form_ui()
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('.')
|
||||
|
@ -422,9 +410,8 @@ class FormsDirectory(Directory):
|
|||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
formdefui.submit_form(form)
|
||||
storage.get_storage().store(formdef)
|
||||
return redirect(formdef.id + '/fields')
|
||||
formdef = formdefui.submit_form(form)
|
||||
return redirect(str(formdef.id) + '/fields')
|
||||
|
||||
def _q_lookup(self, component):
|
||||
return FormDefPage(component)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import quixote
|
||||
from wcs import storage
|
||||
from wcs import misc
|
||||
from wcs.users import User
|
||||
|
||||
items = [
|
||||
('forms', N_('Forms')),
|
||||
|
@ -34,10 +35,7 @@ def user_info [html] ():
|
|||
session = quixote.get_session()
|
||||
if not session or not session.user:
|
||||
return ''
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
except KeyError:
|
||||
return ''
|
||||
user = User.get(session.user)
|
||||
logout_url = quixote.get_request().environ['SCRIPT_NAME'] + '/logout'
|
||||
"""<ul class="user-info">
|
||||
<li class="ui-name">%s</li>
|
||||
|
|
|
@ -3,9 +3,10 @@ from quixote.directory import Directory
|
|||
|
||||
from menu import html_top, html_foot
|
||||
|
||||
from wcs import errors
|
||||
from wcs import misc
|
||||
from wcs import storage
|
||||
from wcs.roles import Role
|
||||
from wcs.roles import Role, RoleEmail
|
||||
from wcs.form import *
|
||||
|
||||
class RoleUI:
|
||||
|
@ -14,16 +15,11 @@ class RoleUI:
|
|||
|
||||
def form_new(self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
auto_id = misc.cfg.get('misc', {}).get('auto-id', False)
|
||||
if not auto_id:
|
||||
form.add(StringWidget, "id", title = _('Role Id'), required = True, size=30,
|
||||
value = self.role.id)
|
||||
form.add(StringWidget, "name", title = _('Role Name'), required = True, size=30,
|
||||
value = self.role.name)
|
||||
form.add(StringWidget, "name", title = _('Role Name'), required = True, size=30)
|
||||
form.add(TextWidget, "details", title = _('Role Details'), required = False,
|
||||
cols = 40, rows = 5, value = self.role.details)
|
||||
cols = 40, rows = 5)
|
||||
form.add(WidgetList, 'emails', title = _('Role Emails'), element_type = StringWidget,
|
||||
value = self.role.emails, add_element_label = _('Add Email'),
|
||||
add_element_label = _('Add Email'),
|
||||
element_kwargs = {'render_br': False, 'size': 30})
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
|
@ -31,45 +27,41 @@ class RoleUI:
|
|||
|
||||
def form_edit(self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
auto_id = misc.cfg.get('misc', {}).get('auto-id', False)
|
||||
if auto_id:
|
||||
form.add_hidden("id", value = self.role.id)
|
||||
else:
|
||||
form.add(StringWidget, "id", title = _('Role Id'), required = False, size=30,
|
||||
value = self.role.id, readonly = 'readonly')
|
||||
form.add(StringWidget, "id", title = _('Role Id'), required = False, size=30,
|
||||
value = self.role.id, readonly = 'readonly')
|
||||
form.add(StringWidget, "name", title = _('Role Name'), required = True, size=30,
|
||||
value = self.role.name)
|
||||
form.add(TextWidget, "details", title = _('Role Details'), required = False,
|
||||
cols = 40, rows = 5, value = self.role.details)
|
||||
form.add(WidgetList, 'emails', title = _('Role Emails'), element_type = StringWidget,
|
||||
value = self.role.emails, add_element_label = _('Add Email'),
|
||||
value = [x.email for x in self.role.emails],
|
||||
add_element_label = _('Add Email'),
|
||||
element_kwargs = {'render_br': False, 'size': 30})
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
return form
|
||||
|
||||
def submit_form(self, form):
|
||||
for f in ('name', 'details', 'emails'):
|
||||
setattr(self.role, f, form.get_widget(f).parse())
|
||||
if not hasattr(self.role, 'id') or not self.role.id:
|
||||
auto_id = misc.cfg.get('misc', {}).get('auto-id', False)
|
||||
if auto_id:
|
||||
new_id = base_id = misc.simplify(self.role.name)
|
||||
existing_ids = storage.get_storage().keys('roles')
|
||||
i = 1
|
||||
while new_id in existing_ids:
|
||||
new_id = '%s-%d' % (base_id, i)
|
||||
i += 1
|
||||
self.role.id = new_id
|
||||
else:
|
||||
self.role.id = form.get_widget('id').parse()
|
||||
if self.role:
|
||||
role = self.role
|
||||
else:
|
||||
role = Role(name = form.get_widget('name').parse())
|
||||
for f in ('name', 'details'):
|
||||
setattr(role, f, form.get_widget(f).parse())
|
||||
for email in role.emails:
|
||||
email.destroySelf()
|
||||
for email in form.get_widget('emails').parse() or []:
|
||||
RoleEmail(email = email, role = role)
|
||||
|
||||
|
||||
|
||||
class RolePage(Directory):
|
||||
_q_exports = ["edit", "delete"]
|
||||
|
||||
def __init__(self, component):
|
||||
self.role = storage.get_storage().retrieve('roles', component)
|
||||
self.role = Role.get(component)
|
||||
if self.role.system:
|
||||
raise errors.TraversalError()
|
||||
self.role_ui = RoleUI(self.role)
|
||||
|
||||
def edit [html] (self):
|
||||
|
@ -84,7 +76,6 @@ class RolePage(Directory):
|
|||
html_foot()
|
||||
else:
|
||||
self.role_ui.submit_form(form)
|
||||
storage.get_storage().store(self.role)
|
||||
return redirect('..')
|
||||
|
||||
def delete [html] (self):
|
||||
|
@ -101,7 +92,7 @@ class RolePage(Directory):
|
|||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
storage.get_storage().remove_id('roles', self.role.id)
|
||||
self.role.destroySelf()
|
||||
return redirect('..')
|
||||
|
||||
|
||||
|
@ -124,32 +115,29 @@ class RolesDirectory(Directory):
|
|||
</ul>""" % _('New Role')
|
||||
|
||||
'<div class="biglist">'
|
||||
for k in storage.get_storage().keys('roles'):
|
||||
role = storage.get_storage().retrieve('roles', k)
|
||||
for role in Role.select(Role.q.system == False):
|
||||
'<div class="biglist-item">'
|
||||
"<h3>%s</h3>" % role.name
|
||||
'<p><span class="cmds"> [ '
|
||||
'<a href="%s/edit">%s</a> - ' % (k, _('Edit'))
|
||||
'<a href="%s/delete">%s</a> ' % (k, _('Delete'))
|
||||
'<a href="%s/edit">%s</a> - ' % (role.id, _('Edit'))
|
||||
'<a href="%s/delete">%s</a> ' % (role.id, _('Delete'))
|
||||
"]</span></p></div>"
|
||||
'</div>'
|
||||
html_foot()
|
||||
|
||||
def new [html] (self):
|
||||
role = Role()
|
||||
role_ui = RoleUI(role)
|
||||
role_ui = RoleUI(None)
|
||||
form = role_ui.form_new()
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('.')
|
||||
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
if not form.is_submitted() or form.has_errors() or form.get_submit() is True:
|
||||
html_top('roles', title = _('New Role'))
|
||||
'<h2>%s</h2>' % _('New Role')
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
role_ui.submit_form(form)
|
||||
storage.get_storage().store(role)
|
||||
return redirect('.')
|
||||
|
||||
def _q_lookup(self, component):
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from quixote import get_session
|
||||
from quixote import get_session, get_session_manager
|
||||
from quixote.directory import Directory, AccessControlled
|
||||
|
||||
import settings
|
||||
|
@ -42,20 +42,29 @@ class RootDirectory(AccessControlled, Directory):
|
|||
|
||||
def _q_access(self):
|
||||
session = get_session()
|
||||
user = None
|
||||
if session.user == 'ultra-user':
|
||||
return
|
||||
|
||||
if not session.user or session.user == 'ultra-user':
|
||||
if len(storage.get_storage().keys('users')) == 0 or session.user == 'ultra-user':
|
||||
user = None
|
||||
if session.user and not str(session.user).startswith('anonymous-'):
|
||||
try:
|
||||
user = users.User.get(session.user)
|
||||
except KeyError:
|
||||
pass
|
||||
except ValueError: # oldWorld session, kill it
|
||||
get_session().user = None
|
||||
|
||||
if not user:
|
||||
query = users.User.select()
|
||||
if query.count() == 0:
|
||||
session.set_user('ultra-user')
|
||||
return # bootstrapping
|
||||
raise errors.AccessUnauthorizedError()
|
||||
if session.user:
|
||||
raise errors.AccessForbiddenError()
|
||||
else:
|
||||
raise errors.AccessUnauthorizedError()
|
||||
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
except KeyError:
|
||||
raise errors.AccessForbiddenError()
|
||||
|
||||
if not 'site-admin' in user.roles:
|
||||
if not user.is_admin:
|
||||
raise errors.AccessForbiddenError()
|
||||
|
||||
|
||||
|
|
|
@ -9,16 +9,11 @@ from wcs import emails
|
|||
from wcs import errors
|
||||
from wcs import misc
|
||||
from wcs.users import User
|
||||
from wcs.roles import Role
|
||||
from wcs import storage
|
||||
|
||||
from wcs.form import *
|
||||
|
||||
def get_user_roles():
|
||||
l = [('site-admin', _('Site Administrator'))]
|
||||
for role in storage.get_storage().values('roles'):
|
||||
l.append( (role.id, role.name) )
|
||||
return l
|
||||
|
||||
|
||||
class UserUI:
|
||||
def __init__(self, user):
|
||||
|
@ -26,16 +21,16 @@ class UserUI:
|
|||
|
||||
def form_new(self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add(StringWidget, "id", title = _('User Id'), required = True, size=30,
|
||||
value = self.user.id)
|
||||
form.add(StringWidget, "name", title = _('User Name'), required = True, size=30,
|
||||
value = self.user.name)
|
||||
form.add(StringWidget, "email", title = _('Email'), required = False, size=30,
|
||||
value = self.user.email)
|
||||
form.add(WidgetList, 'roles', title = _('Roles'), element_type = SingleSelectWidget,
|
||||
value = self.user.roles, add_element_label = _('Add Role'),
|
||||
element_kwargs = {str('render_br'): False,
|
||||
str('options'): [('', '---')] + get_user_roles()})
|
||||
form.add(StringWidget, "name", title = _('User Name'), required = True, size=30)
|
||||
form.add(StringWidget, "email", title = _('Email'), required = False, size=30)
|
||||
form.add(CheckboxWidget, 'is_admin', title = _('Administrator Account'))
|
||||
roles = Role.select()
|
||||
if roles.count():
|
||||
form.add(WidgetList, 'roles', title = _('Roles'), element_type = SingleSelectWidget,
|
||||
add_element_label = _('Add Role'),
|
||||
element_kwargs = {
|
||||
'render_br': False,
|
||||
'options': [(None, '---')] + [(x.id, x.name) for x in roles]})
|
||||
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
|
@ -49,26 +44,42 @@ class UserUI:
|
|||
value = self.user.name)
|
||||
form.add(StringWidget, "email", title = _('Email'), required = False, size=30,
|
||||
value = self.user.email)
|
||||
form.add(WidgetList, 'roles', title = _('Roles'), element_type = SingleSelectWidget,
|
||||
value = self.user.roles, add_element_label = _('Add Role'),
|
||||
element_kwargs = {str('render_br'): False,
|
||||
str('options'): [('', '---')] + get_user_roles()})
|
||||
form.add(CheckboxWidget, 'is_admin', title = _('Administrator Account'),
|
||||
value = self.user.is_admin)
|
||||
roles = Role.select()
|
||||
if roles.count():
|
||||
form.add(WidgetList, 'roles', title = _('Roles'), element_type = SingleSelectWidget,
|
||||
value = [x.id for x in self.user.roles],
|
||||
add_element_label = _('Add Role'),
|
||||
element_kwargs = {
|
||||
'render_br': False,
|
||||
'options': [(None, '---')] + [(x.id, x.name) for x in roles]})
|
||||
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
return form
|
||||
|
||||
def submit_form(self, form):
|
||||
for f in ('id', 'name', 'email'):
|
||||
setattr(self.user, f, form.get_widget(f).parse())
|
||||
self.user.roles = [x for x in form.get_widget('roles').parse() if x]
|
||||
if self.user:
|
||||
user = self.user
|
||||
else:
|
||||
user = User()
|
||||
for f in ('name', 'email', 'is_admin'):
|
||||
setattr(user, f, form.get_widget(f).parse())
|
||||
for role in user.roles:
|
||||
user.removeRole(role)
|
||||
if form.get_widget('roles'):
|
||||
for role_id in form.get_widget('roles').parse() or []:
|
||||
if not role_id:
|
||||
continue
|
||||
user.addRole(Role.get(role_id))
|
||||
|
||||
|
||||
class UserPage(Directory):
|
||||
_q_exports = ["edit", "delete", "token", "debug"]
|
||||
|
||||
def __init__(self, component):
|
||||
self.user = storage.get_storage().retrieve('users', component)
|
||||
self.user = User.get(component)
|
||||
self.user_ui = UserUI(self.user)
|
||||
|
||||
def debug [html] (self):
|
||||
|
@ -91,7 +102,6 @@ class UserPage(Directory):
|
|||
html_foot()
|
||||
else:
|
||||
self.user_ui.submit_form(form)
|
||||
storage.get_storage().store(self.user)
|
||||
return redirect('..')
|
||||
|
||||
def delete [html] (self):
|
||||
|
@ -108,7 +118,7 @@ class UserPage(Directory):
|
|||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
storage.get_storage().remove_id('users', self.user.id)
|
||||
self.user.destroySelf()
|
||||
return redirect('..')
|
||||
|
||||
def token [html] (self):
|
||||
|
@ -132,7 +142,6 @@ class UserPage(Directory):
|
|||
html_top('users', title = _('Identification Token'))
|
||||
token = '-'.join(['%04d' % random.randint(1, 9999) for x in range(4)])
|
||||
self.user.identification_token = str(token)
|
||||
storage.get_storage().store(self.user)
|
||||
|
||||
"<p>"
|
||||
_('Identification Token for %s:') % self.user.name
|
||||
|
@ -169,8 +178,7 @@ class UsersDirectory(Directory):
|
|||
<li><a href="new">%s</a></li>
|
||||
</ul>""" % _('New User')
|
||||
|
||||
users = storage.get_storage().values('users')
|
||||
users.sort(lambda x,y: cmp(x.name, y.name))
|
||||
users = User.select(orderBy = User.q.name)
|
||||
|
||||
'<div class="biglist">'
|
||||
for user in users:
|
||||
|
@ -178,7 +186,11 @@ class UsersDirectory(Directory):
|
|||
"<h3>%s</h3>" % user.name
|
||||
'<p><span class="cmds"> [ '
|
||||
if not user.name_identifiers:
|
||||
'<a href="%s/token">%s</a> - ' % (user.id, _('Identification Token'))
|
||||
if not user.identification_token:
|
||||
'<a href="%s/token">%s</a> - ' % (user.id, _('Identification Token'))
|
||||
else:
|
||||
'<a href="%s/token">%s</a> (%s) - ' % (user.id,
|
||||
_('Identification Token'), user.identification_token)
|
||||
'<a href="%s/edit">%s</a> - ' % (user.id, _('Edit'))
|
||||
'<a href="%s/delete">%s</a> ' % (user.id, _('Delete'))
|
||||
']</span></p></div>'
|
||||
|
@ -189,8 +201,7 @@ class UsersDirectory(Directory):
|
|||
if len(misc.cfg.get('idp', {}).items()) == 0:
|
||||
return error_page('users',
|
||||
_('Liberty support must be setup before creating users.'))
|
||||
user = User()
|
||||
user_ui = UserUI(user)
|
||||
user_ui = UserUI(None)
|
||||
form = user_ui.form_new()
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('.')
|
||||
|
@ -202,7 +213,6 @@ class UsersDirectory(Directory):
|
|||
html_foot()
|
||||
else:
|
||||
user_ui.submit_form(form)
|
||||
storage.get_storage().store(user)
|
||||
return redirect('.')
|
||||
|
||||
def _q_lookup(self, component):
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
from sqlobject import *
|
||||
|
||||
class AnonymityLink(SQLObject):
|
||||
_cacheValue = False
|
||||
formdata = ForeignKey('FormData')
|
||||
key = StringCol(length = 100, default = None)
|
||||
name_identifier = StringCol(default = None)
|
||||
|
|
@ -1,10 +1,53 @@
|
|||
import storage
|
||||
from sqlobject import *
|
||||
|
||||
class Category(storage.Storable):
|
||||
class Category(SQLObject):
|
||||
key = 'id'
|
||||
names = 'categories'
|
||||
_cacheValues = False
|
||||
|
||||
def __init__(self):
|
||||
self.id = ''
|
||||
self.name = ''
|
||||
name = StringCol(length = 100)
|
||||
|
||||
def migrateOldData(cls):
|
||||
import storage
|
||||
from formdef import FormDef
|
||||
from consultationdef import Consultation
|
||||
|
||||
init_method = cls.__init__
|
||||
cls.__init__ = lambda x: x
|
||||
categories = storage.get_storage().values('categories')
|
||||
items = [x.__dict__ for x in categories]
|
||||
cls.__init__ = init_method
|
||||
|
||||
new_ids_mapping = []
|
||||
for item in items:
|
||||
category = Category(name = item['name'])
|
||||
new_ids_mapping.append( (item['id'], category.id) )
|
||||
|
||||
# fixing other tables to get the new ids
|
||||
# formdefs
|
||||
formdef_init_method = FormDef.__init__
|
||||
FormDef.__init__ = lambda x: x
|
||||
formdefs = storage.get_storage().values('formdefs')
|
||||
for formdef in formdefs:
|
||||
cat = formdef.__dict__.get('category')
|
||||
if not cat:
|
||||
formdef.__dict__['category'] = None
|
||||
else:
|
||||
formdef.__dict__['category'] = [x[1] for x in new_ids_mapping if x[0] == cat][0]
|
||||
storage.get_storage().store(formdef)
|
||||
FormDef.__init__ = formdef_init_method
|
||||
|
||||
# consultations
|
||||
consultation_init_method = Consultation.__init__
|
||||
Consultation.__init__ = lambda x: x
|
||||
consultations = storage.get_storage().values('consultations')
|
||||
for consultation in consultations:
|
||||
cat = consultation.__dict__['category']
|
||||
if not cat:
|
||||
consultation.__dict__['category'] = None
|
||||
else:
|
||||
consultation.__dict__['category'] = [x[1] for x in new_ids_mapping if x[0] == cat][0]
|
||||
storage.get_storage().store(consultation)
|
||||
Consultation.__init__ = consultation_init_method
|
||||
|
||||
migrateOldData = classmethod(migrateOldData)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from sqlobject import *
|
||||
from extracols import DictPickleCol
|
||||
|
||||
import emails
|
||||
|
||||
from quixote import get_request
|
||||
|
@ -5,6 +8,10 @@ from quixote import get_request
|
|||
import storage
|
||||
|
||||
from form import *
|
||||
from misc import simplify
|
||||
|
||||
from formdata import FormData
|
||||
from anonylink import AnonymityLink
|
||||
|
||||
widget_classes = {
|
||||
'string': StringWidget,
|
||||
|
@ -21,60 +28,70 @@ widget_extra_attributes = {
|
|||
}
|
||||
|
||||
|
||||
class Consultation(storage.Storable):
|
||||
class ConsultationField(SQLObject):
|
||||
label = StringCol(length = 300)
|
||||
type = StringCol(length = 20)
|
||||
required = BoolCol(default = True)
|
||||
extra = DictPickleCol(default = None)
|
||||
consultation = ForeignKey('Consultation')
|
||||
position = IntCol(default = None)
|
||||
|
||||
|
||||
|
||||
class Consultation(SQLObject):
|
||||
key = 'id'
|
||||
names = 'consultations'
|
||||
receiver = None
|
||||
roles = None
|
||||
category = None
|
||||
|
||||
def __init__(self):
|
||||
self.id = ''
|
||||
self.name = ''
|
||||
self.questions = []
|
||||
self.receiver = ''
|
||||
self.category = ''
|
||||
self.roles = []
|
||||
name = StringCol(length = 200)
|
||||
url_name = StringCol(default = None, length = 200, alternateID = True)
|
||||
fields = MultipleJoin('ConsultationField', joinMethodName = 'fields',
|
||||
joinColumn = 'consultation_id', orderBy = ConsultationField.q.position)
|
||||
receiver = ForeignKey('Role', default = None)
|
||||
roles = RelatedJoin('Role')
|
||||
category = ForeignKey('Category', default = None)
|
||||
|
||||
def _set_name(self, value):
|
||||
self._SO_set_name(value)
|
||||
if not self.url_name or FormData.select(FormData.q.consultationID == self.id).count() == 0:
|
||||
self.url_name = simplify(value)
|
||||
|
||||
def create_form(self, page_no, answers = {}):
|
||||
form = Form(enctype = "multipart/form-data", use_tokens = False)
|
||||
current_page = 0
|
||||
for i, question in enumerate(self.questions):
|
||||
if question['answer'] == 'newpage':
|
||||
for field in self.fields:
|
||||
if field.type == 'newpage':
|
||||
current_page += 1
|
||||
if current_page > page_no:
|
||||
break
|
||||
continue
|
||||
if current_page != page_no:
|
||||
continue
|
||||
if question['answer'] == 'title':
|
||||
form.widgets.append(HtmlWidget(htmltext("<h3>%s</h3>" % question['question'])))
|
||||
if field.type == 'title':
|
||||
form.widgets.append(HtmlWidget(htmltext("<h3>%s</h3>" % field.label)))
|
||||
continue
|
||||
if question['answer'] == 'subtitle':
|
||||
form.widgets.append(HtmlWidget(htmltext("<h4>%s</h4>" % question['question'])))
|
||||
if field.type == 'subtitle':
|
||||
form.widgets.append(HtmlWidget(htmltext("<h4>%s</h4>" % field.label)))
|
||||
continue
|
||||
if question['answer'] == 'comment':
|
||||
form.widgets.append(HtmlWidget(htmltext("<p>%s</p>" % question['question'])))
|
||||
if field.type == 'comment':
|
||||
form.widgets.append(HtmlWidget(htmltext("<p>%s</p>" % field.label)))
|
||||
continue
|
||||
|
||||
widget_class = widget_classes[question['answer']]
|
||||
widget_class = widget_classes[field.type]
|
||||
|
||||
kwargs = {'required': question.get('required', True)}
|
||||
if question['answer'] == 'item':
|
||||
kwargs['options'] = question.get('items', ['---'])
|
||||
if question.get('show-as-radio'):
|
||||
kwargs = {'required': field.required}
|
||||
if field.type == 'item':
|
||||
kwargs['options'] = field.extra.get('items', ['---'])
|
||||
if field.extra.get('show-as-radio'):
|
||||
widget_class = RadiobuttonsWidget
|
||||
if len(kwargs['options']) > 2:
|
||||
kwargs['delim'] = htmltext('<br />')
|
||||
value = None
|
||||
if answers.has_key(question['question']):
|
||||
kwargs['value'] = answers[question['question']]
|
||||
if widget_extra_attributes.has_key(question['answer']):
|
||||
for k in widget_extra_attributes[question['answer']]:
|
||||
v = question.get(k, None)
|
||||
kwargs['value'] = answers.get(field.id)
|
||||
if widget_extra_attributes.has_key(field.type):
|
||||
for k in widget_extra_attributes[field.type]:
|
||||
v = field.extra.get(k, None)
|
||||
if v is not None:
|
||||
kwargs[k] = v
|
||||
form.add(widget_class, "f%d" % i, title = question['question'], **kwargs)
|
||||
form.add(widget_class, "f%d" % field.id, title = field.label, **kwargs)
|
||||
|
||||
if page_no != 0:
|
||||
form.add_submit("previous", _("Previous"))
|
||||
|
@ -84,10 +101,68 @@ class Consultation(storage.Storable):
|
|||
|
||||
def get_data(self, form):
|
||||
d = {}
|
||||
for i, question in enumerate(self.questions):
|
||||
if question['answer'] in ('title', 'subtitle', 'comment'):
|
||||
continue
|
||||
if form.get_widget('f%d' % i):
|
||||
d[question['question']] = form.get_widget('f%d' % i).parse()
|
||||
for field in self.fields:
|
||||
widget = form.get_widget('f%s' % field.id)
|
||||
if widget:
|
||||
d[field.id] = widget.parse()
|
||||
return d
|
||||
|
||||
def get_filled(self, session):
|
||||
completed = FormData.select(AND(
|
||||
FormData.q.consultationID == self.id,
|
||||
FormData.q.userID == session.user))
|
||||
if completed.count():
|
||||
return completed[0]
|
||||
|
||||
completed = AnonymityLink.select(OR(
|
||||
AnonymityLink.q.name_identifier == session.name_identifier,
|
||||
AND(AnonymityLink.q.key != None,
|
||||
AnonymityLink.q.key == session.get_anonymous_key(False))))
|
||||
for c in completed:
|
||||
if c.formdata.consultationID == self.id:
|
||||
return c.formdata
|
||||
|
||||
raise SQLObjectNotFound
|
||||
|
||||
def migrateOldData(cls):
|
||||
import storage
|
||||
from roles import Role, get_logged_users_role
|
||||
from categories import Category
|
||||
|
||||
init_method = cls.__init__
|
||||
cls.__init__ = lambda x: x
|
||||
consultations = storage.get_storage().values('consultations')
|
||||
items = [x.__dict__ for x in consultations]
|
||||
cls.__init__ = init_method
|
||||
|
||||
items.sort(lambda x,y: cmp(x['id'], y['id']))
|
||||
logged_users = get_logged_users_role()
|
||||
for item in items:
|
||||
consultation = Consultation(name = item['name'])
|
||||
consultation.url_name = item['id']
|
||||
consultation.receiver = Role.get(item['receiver'])
|
||||
if item.get('category'):
|
||||
consultation.category = Category.get(item['category'])
|
||||
for role in item.get('roles', []):
|
||||
if role == 'logged-users':
|
||||
consultation.addRole(logged_users)
|
||||
continue
|
||||
consultation.addRole(Role.get(role))
|
||||
for i, field in enumerate(item['questions']):
|
||||
fieldObject = ConsultationField(label = field['question'], type = field['answer'],
|
||||
consultation = consultation)
|
||||
fieldObject.required = field.get('required', False)
|
||||
fieldObject.position = i
|
||||
d = field.copy()
|
||||
del d['question']
|
||||
del d['answer']
|
||||
del d['required']
|
||||
if d:
|
||||
fieldObject.extra = d
|
||||
|
||||
# convert submitted forms
|
||||
name = 'consultation-%s' % item['id']
|
||||
newname = 'consultationtmp-%s' % consultation.id
|
||||
storage.get_storage().rename_table(name, newname)
|
||||
|
||||
migrateOldData = classmethod(migrateOldData)
|
||||
|
|
|
@ -3,12 +3,18 @@ import os
|
|||
from quixote import get_request, get_response, get_session
|
||||
from quixote.directory import Directory
|
||||
|
||||
from sqlobject import *
|
||||
|
||||
from wcs import errors
|
||||
from wcs import misc
|
||||
from wcs import storage
|
||||
from wcs import template
|
||||
from wcs.form import *
|
||||
|
||||
from wcs.categories import Category
|
||||
from wcs.consultationdef import Consultation
|
||||
from wcs.formdata import FormData
|
||||
from wcs.users import User
|
||||
|
||||
def html_top [html] (title = None):
|
||||
template.html_top(title = title, script = '<script src="/js/sorttable.js"></script>')
|
||||
|
||||
|
@ -19,29 +25,25 @@ class BackOfficeDirectory(Directory):
|
|||
_q_exports = [""]
|
||||
|
||||
def _q_index [html] (self):
|
||||
html_top(_("Consultations"))
|
||||
"<h1>%s</h1>" % _('Back Office')
|
||||
html_top(_('Back Office'))
|
||||
'<h1>%s</h1>' % _('Consultations')
|
||||
|
||||
session = get_session()
|
||||
user = None
|
||||
if session and session.user and not session.user.startswith(str('anonymous-')):
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
except KeyError:
|
||||
pass
|
||||
if session and session.user and not str(session.user).startswith(str('anonymous-')):
|
||||
user = User.get(session.user)
|
||||
|
||||
l = []
|
||||
for k in storage.get_storage().keys(str('consultations')):
|
||||
consultation = storage.get_storage().retrieve('consultations', k)
|
||||
if user and (consultation.receiver in (user.roles or []) or 'site-admin' in user.roles):
|
||||
l.append(consultation)
|
||||
if user:
|
||||
for consultation in Consultation.select(orderBy = Consultation.q.name):
|
||||
if user.is_admin or consultation.receiver in user.roles:
|
||||
l.append(consultation)
|
||||
l.sort(lambda x,y: cmp(x.name, y.name))
|
||||
|
||||
cats = storage.get_storage().values('categories')
|
||||
cats.sort(lambda x,y: cmp(x.name, y.name))
|
||||
cats = Category.select(orderBy = Category.q.name)
|
||||
one = False
|
||||
for c in cats:
|
||||
l2 = [x for x in l if x.category == c.id]
|
||||
l2 = [x for x in l if x.categoryID == c.id]
|
||||
if l2:
|
||||
"<h2>%s</h2>" % c.name
|
||||
"<ul>"
|
||||
|
@ -59,6 +61,9 @@ class BackOfficeDirectory(Directory):
|
|||
"""<li><a href="%s/">%s</a></li>""" % (consultation.id, consultation.name)
|
||||
"</ul>"
|
||||
|
||||
if not one and not l2:
|
||||
raise errors.AccessForbiddenError()
|
||||
|
||||
'<a href="..">%s</a>' % _('Back')
|
||||
|
||||
html_foot()
|
||||
|
@ -71,21 +76,15 @@ class ConsultationPage(Directory):
|
|||
|
||||
def __init__(self, component):
|
||||
self.component = component
|
||||
try:
|
||||
self.consultation = storage.get_storage().retrieve('consultations', component)
|
||||
except KeyError:
|
||||
raise errors.TraversalError()
|
||||
self.consultation = Consultation.get(component)
|
||||
|
||||
session = get_session()
|
||||
user = None
|
||||
if session:
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
except KeyError:
|
||||
pass
|
||||
if session and session.user and not str(session.user).startswith(str('anonymous-')):
|
||||
user = User.get(session.user)
|
||||
if not user:
|
||||
raise errors.AccessUnauthorizedError()
|
||||
if not 'site-admin' in user.roles and not self.consultation.receiver in (user.roles or []):
|
||||
if not user.is_admin and not self.consultation.receiver in user.roles:
|
||||
if session.user:
|
||||
raise errors.AccessForbiddenError()
|
||||
else:
|
||||
|
@ -107,84 +106,79 @@ class ConsultationPage(Directory):
|
|||
|
||||
def listing [html] (self):
|
||||
html_top('%s - %s' % (_('Consultation'), self.consultation.name))
|
||||
"<h1>%s</h1>" % _('Back Office')
|
||||
'<h1>%s</h1>' % _('Back Office')
|
||||
'<h2>%s</h2>' % self.consultation.name
|
||||
names = 'consultation-' + self.consultation.id
|
||||
"""<table id="listing" class="sortable"><thead><tr>"""
|
||||
"<th></th>"
|
||||
for f in self.consultation.questions:
|
||||
if f['answer'] in ('title', 'subtitle', 'comment', 'newpage'):
|
||||
'<table id="listing" class="sortable"><thead><tr>'
|
||||
'<th></th>'
|
||||
for f in self.consultation.fields:
|
||||
if f.type in ('title', 'subtitle', 'comment', 'newpage'):
|
||||
continue
|
||||
"<th>%s</th>" % f['question']
|
||||
"</tr></thead>"
|
||||
"<tbody>"
|
||||
for k in storage.get_storage().keys(names):
|
||||
filled = storage.get_storage().retrieve(names, k)
|
||||
'<th>%s</th>' % f.label
|
||||
'</tr></thead>'
|
||||
'<tbody>'
|
||||
items = FormData.select(FormData.q.consultationID == self.consultation.id)
|
||||
for filled in items:
|
||||
if filled.status != 'done':
|
||||
continue
|
||||
"<tr>"
|
||||
'<tr>'
|
||||
link = os.path.join(get_request().environ['SCRIPT_NAME'], 'consultations',
|
||||
self.consultation.id, filled.id, 'status')
|
||||
str(self.consultation.id), str(filled.id), 'status')
|
||||
'<td><a href="/%s">☞</a></td>' % link
|
||||
for f in self.consultation.questions:
|
||||
if f['answer'] in ('title', 'subtitle', 'comment', 'newpage'):
|
||||
for f in self.consultation.fields:
|
||||
if f.type in ('title', 'subtitle', 'comment', 'newpage'):
|
||||
continue
|
||||
"<td>%s</td>" % filled.data.get(f['question'], '')
|
||||
"</tr>\n"
|
||||
"</tbody></table>"
|
||||
'<td>%s</td>' % filled.data.get(f.id, '')
|
||||
'</tr>\n'
|
||||
'</tbody></table>'
|
||||
'<a href=".">%s</a>' % _('Back')
|
||||
html_foot()
|
||||
|
||||
def csv [plain] (self):
|
||||
names = 'consultation-' + self.consultation.id
|
||||
|
||||
def fixcsv(s):
|
||||
if type(s) is not str: return s
|
||||
if not s: return s
|
||||
return s.replace('\n', ' ').replace(';', ',')
|
||||
|
||||
questions = [x for x in self.consultation.questions if x['answer'] not in (
|
||||
'title', 'subtitle', 'comment', 'newpage')]
|
||||
fields = [x for x in self.consultation.fields \
|
||||
if x.type not in ('title', 'subtitle', 'comment', 'newpage')]
|
||||
|
||||
for k in storage.get_storage().keys(names):
|
||||
filled = storage.get_storage().retrieve(names, k)
|
||||
if filled.status != 'done':
|
||||
continue
|
||||
';'.join([str(fixcsv(filled.data.get(x['question'], ''))) for x in questions]) + '\r\n'
|
||||
items = FormData.select(FormData.q.consultationID == self.consultation.id)
|
||||
for filled in items:
|
||||
';'.join([str(fixcsv(filled.data.get(x.id, ''))) for x in fields]) + '\r\n'
|
||||
response = get_response()
|
||||
response.set_content_type('text/csv')
|
||||
|
||||
def stats [html] (self):
|
||||
html_top('%s - %s' % (_('Consultation'), self.consultation.name))
|
||||
names = 'consultation-' + self.consultation.id
|
||||
|
||||
filled_values = [x for x in storage.get_storage().values(names) if x.status == 'done']
|
||||
filled_values = FormData.select(AND(FormData.q.consultationID == self.consultation.id,
|
||||
FormData.q.status == str('done')))
|
||||
|
||||
'<p>%s %d</p>' % (_('Number of filled consultations:'), len(filled_values))
|
||||
no_records = filled_values.count()
|
||||
'<p>%s %d</p>' % (_('Number of filled consultations:'), no_records)
|
||||
|
||||
for f in self.consultation.questions:
|
||||
if f['answer'] == 'title':
|
||||
'<h3>%s</h3>' % f['question']
|
||||
for f in self.consultation.fields:
|
||||
if f.type == 'title':
|
||||
'<h3>%s</h3>' % f.label
|
||||
continue
|
||||
if f['answer'] == 'subtitle':
|
||||
'<h4>%s</h4>' % f['question']
|
||||
if f.type == 'subtitle':
|
||||
'<h4>%s</h4>' % f.label
|
||||
continue
|
||||
if f['answer'] in ('comment', 'newpage'):
|
||||
if f.type in ('comment', 'newpage'):
|
||||
continue
|
||||
'<div class="question">'
|
||||
'<p class="label">'
|
||||
f['question']
|
||||
f.label
|
||||
'</p>'
|
||||
if f['answer'] == 'item':
|
||||
options = f['items']
|
||||
if f.type == 'item':
|
||||
options = f.extra.get('items', [])
|
||||
'<table>'
|
||||
no_records = len(filled_values)
|
||||
for o in options:
|
||||
'<tr>'
|
||||
'<td class="label">'
|
||||
o
|
||||
'</td>'
|
||||
no = len([None for x in filled_values if x.data.get(f['question']) == o])
|
||||
no = len([None for x in filled_values if x.data.get(f.id) == o])
|
||||
if no_records:
|
||||
'<td class="percent">'
|
||||
' %.2f %%' % (100.*no/no_records)
|
||||
|
@ -200,12 +194,12 @@ class ConsultationPage(Directory):
|
|||
#'NaN'
|
||||
'</tr>'
|
||||
'</table>'
|
||||
elif f['answer'] in ('email', 'string', 'text'):
|
||||
elif f.type in ('email', 'string', 'text'):
|
||||
'<div class="all-the-answers">'
|
||||
for t in filled_values:
|
||||
if t.data.get(f['question'], None):
|
||||
if t.data.get(f.id):
|
||||
'<div>'
|
||||
t.data.get(f['question'])
|
||||
t.data.get(f.id)
|
||||
'<hr /></div>'
|
||||
'</div>'
|
||||
else:
|
||||
|
|
|
@ -1,17 +1,24 @@
|
|||
import random
|
||||
import time
|
||||
|
||||
from quixote import get_request, get_response, get_session, redirect
|
||||
from quixote.directory import Directory, AccessControlled
|
||||
|
||||
from sqlobject import *
|
||||
|
||||
from wcs import errors
|
||||
from wcs import formdata
|
||||
from wcs import storage
|
||||
from wcs import misc
|
||||
from wcs import users
|
||||
from wcs import template
|
||||
from wcs.form import *
|
||||
|
||||
from wcs.categories import Category
|
||||
from wcs.anonylink import AnonymityLink
|
||||
from wcs.consultationdef import Consultation
|
||||
from wcs.users import User
|
||||
from wcs.roles import get_logged_users_role
|
||||
from wcs.formdata import FormData
|
||||
|
||||
from backoffice import BackOfficeDirectory
|
||||
|
||||
def html_top [html] (title = None):
|
||||
|
@ -20,34 +27,16 @@ def html_top [html] (title = None):
|
|||
def html_foot [html] ():
|
||||
template.html_foot()
|
||||
|
||||
def get_consultation_key(session, consultation, generate = True):
|
||||
if session.user:
|
||||
return session.user
|
||||
|
||||
if session.anonymous_id:
|
||||
return session.anonymous_id
|
||||
|
||||
if not generate:
|
||||
return None
|
||||
|
||||
while True:
|
||||
random_key = 'random-%d' % random.randint(0, 1000000000)
|
||||
if not storage.get_storage().has_key(
|
||||
"consultation-" + consultation.id, random_key):
|
||||
break
|
||||
session.anonymous_id = random_key
|
||||
return random_key
|
||||
|
||||
|
||||
def get_summary [html] (consultation, filled):
|
||||
for f in consultation.questions:
|
||||
if f['answer'] in ('newpage', 'title', 'subtitle', 'comment'):
|
||||
for f in consultation.fields:
|
||||
if f.type in ('newpage', 'title', 'subtitle', 'comment'):
|
||||
continue
|
||||
'<div class="question">'
|
||||
'<p class="label">'
|
||||
f['question']
|
||||
f.label
|
||||
'</p>'
|
||||
'<p>%s</p>' % filled.data.get(f['question'], '')
|
||||
'<p>%s</p>' % filled.data.get(f.id, '')
|
||||
'</div>'
|
||||
|
||||
|
||||
|
@ -56,21 +45,16 @@ class ConsultationStatusPage(Directory):
|
|||
|
||||
def __init__(self, consultation, component):
|
||||
self.consultation = consultation
|
||||
try:
|
||||
self.filled = storage.get_storage().retrieve(
|
||||
"consultation-" + self.consultation.id, component)
|
||||
except KeyError:
|
||||
self.filled = FormData.get(component)
|
||||
if self.filled.consultation != self.consultation:
|
||||
raise errors.TraversalError()
|
||||
|
||||
def check_receiver(self):
|
||||
session = get_session()
|
||||
if not session or not session.user:
|
||||
raise errors.AccessUnauthorizedError()
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
except KeyError:
|
||||
raise errors.AccessUnauthorizedError()
|
||||
if not (self.consultation.receiver in user.roles or 'site-admin' in user.roles):
|
||||
user = User.get(session.user)
|
||||
if not (user.is_admin or self.formdef.receiver in user.roles):
|
||||
raise errors.AccessForbiddenError()
|
||||
|
||||
def status [html] (self):
|
||||
|
@ -91,44 +75,43 @@ class ConsultationPage(Directory):
|
|||
_q_exports = ["", "submit"]
|
||||
|
||||
def __init__(self, component):
|
||||
self.component = component
|
||||
try:
|
||||
self.consultation = storage.get_storage().retrieve('consultations', component)
|
||||
except KeyError:
|
||||
self.consultation = Consultation.byUrl_name(component)
|
||||
except errors.SQLObjectNotFound:
|
||||
raise errors.TraversalError()
|
||||
|
||||
self.page_number = len([
|
||||
x for x in self.consultation.questions if x['answer'] == 'newpage']) + 1
|
||||
x for x in self.consultation.fields if x.type == 'newpage']) + 1
|
||||
|
||||
session = get_session()
|
||||
user = None
|
||||
if session:
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
except KeyError:
|
||||
user = users.User()
|
||||
if session and session.user and not str(session.user).startswith(str('anonymous-')):
|
||||
user = User.get(session.user)
|
||||
if self.consultation.roles:
|
||||
if not session.user:
|
||||
raise errors.AccessUnauthorizedError()
|
||||
if 'logged-users' not in self.consultation.roles and not 'site-admin' in user.roles:
|
||||
for q in user.roles or []:
|
||||
if not user.is_admin and not get_logged_users_role() not in formdef.roles:
|
||||
for q in user.roles:
|
||||
if q in self.consultation.roles or q == self.consultation.receiver:
|
||||
break
|
||||
else:
|
||||
raise errors.AccessForbiddenError()
|
||||
|
||||
consultation_key = get_consultation_key(session, self.consultation)
|
||||
try:
|
||||
self.filled = storage.get_storage().retrieve(
|
||||
"consultation-" + self.consultation.id, consultation_key)
|
||||
except KeyError:
|
||||
self.filled = formdata.FormData()
|
||||
self.filled.names = 'consultation-' + self.component
|
||||
self.filled.data = {}
|
||||
self.filled.status = 'started'
|
||||
self.filled.id = consultation_key
|
||||
if session and session.user:
|
||||
self.filled.user_id = session.user
|
||||
self.filled = self.consultation.get_filled(session)
|
||||
except SQLObjectNotFound:
|
||||
self.filled = FormData()
|
||||
self.filled.consultation = self.consultation
|
||||
if user:
|
||||
self.filled.user = user
|
||||
else:
|
||||
a = AnonymityLink(formdata = self.filled)
|
||||
if session.name_identifier:
|
||||
a.name_identifier = session.name_identifier
|
||||
else:
|
||||
a.key = session.get_anonymous_key()
|
||||
self.filled.status = 'watched'
|
||||
|
||||
|
||||
def _q_index [html] (self):
|
||||
self.page(0)
|
||||
|
@ -173,12 +156,16 @@ class ConsultationPage(Directory):
|
|||
return self.page(page_no, page_change = False)
|
||||
|
||||
page_no = int(page_no) + 1
|
||||
self.filled.data.update(self.consultation.get_data(form))
|
||||
data = self.filled.data
|
||||
data.update(self.consultation.get_data(form))
|
||||
self.filled.data = data
|
||||
|
||||
if self.filled.status == 'watched':
|
||||
self.filled.status = 'started'
|
||||
|
||||
if page_no == self.page_number:
|
||||
self.filled.receipt_time = time.localtime()
|
||||
self.filled.status = 'done'
|
||||
storage.get_storage().store(self.filled)
|
||||
|
||||
if page_no == self.page_number:
|
||||
return self.page_end()
|
||||
|
@ -203,43 +190,40 @@ class RootDirectory(Directory):
|
|||
|
||||
session = get_session()
|
||||
user = None
|
||||
if session and session.user and not session.user.startswith(str('anonymous-')):
|
||||
if session and session.user and not str(session.user).startswith(str('anonymous-')):
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
user = User.get(session.user)
|
||||
"<p>%s</p>" % _('You are logged in as %s.') % user.name
|
||||
except KeyError:
|
||||
user = users.User()
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
|
||||
backoffice_link = False
|
||||
l = []
|
||||
for k in storage.get_storage().keys(str('consultations')):
|
||||
consultation = storage.get_storage().retrieve('consultations', k)
|
||||
if user and consultation.receiver in (user.roles or []):
|
||||
for consultation in Consultation.select(orderBy = Consultation.q.name):
|
||||
if user and consultation.receiver in user.roles:
|
||||
backoffice_link = True
|
||||
if consultation.roles:
|
||||
if not session.user:
|
||||
continue
|
||||
if 'logged-users' not in consultation.roles:
|
||||
for q in user.roles or []:
|
||||
if get_logged_users_role() not in consultation.roles:
|
||||
for q in (user and user.roles) or []:
|
||||
if q in consultation.roles:
|
||||
break
|
||||
else:
|
||||
continue
|
||||
l.append(consultation)
|
||||
if user and 'site-admin' in user.roles:
|
||||
if user and user.is_admin:
|
||||
backoffice_link = True
|
||||
l.sort(lambda x,y: cmp(x.name, y.name))
|
||||
|
||||
cats = storage.get_storage().values('categories')
|
||||
cats.sort(lambda x,y: cmp(x.name, y.name))
|
||||
cats = Category.select(orderBy = Category.q.name)
|
||||
one = False
|
||||
for c in cats:
|
||||
l2 = [x for x in l if x.category == c.id]
|
||||
l2 = [x for x in l if x.categoryID == c.id]
|
||||
if l2:
|
||||
self.consultation_list(l2, title = c.name, session = session)
|
||||
one = True
|
||||
|
||||
l2 = [x for x in l if not x.category]
|
||||
l2 = [x for x in l if not x.categoryID]
|
||||
if l2:
|
||||
if one:
|
||||
title = _('Misc')
|
||||
|
@ -252,7 +236,7 @@ class RootDirectory(Directory):
|
|||
if backoffice_link:
|
||||
'<a href="backoffice/">%s</a> ' % _('Back Office')
|
||||
if not misc.cfg.get('misc', {}).get('do-not-token', False) and \
|
||||
session.user.startswith(str('anonymous-')):
|
||||
str(session.user).startswith(str('anonymous-')):
|
||||
"""<a href="../token">%s</a> - """ % _('Enter Identification Token')
|
||||
"""<a href="../logout">%s</a></p>""" % _('Logout')
|
||||
|
||||
|
@ -266,16 +250,21 @@ class RootDirectory(Directory):
|
|||
'<h2>%s</h2>' % title
|
||||
'<ul>'
|
||||
for consultation in list:
|
||||
'<li><a href="%s/">%s</a>' % (consultation.id, consultation.name)
|
||||
try:
|
||||
filled = consultation.get_filled(session)
|
||||
except SQLObjectNotFound:
|
||||
filled = None
|
||||
|
||||
consultation_key = get_consultation_key(session, consultation, generate = False)
|
||||
if consultation_key and storage.get_storage().has_key(
|
||||
'consultation-' + consultation.id, consultation_key):
|
||||
filled = storage.get_storage().retrieve(
|
||||
"consultation-" + consultation.id, consultation_key)
|
||||
if filled.status == 'done':
|
||||
' (%s)' % _('Already completed')
|
||||
'</li>'
|
||||
if filled and filled.status == 'done':
|
||||
'<li>%s (%s, <a href="%s/">%s</a>)</li>' % (consultation.name,
|
||||
_('already completed'),
|
||||
consultation.url_name,
|
||||
_('review'))
|
||||
elif filled and filled.status == 'started':
|
||||
'<li><a href="%s/">%s</a> (%s)</li>' % (consultation.url_name,
|
||||
consultation.name, _('being filled'))
|
||||
else:
|
||||
'<li><a href="%s/">%s</a></li>' % (consultation.url_name, consultation.name)
|
||||
'</ul>'
|
||||
|
||||
def _q_lookup(self, component):
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import quixote
|
||||
from quixote.errors import *
|
||||
from sqlobject import SQLObjectNotFound
|
||||
|
||||
import template
|
||||
|
||||
|
|
113
wcs/formdata.py
113
wcs/formdata.py
|
@ -1,28 +1,101 @@
|
|||
import storage
|
||||
from sqlobject import *
|
||||
from extracols import DictPickleCol
|
||||
import time
|
||||
|
||||
class Evolution:
|
||||
who = None
|
||||
status = None
|
||||
time = None
|
||||
comment = None
|
||||
from anonylink import AnonymityLink
|
||||
|
||||
def __init__(self, status, comment, who):
|
||||
self.status = status
|
||||
self.comment = comment
|
||||
self.who = who
|
||||
self.time = time.localtime()
|
||||
class FormDataEvolution(SQLObject):
|
||||
_cacheValues = False
|
||||
|
||||
class FormData(storage.Storable):
|
||||
who = ForeignKey('User', default = None)
|
||||
status = StringCol(length = 40)
|
||||
time = DateTimeCol()
|
||||
comment = StringCol(default = None)
|
||||
formdata = ForeignKey('FormData')
|
||||
|
||||
#def __init__(self, status, comment, who):
|
||||
# self.time = time.localtime() #XXX: do not forget
|
||||
|
||||
class FormData(SQLObject):
|
||||
key = 'id'
|
||||
names = 'forms'
|
||||
user_id = None
|
||||
receipt_time = None
|
||||
status = None
|
||||
evolution = None
|
||||
_cacheValues = False
|
||||
|
||||
def __init__(self):
|
||||
self.id = None
|
||||
self.data = None
|
||||
self.user_id = None
|
||||
user = ForeignKey('User', default = None)
|
||||
receipt_time = DateTimeCol(default = None)
|
||||
status = StringCol(default = None, length = 40)
|
||||
evolution = MultipleJoin('FormDataEvolution', joinMethodName = 'evolution',
|
||||
joinColumn = 'formdata_id')
|
||||
data = DictPickleCol(default = None)
|
||||
|
||||
formdef = ForeignKey('FormDef', default = None)
|
||||
consultation = ForeignKey('Consultation', default = None)
|
||||
|
||||
|
||||
def migrateOldData(cls):
|
||||
import storage
|
||||
from formdef import FormDef
|
||||
from consultationdef import Consultation
|
||||
from users import User
|
||||
|
||||
def migrate(objectdef):
|
||||
if isinstance(objectdef, FormDef):
|
||||
formdataname = 'formtmp-%s' % objectdef.id
|
||||
elif isinstance(objectdef, Consultation):
|
||||
formdataname = 'consultationtmp-%s' % objectdef.id
|
||||
formdata_init_method = FormData.__init__
|
||||
FormData.__init__ = lambda x: x
|
||||
formdatadicts = [x.__dict__ for x in storage.get_storage().values(formdataname)]
|
||||
FormData.__init__ = formdata_init_method
|
||||
fields = objectdef.fields
|
||||
for formdict in formdatadicts:
|
||||
formdata = FormData()
|
||||
if isinstance(objectdef, FormDef):
|
||||
formdata.formdef = objectdef
|
||||
elif isinstance(objectdef, Consultation):
|
||||
formdata.consultation = objectdef
|
||||
if formdict.get('user_id'):
|
||||
user_id = formdict.get('user_id')
|
||||
if user_id == 'ultra-user':
|
||||
pass # ignore, this shouldn't have happened
|
||||
elif str(user_id).startswith('anonymous-'):
|
||||
a = AnonymityLink(formdata = formdata)
|
||||
a.name_identifier = user_id[10:]
|
||||
elif str(user_id).startswith('_'): # really old wcs versions
|
||||
a = AnonymityLink(formdata = formdata)
|
||||
a.name_identifier = user_id
|
||||
else:
|
||||
try:
|
||||
formdata.user = User.get(user_id)
|
||||
except ValueError:
|
||||
a = AnonymityLink(formdata = formdata)
|
||||
a.key = user_id
|
||||
|
||||
formdata.status = formdict.get('status')
|
||||
formdata.receipt_time = formdict.get('receipt_time')
|
||||
newdata = {}
|
||||
for k, v in formdict.get('data', {}).items():
|
||||
# changed keys from 'field name' to 'field id'
|
||||
try:
|
||||
field = [x for x in fields if x.label == k][0]
|
||||
except IndexError:
|
||||
continue
|
||||
newdata[field.id] = v
|
||||
formdata.data = newdata
|
||||
for evo in formdict.get('evolution', []):
|
||||
evo_dict = evo.__dict__
|
||||
evo = FormDataEvolution(formdata = formdata,
|
||||
time = evo_dict.get('time'),
|
||||
status = evo_dict.get('status'))
|
||||
if evo_dict.get('who'):
|
||||
evo.who = User.get(evo_dict.get('who'))
|
||||
evo.comment = evo_dict.get('comment')
|
||||
|
||||
for objectdef in FormDef.select():
|
||||
migrate(objectdef)
|
||||
for objectdef in Consultation.select():
|
||||
migrate(objectdef)
|
||||
migrateOldData = classmethod(migrateOldData)
|
||||
|
||||
class Evolution: # for backward compatibility with old pickled files
|
||||
pass
|
||||
|
|
250
wcs/formdef.py
250
wcs/formdef.py
|
@ -1,10 +1,13 @@
|
|||
import emails
|
||||
|
||||
from sqlobject import *
|
||||
from extracols import DictPickleCol
|
||||
from quixote import get_request, get_session
|
||||
|
||||
import storage
|
||||
import emails
|
||||
|
||||
from form import *
|
||||
from misc import simplify
|
||||
|
||||
from formdata import FormData
|
||||
|
||||
widget_classes = {
|
||||
'string': StringWidget,
|
||||
|
@ -28,103 +31,112 @@ status_labels = {
|
|||
'finished': N_('Finished')
|
||||
}
|
||||
|
||||
class FormField(SQLObject):
|
||||
label = StringCol(length = 300)
|
||||
type = StringCol(length = 20)
|
||||
required = BoolCol(default = True)
|
||||
extra = DictPickleCol(default = None)
|
||||
formdef = ForeignKey('FormDef')
|
||||
position = IntCol(default = None)
|
||||
|
||||
class FormDef(storage.Storable):
|
||||
|
||||
class FormDef(SQLObject):
|
||||
key = 'id'
|
||||
names = 'formdefs'
|
||||
receiver = None
|
||||
roles = None
|
||||
category = None
|
||||
discussion = False
|
||||
confirmation = True
|
||||
public = False
|
||||
detailed_emails = False
|
||||
|
||||
def __init__(self):
|
||||
self.id = ''
|
||||
self.name = ''
|
||||
self.fields = []
|
||||
self.receiver = ''
|
||||
self.category = ''
|
||||
self.roles = []
|
||||
name = StringCol(length = 200)
|
||||
url_name = StringCol(default = None, length = 200, alternateID = True)
|
||||
fields = MultipleJoin('FormField', joinMethodName = 'fields', joinColumn = 'formdef_id',
|
||||
orderBy = FormField.q.position)
|
||||
receiver = ForeignKey('Role', default = None)
|
||||
category = ForeignKey('Category', default = None)
|
||||
roles = RelatedJoin('Role')
|
||||
discussion = BoolCol(default = False)
|
||||
confirmation = BoolCol(default = True)
|
||||
public = BoolCol(default = False)
|
||||
detailed_emails = BoolCol(default = False)
|
||||
|
||||
def _set_name(self, value):
|
||||
self._SO_set_name(value)
|
||||
if not self.url_name or FormData.select(FormData.q.formdefID == self.id).count() == 0:
|
||||
self.url_name = simplify(value)
|
||||
|
||||
def create_form(self): # XXX: merge create_form and create_view_form
|
||||
form = Form(enctype = "multipart/form-data", use_tokens = not self.confirmation)
|
||||
for i, field in enumerate(self.fields):
|
||||
if field['type'] == 'title':
|
||||
form.widgets.append(HtmlWidget(htmltext("<h3>%s</h3>" % field['name'])))
|
||||
for field in self.fields:
|
||||
if field.type == 'title':
|
||||
form.widgets.append(HtmlWidget(htmltext('<h3>%s</h3>' % field.label)))
|
||||
continue
|
||||
if field['type'] == 'subtitle':
|
||||
form.widgets.append(HtmlWidget(htmltext("<h4>%s</h4>" % field['name'])))
|
||||
if field.type == 'subtitle':
|
||||
form.widgets.append(HtmlWidget(htmltext('<h4>%s</h4>' % field.label)))
|
||||
continue
|
||||
if field['type'] == 'comment':
|
||||
form.widgets.append(HtmlWidget(htmltext("<p>%s</p>" % field['name'])))
|
||||
if field.type == 'comment':
|
||||
form.widgets.append(HtmlWidget(htmltext('<p>%s</p>' % field.label)))
|
||||
continue
|
||||
|
||||
widget_class = widget_classes[field['type']]
|
||||
widget_class = widget_classes[field.type]
|
||||
|
||||
kwargs = {'required': field.get('required', True)}
|
||||
if field['type'] == 'item':
|
||||
kwargs['options'] = field.get('items', ['---'])
|
||||
if field.get('show-as-radio'):
|
||||
kwargs = {'required': field.required}
|
||||
if field.type == 'item':
|
||||
kwargs['options'] = field.extra.get('items', ['---'])
|
||||
if field.extra.get('show-as-radio'):
|
||||
widget_class = RadiobuttonsWidget
|
||||
if widget_extra_attributes.has_key(field['type']):
|
||||
for k in widget_extra_attributes[field['type']]:
|
||||
v = field.get(k, None)
|
||||
if v is not None:
|
||||
if widget_extra_attributes.has_key(field.type):
|
||||
for k in widget_extra_attributes[field.type]:
|
||||
v = field.extra.get(k)
|
||||
if v:
|
||||
kwargs[k] = v
|
||||
form.add(widget_class, "f%d" % i, title = field['name'], **kwargs)
|
||||
form.add(widget_class, 'f%d' % field.id, title = field.label, **kwargs)
|
||||
return form
|
||||
|
||||
def create_view_form(self, dict = {}):
|
||||
form = Form(enctype = "multipart/form-data")
|
||||
session = get_session()
|
||||
for i, field in enumerate(self.fields):
|
||||
for field in self.fields:
|
||||
kwargs = {}
|
||||
if field['type'] == 'title':
|
||||
form.widgets.append(HtmlWidget(htmltext("<h3>%s</h3>" % field['name'])))
|
||||
if field.type == 'title':
|
||||
form.widgets.append(HtmlWidget(htmltext('<h3>%s</h3>' % field.label)))
|
||||
continue
|
||||
if field['type'] == 'subtitle':
|
||||
form.widgets.append(HtmlWidget(htmltext("<h4>%s</h4>" % field['name'])))
|
||||
if field.type == 'subtitle':
|
||||
form.widgets.append(HtmlWidget(htmltext('<h4>%s</h4>' % field.label)))
|
||||
continue
|
||||
if field['type'] == 'comment':
|
||||
form.widgets.append(HtmlWidget(htmltext("<p>%s</p>" % field['name'])))
|
||||
if field.type == 'comment':
|
||||
form.widgets.append(HtmlWidget(htmltext('<p>%s</p>' % field.label)))
|
||||
continue
|
||||
|
||||
widget_class = widget_classes[field['type']]
|
||||
value = dict.get(field['name'], '')
|
||||
if field['type'] == 'item':
|
||||
widget_class = widget_classes[field.type]
|
||||
value = dict.get(field.label, '')
|
||||
if field.type == 'item':
|
||||
widget_class = StringWidget
|
||||
|
||||
if field['type'] == 'file':
|
||||
if field.type == 'file':
|
||||
kwargs['preview'] = True
|
||||
if field['type'] == 'bool':
|
||||
if field.type == 'bool':
|
||||
kwargs['disabled'] = 'disabled'
|
||||
|
||||
if widget_extra_attributes.has_key(field['type']):
|
||||
for k in widget_extra_attributes[field['type']]:
|
||||
v = field.get(k, None)
|
||||
if v is not None:
|
||||
if widget_extra_attributes.has_key(field.type):
|
||||
for k in widget_extra_attributes[field.type]:
|
||||
v = field.extra.get(k)
|
||||
if v:
|
||||
kwargs[k] = v
|
||||
|
||||
if field['type'] == 'file':
|
||||
if field.type == 'file':
|
||||
widget_class = FakeFileWidget
|
||||
|
||||
form.add(widget_class, "f%d" % i, title = field['name'],
|
||||
readonly = "readonly", value = value, **kwargs)
|
||||
form.add(widget_class, 'f%d' % field.id, title = field.label,
|
||||
value = value, readonly = 'readonly', **kwargs)
|
||||
return form
|
||||
|
||||
def get_data(self, form):
|
||||
d = {}
|
||||
for i, field in enumerate(self.fields):
|
||||
if field['type'] in ('title', 'subtitle', 'comment'):
|
||||
continue
|
||||
d[field['name']] = form.get_widget('f%d' % i).parse()
|
||||
for field in self.fields:
|
||||
widget = form.get_widget('f%s' % field.id)
|
||||
if widget:
|
||||
d[field.id] = widget.parse()
|
||||
return d
|
||||
|
||||
def notify_new(self, formdata):
|
||||
receiver = storage.get_storage().retrieve('roles', self.receiver)
|
||||
if not receiver.emails:
|
||||
if not self.receiver.emails:
|
||||
return
|
||||
url = '%s/%s/status' % (get_request().get_url(1), formdata.id)
|
||||
mail_body = _("""Hi,
|
||||
|
@ -134,50 +146,42 @@ link: %(url)s
|
|||
""") % {'url': url}
|
||||
if self.detailed_emails:
|
||||
details = []
|
||||
submitter = None
|
||||
try:
|
||||
submitter = storage.get_storage().retrieve('users', formdata.user_id)
|
||||
except KeyError:
|
||||
pass
|
||||
if submitter:
|
||||
if formdata.user:
|
||||
details.append(_('User name'))
|
||||
details.append(' %s' % submitter.name)
|
||||
for i, f in enumerate(self.fields):
|
||||
if not formdata.data.has_key(f['name']):
|
||||
details.append(' %s' % formdata.user.name)
|
||||
fields = self.fields
|
||||
for field in self.fields:
|
||||
data = formdata.data
|
||||
if not data.has_key(field.id):
|
||||
continue
|
||||
details.append(f['name'])
|
||||
if f['type'] == 'bool':
|
||||
if formdata.data[f['name']]:
|
||||
details.append(field.label)
|
||||
if field.type == 'bool':
|
||||
if data[field.id]:
|
||||
details.append(' %s' % _('Yes'))
|
||||
else:
|
||||
details.append(' %s' % _('No'))
|
||||
elif f['type'] == 'file':
|
||||
file_url = url.replace('status', 'download?f=%d' % i)
|
||||
elif field.type == 'file':
|
||||
file_url = url.replace('status', 'download?f=%d' % field.id)
|
||||
details.append(' %s' % file_url)
|
||||
#details.append(' %s' % formdata.data[f['name']])
|
||||
elif f['type'] == 'text':
|
||||
elif field.type == 'text':
|
||||
# XXX: howto support preformatted text in a dl in docutils ?
|
||||
details.append(formdata.data[f['name']].replace('\n', '\n '))
|
||||
details.append(data[field.id].replace('\n', '\n '))
|
||||
else:
|
||||
details.append(' %s' % formdata.data[f['name']])
|
||||
details.append(' %s' % data[field.id])
|
||||
mail_body += '\n\n' + '\n'.join(details)
|
||||
|
||||
emails.email(_("New form (%s)") % self.name, mail_body, receiver.emails[0],
|
||||
bcc = receiver.emails[1:])
|
||||
emails.email(_("New form (%s)") % self.name, mail_body,
|
||||
self.receiver.emails[0].email,
|
||||
bcc = [x.email for x in self.receiver.emails[1:]])
|
||||
|
||||
def notify_change_user(self, formdata, old_status):
|
||||
if not formdata.user_id:
|
||||
if not formdata.user:
|
||||
return
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', formdata.user_id)
|
||||
except KeyError:
|
||||
return
|
||||
if not user.email:
|
||||
if not formdata.user.email:
|
||||
return
|
||||
|
||||
receiver = storage.get_storage().retrieve('roles', self.receiver)
|
||||
if receiver.emails:
|
||||
from_email = receiver.emails[0]
|
||||
if self.receiver.emails:
|
||||
from_email = self.receiver.emails[0].email
|
||||
else:
|
||||
from_email = None
|
||||
|
||||
|
@ -203,7 +207,7 @@ consult it with this link:
|
|||
|
||||
mail_body += self.get_detailed_evolution(formdata)
|
||||
|
||||
emails.email(_('Form status change'), mail_body, user.email,
|
||||
emails.email(_('Form status change'), mail_body, formdata.user.email,
|
||||
replyto = from_email)
|
||||
|
||||
def get_detailed_evolution(self, formdata):
|
||||
|
@ -213,13 +217,8 @@ consult it with this link:
|
|||
details = []
|
||||
evo = formdata.evolution[-1]
|
||||
if evo.who:
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', evo.who)
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
details.append(_('User name'))
|
||||
details.append(' %s' % user.name)
|
||||
details.append(_('User name'))
|
||||
details.append(' %s' % evo.who.name)
|
||||
if evo.status:
|
||||
details.append(_('Status'))
|
||||
details.append(' %s' % _(status_labels[evo.status]))
|
||||
|
@ -229,8 +228,7 @@ consult it with this link:
|
|||
|
||||
|
||||
def notify_change_receiver(self, formdata):
|
||||
receiver = storage.get_storage().retrieve('roles', self.receiver)
|
||||
if not receiver.emails:
|
||||
if not self.receiver.emails:
|
||||
return
|
||||
|
||||
url = '%s/status' % get_request().get_url(1)
|
||||
|
@ -242,5 +240,57 @@ A form just changed, you can consult it with this link:
|
|||
""") % {'url': url}
|
||||
mail_body += self.get_detailed_evolution(formdata)
|
||||
|
||||
emails.email(_('Form status change (%s)') % self.name, mail_body, receiver.emails)
|
||||
emails.email(_('Form status change (%s)') % self.name, mail_body,
|
||||
[x.email for x in self.receiver.emails])
|
||||
|
||||
def migrateOldData(cls):
|
||||
import storage
|
||||
from roles import Role, get_logged_users_role
|
||||
from categories import Category
|
||||
|
||||
init_method = cls.__init__
|
||||
cls.__init__ = lambda x: x
|
||||
formdefs = storage.get_storage().values('formdefs')
|
||||
items = [x.__dict__ for x in formdefs]
|
||||
cls.__init__ = init_method
|
||||
|
||||
items.sort(lambda x,y: cmp(x['id'], y['id']))
|
||||
logged_users = get_logged_users_role()
|
||||
for item in items:
|
||||
formdef = FormDef(name = item['name'])
|
||||
formdef.url_name = item['id']
|
||||
try:
|
||||
formdef.receiver = Role.get(item['receiver'])
|
||||
except SQLObjectNotFound:
|
||||
formdef.receiver = None
|
||||
if item.get('category'):
|
||||
formdef.category = Category.get(item['category'])
|
||||
for role in item.get('roles', []):
|
||||
if role == 'logged-users':
|
||||
formdef.addRole(logged_users)
|
||||
continue
|
||||
formdef.addRole(Role.get(role))
|
||||
formdef.discussion = item.get('discussion', False)
|
||||
formdef.confirmation = item.get('confirmation', True)
|
||||
formdef.public = item.get('public', False)
|
||||
formdef.detailed_emails = item.get('detailed_emails', False)
|
||||
for i, field in enumerate(item['fields']):
|
||||
fieldObject = FormField(label = field['name'], type = field['type'],
|
||||
formdef = formdef)
|
||||
fieldObject.required = field.get('required', False)
|
||||
fieldObject.position = i
|
||||
d = field.copy()
|
||||
del d['name']
|
||||
del d['type']
|
||||
if d.has_key('required'):
|
||||
del d['required']
|
||||
if d:
|
||||
fieldObject.extra = d
|
||||
|
||||
# convert submitted forms
|
||||
name = 'form-%s' % item['id']
|
||||
newname = 'formtmp-%s' % formdef.id
|
||||
storage.get_storage().rename_table(name, newname)
|
||||
|
||||
migrateOldData = classmethod(migrateOldData)
|
||||
|
||||
|
|
|
@ -5,9 +5,12 @@ from quixote.directory import Directory
|
|||
|
||||
from wcs import errors
|
||||
from wcs import misc
|
||||
from wcs import storage
|
||||
from wcs import template
|
||||
from wcs.form import *
|
||||
from wcs.categories import Category
|
||||
from wcs.formdata import FormData
|
||||
from wcs.formdef import FormDef
|
||||
from wcs.users import User
|
||||
|
||||
from root import status_labels
|
||||
|
||||
|
@ -29,29 +32,24 @@ class BackOfficeDirectory(Directory):
|
|||
_q_exports = [""]
|
||||
|
||||
def _q_index [html] (self):
|
||||
html_top()
|
||||
"<h1>%s</h1>" % _('Back Office')
|
||||
html_top(_('Back Office'))
|
||||
'<h1>%s</h1>' % _('Forms')
|
||||
|
||||
session = get_session()
|
||||
user = None
|
||||
if session and session.user and not session.user.startswith(str('anonymous-')):
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
except KeyError:
|
||||
pass
|
||||
if session and session.user and not str(session.user).startswith(str('anonymous-')):
|
||||
user = User.get(session.user)
|
||||
|
||||
l = []
|
||||
for k in storage.get_storage().keys(str('formdefs')):
|
||||
formdef = storage.get_storage().retrieve('formdefs', k)
|
||||
if user and (formdef.receiver in (user.roles or []) or 'site-admin' in user.roles):
|
||||
l.append(formdef)
|
||||
l.sort(lambda x,y: cmp(x.name, y.name))
|
||||
if user:
|
||||
for formdef in FormDef.select(orderBy = FormDef.q.name):
|
||||
if user.is_admin or formdef.receiver in user.roles:
|
||||
l.append(formdef)
|
||||
|
||||
cats = storage.get_storage().values('categories')
|
||||
cats.sort(lambda x,y: cmp(x.name, y.name))
|
||||
cats = Category.select(orderBy = Category.q.name)
|
||||
one = False
|
||||
for c in cats:
|
||||
l2 = [x for x in l if x.category == c.id]
|
||||
l2 = [x for x in l if x.categoryID == c.id]
|
||||
if l2:
|
||||
"<h2>%s</h2>" % c.name
|
||||
"<ul>"
|
||||
|
@ -84,19 +82,17 @@ class FormDefUI:
|
|||
self.formdef = formdef
|
||||
|
||||
def listing [html] (self, url_action = None):
|
||||
names = 'form-' + self.formdef.id
|
||||
"""<table id="listing" class="sortable"><thead><tr>"""
|
||||
"<th></th>"
|
||||
'<table id="listing" class="sortable"><thead><tr>'
|
||||
'<th></th>'
|
||||
for f in self.formdef.fields:
|
||||
if f['type'] in ('title', 'subtitle', 'comment'):
|
||||
if f.type in ('title', 'subtitle', 'comment'):
|
||||
continue
|
||||
"<th>%s</th>" % f['name']
|
||||
"<th>%s</th>" % _('Status')
|
||||
"</tr></thead>"
|
||||
"<tbody>"
|
||||
items = storage.get_storage().values(names)
|
||||
items.sort(lambda x,y: cmp(x.receipt_time, y.receipt_time))
|
||||
items.reverse()
|
||||
'<th>%s</th>' % f.label
|
||||
'<th>%s</th>' % _('Status')
|
||||
'</tr></thead>'
|
||||
'<tbody>'
|
||||
items = FormData.select(FormData.q.formdefID == self.formdef.id,
|
||||
orderBy = str('-receipt_time'))
|
||||
if url_action:
|
||||
url_action = '/' + url_action
|
||||
else:
|
||||
|
@ -104,24 +100,24 @@ class FormDefUI:
|
|||
for filled in items:
|
||||
'<tr class="status-%s">' % filled.status
|
||||
link = os.path.join(get_request().environ['SCRIPT_NAME'], 'forms',
|
||||
self.formdef.id, filled.id)
|
||||
self.formdef.url_name, str(filled.id))
|
||||
'<td><a href="/%s%s">☞</a></td>' % (link, url_action)
|
||||
for i, f in enumerate(self.formdef.fields):
|
||||
if f['type'] in ('title', 'subtitle', 'comment'):
|
||||
if f.type in ('title', 'subtitle', 'comment'):
|
||||
continue
|
||||
if f['type'] == 'bool':
|
||||
if f.type == 'bool':
|
||||
'<td>'
|
||||
if filled.data[f['name']]:
|
||||
if filled.data[f.id]:
|
||||
_('Yes')
|
||||
else:
|
||||
_('No')
|
||||
'</td>'
|
||||
elif f['type'] == 'text':
|
||||
"<td>%s</td>" % ellipsize(filled.data.get(f['name'], '') or '')
|
||||
elif f['type'] == 'file':
|
||||
'<td><a href="/%s/download?f=%d">%s</a></td>' % (link, i, filled.data[f['name']])
|
||||
elif f.type == 'text':
|
||||
"<td>%s</td>" % ellipsize(filled.data.get(f.id, '') or '')
|
||||
elif f.type == 'file':
|
||||
'<td><a href="/%s/download?f=%d">%s</a></td>' % (link, f.id, filled.data[f.id])
|
||||
else:
|
||||
"<td>%s</td>" % filled.data.get(f['name'], '')
|
||||
"<td>%s</td>" % filled.data.get(f.id, '')
|
||||
"<td>%s</td>" % _(status_labels[filled.status])
|
||||
"</tr>\n"
|
||||
"</tbody></table>"
|
||||
|
@ -132,22 +128,18 @@ class FormPage(Directory):
|
|||
_q_exports = ["", "listing", "csv"]
|
||||
|
||||
def __init__(self, component):
|
||||
self.component = component
|
||||
try:
|
||||
self.formdef = storage.get_storage().retrieve('formdefs', component)
|
||||
except KeyError:
|
||||
self.formdef = FormDef.get(component)
|
||||
except errors.SQLObjectNotFound:
|
||||
raise errors.TraversalError()
|
||||
|
||||
session = get_session()
|
||||
user = None
|
||||
if session:
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
except KeyError:
|
||||
pass
|
||||
user = User.get(session.user)
|
||||
if not user:
|
||||
raise errors.AccessUnauthorizedError()
|
||||
if not 'site-admin' in user.roles and not self.formdef.receiver in (user.roles or []):
|
||||
if not user.is_admin and not self.formdef.receiver in user.roles:
|
||||
if session.user:
|
||||
raise errors.AccessForbiddenError()
|
||||
else:
|
||||
|
@ -174,18 +166,16 @@ class FormPage(Directory):
|
|||
html_foot()
|
||||
|
||||
def csv [plain] (self):
|
||||
names = 'form-' + self.formdef.id
|
||||
|
||||
def fixcsv(s):
|
||||
if type(s) is not str: return s
|
||||
if not s: return s
|
||||
return s.replace('\n', ' ').replace(';', ',')
|
||||
|
||||
fields = [x for x in self.formdef.fields if x['type'] not in ('title', 'subtitle', 'file')]
|
||||
fields = [x for x in self.formdef.fields if x.type not in ('title', 'subtitle', 'file')]
|
||||
|
||||
for k in storage.get_storage().keys(names):
|
||||
filled = storage.get_storage().retrieve(names, k)
|
||||
';'.join([str(fixcsv(filled.data.get(x['name'], ''))) for x in fields]) + '\r\n'
|
||||
items = FormData.select(FormData.q.formdefID == self.formdef.id)
|
||||
for filled in items:
|
||||
';'.join([str(fixcsv(filled.data.get(x.id, ''))) for x in fields]) + '\r\n'
|
||||
response = get_response()
|
||||
response.set_content_type('text/csv')
|
||||
|
||||
|
|
|
@ -4,15 +4,21 @@ import time
|
|||
from quixote import get_request, get_response, get_session, redirect
|
||||
from quixote.directory import Directory, AccessControlled
|
||||
|
||||
from sqlobject import *
|
||||
|
||||
from wcs import errors
|
||||
from wcs import formdata
|
||||
from wcs import storage
|
||||
from wcs import misc
|
||||
from wcs import users
|
||||
from wcs import template
|
||||
from wcs.form import *
|
||||
|
||||
from wcs.formdef import status_labels
|
||||
from wcs.anonylink import AnonymityLink
|
||||
from wcs.categories import Category
|
||||
from wcs.formdef import FormField, FormDef, status_labels
|
||||
from wcs.formdata import FormData
|
||||
from wcs.users import User
|
||||
from wcs.roles import get_logged_users_role
|
||||
|
||||
|
||||
from backoffice import BackOfficeDirectory, FormDefUI
|
||||
|
@ -30,40 +36,48 @@ class FormStatusPage(Directory):
|
|||
def __init__(self, formdef, component):
|
||||
self.formdef = formdef
|
||||
try:
|
||||
self.filled = storage.get_storage().retrieve("form-" + formdef.id, component)
|
||||
except KeyError:
|
||||
self.filled = FormData.get(component)
|
||||
except errors.SQLObjectNotFound:
|
||||
raise errors.TraversalError()
|
||||
if self.filled.formdef != self.formdef:
|
||||
raise errors.TraversalError()
|
||||
|
||||
def _q_index [html] (self):
|
||||
session = get_session()
|
||||
if not self.formdef.public and (not session or self.filled.user_id != session.user):
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
except KeyError:
|
||||
mine = False
|
||||
if self.filled.userID != session.user:
|
||||
mine = True
|
||||
elif str(session.user).startswith(str('anonymous-')):
|
||||
anonylink = AnonymityLink.select(AND(
|
||||
AnonymityLink.q.name_identifier == session.name_identifier,
|
||||
AnonymityLink.q.formdataID == self.filled.id))
|
||||
if anonylink.count() == 0:
|
||||
mine = True
|
||||
|
||||
if not self.formdef.public and not mine:
|
||||
user = User.get(session.user)
|
||||
if not user.is_admin:
|
||||
raise errors.AccessError()
|
||||
if not 'site-admin' in user.roles:
|
||||
raise errors.AccessError()
|
||||
html_top(self.formdef.name + ' - ' + self.filled.id)
|
||||
|
||||
html_top('%s - %s' % (self.formdef.name, self.filled.id))
|
||||
if self.filled.receipt_time is not None:
|
||||
tm = time.strftime(str("%Y-%m-%d %H:%M"), self.filled.receipt_time)
|
||||
tm = self.filled.receipt_time.strftime(str("%Y-%m-%d %H:%M"))
|
||||
else:
|
||||
tm = '???'
|
||||
"<p>"
|
||||
_('The form has been recorded on %s with the number %s.') % (tm, self.filled.id)
|
||||
"</p>"
|
||||
if self.formdef.receiver and session.user and self.filled.user_id == session.user:
|
||||
try:
|
||||
receiver = storage.get_storage().retrieve('roles', self.formdef.receiver)
|
||||
details = receiver.details
|
||||
except KeyError:
|
||||
details = self.formdef.receiver # was done like that before
|
||||
if details:
|
||||
"<p>"
|
||||
_('Your case is handled by:')
|
||||
"</p>"
|
||||
if self.formdef.receiver and mine:
|
||||
if self.formdef.receiver.details:
|
||||
'<p>'
|
||||
if self.filled.status != 'finished':
|
||||
_('Your case is handled by:')
|
||||
else:
|
||||
_('Your case has been handled by:')
|
||||
'</p>'
|
||||
'<p id="receiver">'
|
||||
htmltext(details.replace(str('\n'), str('<br />')))
|
||||
"</p>"
|
||||
htmltext(self.formdef.receiver.details.replace(str('\n'), str('<br />')))
|
||||
'</p>'
|
||||
|
||||
self.receipt()
|
||||
|
||||
|
@ -94,14 +108,9 @@ class FormStatusPage(Directory):
|
|||
'<h2>%s</h2>' % _('Log')
|
||||
'<dl id="evolutions">'
|
||||
for evo in self.filled.evolution:
|
||||
"<dt>%s" % time.strftime(str("%Y-%m-%d %H:%M"), evo.time)
|
||||
"<dt>%s" % evo.time.strftime(str("%Y-%m-%d %H:%M"))
|
||||
if evo.who:
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', evo.who)
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
' <span class="user">%s</span>' % user.name
|
||||
' <span class="user">%s</span>' % evo.who.name
|
||||
'</dt>'
|
||||
'<dd>'
|
||||
if evo.status:
|
||||
|
@ -118,47 +127,41 @@ class FormStatusPage(Directory):
|
|||
session = get_session()
|
||||
if not session or not session.user:
|
||||
raise errors.AccessUnauthorizedError()
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
except KeyError:
|
||||
raise errors.AccessUnauthorizedError()
|
||||
if not (self.formdef.receiver in user.roles or 'site-admin' in user.roles):
|
||||
user = User.get(session.user)
|
||||
if not (user.is_admin or self.formdef.receiver in user.roles):
|
||||
raise errors.AccessForbiddenError()
|
||||
|
||||
|
||||
def receipt [html] (self, always_include_user = False, show_status = True, form_url = ''):
|
||||
user = None
|
||||
if always_include_user or self.filled.user_id != get_session().user:
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', self.filled.user_id)
|
||||
except KeyError:
|
||||
pass
|
||||
if always_include_user or self.filled.userID != get_session().user:
|
||||
user = self.filled.user
|
||||
|
||||
'<dl id="receipt">'
|
||||
if user:
|
||||
'<dt>%s</dt>' % _('User name')
|
||||
'<dd>%s</dd>' % user.name
|
||||
|
||||
for i, f in enumerate(self.formdef.fields):
|
||||
if not self.filled.data.has_key(f['name']):
|
||||
for f in self.formdef.fields:
|
||||
if not self.filled.data.has_key(f.id):
|
||||
continue
|
||||
'<dt>%s</dt>' % f['name']
|
||||
'<dt>%s</dt>' % f.label
|
||||
'<dd>'
|
||||
if f['type'] == 'bool':
|
||||
if self.filled.data[f['name']]:
|
||||
if f.type == 'bool':
|
||||
if self.filled.data[f.id]:
|
||||
_('Yes')
|
||||
else:
|
||||
_('No')
|
||||
elif f['type'] == 'file':
|
||||
'<a href="%sdownload?f=%d">%s</a>' % (form_url, i, self.filled.data[f['name']])
|
||||
elif f['type'] == 'text':
|
||||
if f.get('pre', False):
|
||||
elif f.type == 'file':
|
||||
'<a href="%sdownload?f=%d">%s</a>' % (form_url, f.id, self.filled.data[f.id])
|
||||
elif f.type == 'text':
|
||||
if f.extra.get('pre', False):
|
||||
'<pre>'
|
||||
self.filled.data[f['name']]
|
||||
if f.get('pre', False):
|
||||
self.filled.data[f.id]
|
||||
if f.extra.get('pre', False):
|
||||
'</pre>'
|
||||
else:
|
||||
self.filled.data[f['name']]
|
||||
self.filled.data[f.id]
|
||||
'</dd>'
|
||||
|
||||
if show_status:
|
||||
|
@ -191,9 +194,9 @@ class FormStatusPage(Directory):
|
|||
response.headers[str('location')] = get_request().get_url()
|
||||
response.content_type = 'text/plain'
|
||||
return "Your browser should redirect you"
|
||||
html_top(self.formdef.name + ' - ' + self.filled.id)
|
||||
html_top('%s - %s' % (self.formdef.name, self.filled.id))
|
||||
if self.filled.receipt_time is not None:
|
||||
tm = time.strftime(str("%Y-%m-%d %H:%M"), self.filled.receipt_time)
|
||||
tm = self.filled.receipt_time.strftime(str("%Y-%m-%d %H:%M"))
|
||||
else:
|
||||
tm = '???'
|
||||
"<p>"
|
||||
|
@ -232,15 +235,14 @@ class FormStatusPage(Directory):
|
|||
|
||||
who = None
|
||||
session = get_session()
|
||||
if session.user and not session.user.startswith('anonymous-'):
|
||||
if session.user and not str(session.user).startswith('anonymous-'):
|
||||
who = session.user
|
||||
evo = formdata.Evolution(status, comment, who)
|
||||
if not self.filled.evolution:
|
||||
self.filled.evolution = []
|
||||
self.filled.evolution.append(evo)
|
||||
evo = formdata.FormDataEvolution(status = status, time = time.localtime(),
|
||||
formdata = self.filled)
|
||||
evo.who = who
|
||||
evo.comment = comment
|
||||
if status:
|
||||
self.filled.status = status
|
||||
storage.get_storage().store(self.filled)
|
||||
|
||||
if comment_only:
|
||||
self.formdef.notify_change_receiver(self.filled)
|
||||
|
@ -248,18 +250,19 @@ class FormStatusPage(Directory):
|
|||
self.formdef.notify_change_user(self.filled, old_status)
|
||||
|
||||
def download(self):
|
||||
if not self.formdef.public and not self.filled.user_id == get_session().user:
|
||||
if not self.formdef.public and not self.filled.userID == get_session().user:
|
||||
self.check_receiver()
|
||||
try:
|
||||
fn = get_request().form['f']
|
||||
f = self.formdef.fields[int(fn)]
|
||||
f = FormField.get(fn)
|
||||
except (KeyError, ValueError):
|
||||
raise
|
||||
raise TraversalError()
|
||||
|
||||
if f['type'] != 'file':
|
||||
if f.type != 'file':
|
||||
raise TraversalError()
|
||||
|
||||
file = self.filled.data[f['name']]
|
||||
file = self.filled.data[int(fn)]
|
||||
response = get_response()
|
||||
if file.content_type:
|
||||
response.set_content_type(file.content_type)
|
||||
|
@ -278,24 +281,23 @@ class FormPage(Directory):
|
|||
_q_exports = ["", "submit", 'listing']
|
||||
|
||||
def __init__(self, component):
|
||||
self.component = component
|
||||
try:
|
||||
self.formdef = storage.get_storage().retrieve('formdefs', component)
|
||||
except KeyError:
|
||||
self.formdef = FormDef.byUrl_name(component)
|
||||
except errors.SQLObjectNotFound:
|
||||
raise errors.TraversalError()
|
||||
|
||||
session = get_session()
|
||||
user = None
|
||||
if session:
|
||||
if session and session.user:
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
except KeyError:
|
||||
user = users.User()
|
||||
user = User.get(session.user)
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
if self.formdef.roles:
|
||||
if not session.user:
|
||||
raise errors.AccessUnauthorizedError()
|
||||
if 'logged-users' not in self.formdef.roles and not 'site-admin' in user.roles:
|
||||
for q in user.roles or []:
|
||||
if get_logged_users_role() not in self.formdef.roles and not (user and user.is_admin):
|
||||
for q in (user and user.roles) or []:
|
||||
if q in self.formdef.roles or q == self.formdef.receiver:
|
||||
break
|
||||
else:
|
||||
|
@ -350,15 +352,17 @@ class FormPage(Directory):
|
|||
if step == '0' and self.formdef.confirmation:
|
||||
return self.validating()
|
||||
else:
|
||||
filled = formdata.FormData()
|
||||
filled.names = 'form-' + self.component
|
||||
filled = formdata.FormData(formdef = self.formdef)
|
||||
filled.data = self.formdef.get_data(form)
|
||||
filled.receipt_time = time.localtime()
|
||||
filled.status = 'new'
|
||||
session = get_session()
|
||||
if session and session.user:
|
||||
filled.user_id = session.user
|
||||
storage.get_storage().store(filled)
|
||||
if session and session.user and not str(session.user).startswith(str('anonymous-')):
|
||||
filled.user = User.get(session.user)
|
||||
else:
|
||||
a = AnonymityLink(formdata = filled)
|
||||
if session.name_identifier:
|
||||
a.name_identifier = session.name_identifier
|
||||
self.formdef.notify_new(filled)
|
||||
return self.receipt_page(filled)
|
||||
|
||||
|
@ -383,34 +387,31 @@ class FormPage(Directory):
|
|||
else:
|
||||
self.step(1)
|
||||
|
||||
tm = time.strftime(str("%Y-%m-%d %H:%M"), filled.receipt_time)
|
||||
tm = filled.receipt_time.strftime(str("%Y-%m-%d %H:%M"))
|
||||
"<p>"
|
||||
_('The form has been recorded on %s with the number %s.') % (tm, filled.id)
|
||||
"</p>"
|
||||
if self.formdef.receiver:
|
||||
try:
|
||||
receiver = storage.get_storage().retrieve('roles', self.formdef.receiver)
|
||||
details = receiver.details
|
||||
except KeyError:
|
||||
details = self.formdef.receiver # was done like that before
|
||||
if details:
|
||||
if self.formdef.receiver.details:
|
||||
"<p>"
|
||||
_('Your case will be handled by:')
|
||||
"</p>"
|
||||
'<p id="receiver">'
|
||||
htmltext(details.replace(str('\n'), str('<br />')))
|
||||
htmltext(self.formdef.receiver.details.replace(str('\n'), str('<br />')))
|
||||
"</p>"
|
||||
|
||||
form_status = FormStatusPage(self.formdef, filled.id)
|
||||
form_status.receipt(show_status = False,
|
||||
form_url = os.path.join(get_request().get_url(1), filled.id, ''))
|
||||
form_url = os.path.join(get_request().get_url(1), str(filled.id), ''))
|
||||
'<a href="..">%s</a>' % _("Back Home")
|
||||
html_foot()
|
||||
|
||||
|
||||
def listing [html] (self):
|
||||
html_top('%s - %s' % (_('Listing'), self.formdef.name))
|
||||
if 'site-admin' in self.user.roles or self.formdef.receiver in (self.user.roles or []):
|
||||
if self.user and (
|
||||
'site-admin' in self.user.roles or
|
||||
self.formdef.receiver in (self.user.roles or [])):
|
||||
FormDefUI(self.formdef).listing('status')
|
||||
else:
|
||||
FormDefUI(self.formdef).listing()
|
||||
|
@ -437,43 +438,40 @@ class RootDirectory(AccessControlled, Directory):
|
|||
|
||||
session = get_session()
|
||||
user = None
|
||||
if session and session.user and not session.user.startswith(str('anonymous-')):
|
||||
if session and session.user and not str(session.user).startswith(str('anonymous-')):
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
user = User.get(session.user)
|
||||
"<p>%s</p>" % _('You are logged in as %s.') % user.name
|
||||
except KeyError:
|
||||
user = users.User()
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
|
||||
backoffice_link = False
|
||||
l = []
|
||||
for k in storage.get_storage().keys(str('formdefs')):
|
||||
formdef = storage.get_storage().retrieve('formdefs', k)
|
||||
if user and formdef.receiver in (user.roles or []):
|
||||
for formdef in FormDef.select(orderBy = FormDef.q.name):
|
||||
if user and formdef.receiver in user.roles:
|
||||
backoffice_link = True
|
||||
if formdef.roles:
|
||||
if not session.user:
|
||||
continue
|
||||
if 'logged-users' not in formdef.roles:
|
||||
for q in user.roles or []:
|
||||
if get_logged_users_role() not in formdef.roles:
|
||||
for q in (user and user.roles) or []:
|
||||
if q in formdef.roles:
|
||||
break
|
||||
else:
|
||||
continue
|
||||
l.append(formdef)
|
||||
if user and 'site-admin' in user.roles:
|
||||
if user and user.is_admin:
|
||||
backoffice_link = True
|
||||
l.sort(lambda x,y: cmp(x.name, y.name))
|
||||
|
||||
cats = storage.get_storage().values('categories')
|
||||
cats.sort(lambda x,y: cmp(x.name, y.name))
|
||||
cats = Category.select(orderBy = Category.q.name)
|
||||
one = False
|
||||
for c in cats:
|
||||
l2 = [x for x in l if x.category == c.id]
|
||||
l2 = [x for x in l if x.categoryID == c.id]
|
||||
if l2:
|
||||
self.form_list(l2, title = c.name, session = session)
|
||||
one = True
|
||||
|
||||
l2 = [x for x in l if not x.category]
|
||||
l2 = [x for x in l if not x.categoryID]
|
||||
if l2:
|
||||
if one:
|
||||
title = _('Misc')
|
||||
|
@ -483,34 +481,32 @@ class RootDirectory(AccessControlled, Directory):
|
|||
|
||||
if session and session.user:
|
||||
l = []
|
||||
for k in storage.get_storage().keys('formdefs'):
|
||||
formdef = storage.get_storage().retrieve('formdefs', k)
|
||||
formnames = "form-" + formdef.id
|
||||
for q in storage.get_storage().keys(formnames):
|
||||
filled = storage.get_storage().retrieve(formnames, q)
|
||||
filled.formdef = formdef
|
||||
if filled.user_id == session.user:
|
||||
l.append(filled)
|
||||
l.sort(lambda x,y: -cmp(x.receipt_time, y.receipt_time))
|
||||
current = [x for x in l if x.status in ('new', 'accepted')]
|
||||
if str(session.user).startswith(str('anonymous-')):
|
||||
anonylinks = AnonymityLink.select(
|
||||
AnonymityLink.q.name_identifier == session.name_identifier)
|
||||
user_forms = [x.formdata for x in anonylinks if x.formdata]
|
||||
else:
|
||||
user_forms = FormData.select(FormData.q.userID == session.user,
|
||||
orderBy = FormData.q.receipt_time)
|
||||
current = [x for x in user_forms if x.status in ('new', 'accepted')]
|
||||
if current:
|
||||
'<h2 id="submitted">%s</h2>' % _('Your Current Forms')
|
||||
'<ul>'
|
||||
for f in current:
|
||||
'<li><a href="%s/%s">%s</a>, %s, %s: %s</li>' % (
|
||||
f.formdef.id, f.id, f.formdef.name,
|
||||
time.strftime(str("%Y-%m-%d %H:%M"), f.receipt_time),
|
||||
f.formdef.url_name, f.id, f.formdef.name,
|
||||
f.receipt_time.strftime(str("%Y-%m-%d %H:%M")),
|
||||
_('status'),
|
||||
_(status_labels[f.status]) )
|
||||
'</ul>'
|
||||
done = [x for x in l if x.status in ('rejected', 'finished')]
|
||||
done = [x for x in user_forms if x.status in ('rejected', 'finished')]
|
||||
if done:
|
||||
'<h2 id="done">%s</h2>' % _('Your Old Forms')
|
||||
'<ul>'
|
||||
for f in done:
|
||||
'<li><a href="%s/%s">%s</a>, %s, %s: %s</li>' % (
|
||||
f.formdef.id, f.id, f.formdef.name,
|
||||
time.strftime(str("%Y-%m-%d %H:%M"), f.receipt_time),
|
||||
f.formdef.url_name, f.id, f.formdef.name,
|
||||
f.receipt_time.strftime(str("%Y-%m-%d %H:%M")),
|
||||
_('status'),
|
||||
_(status_labels[f.status]) )
|
||||
'</ul>'
|
||||
|
@ -519,7 +515,7 @@ class RootDirectory(AccessControlled, Directory):
|
|||
if backoffice_link:
|
||||
'<a href="backoffice/">%s</a> ' % _('Back Office')
|
||||
if not misc.cfg.get('misc', {}).get('do-not-token', False) and \
|
||||
session.user.startswith(str('anonymous-')):
|
||||
str(session.user).startswith(str('anonymous-')):
|
||||
"""<a href="../token">%s</a> - """ % _('Enter Identification Token')
|
||||
"""<a href="../logout">%s</a></p>""" % _('Logout')
|
||||
|
||||
|
@ -533,9 +529,9 @@ class RootDirectory(AccessControlled, Directory):
|
|||
'<h2>%s</h2>' % title
|
||||
'<ul>'
|
||||
for formdef in list:
|
||||
'<li><a href="%s/">%s</a>' % (formdef.id, formdef.name)
|
||||
'<li><a href="%s/">%s</a>' % (formdef.url_name, formdef.name)
|
||||
if formdef.public:
|
||||
' <a class="listing" href="%s/listing">%s</a>' % (formdef.id, _('(listing)'))
|
||||
' <a class="listing" href="%s/listing">%s</a>' % (formdef.url_name, _('(listing)'))
|
||||
'</li>'
|
||||
'</ul>'
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ from wcs import misc
|
|||
from wcs import storage
|
||||
from wcs.form import *
|
||||
from wcs.template import *
|
||||
from wcs.users import User
|
||||
from wcs.users import User, NameIdentifier
|
||||
|
||||
|
||||
class RootDirectory(Directory):
|
||||
|
@ -83,7 +83,11 @@ class RootDirectory(Directory):
|
|||
login.processAuthnResponseMsg(get_field('LARES'))
|
||||
login.acceptSso()
|
||||
session = get_session()
|
||||
session.lasso_session_dump = login.session.dump()
|
||||
if login.isSessionDirty:
|
||||
if login.session:
|
||||
session.lasso_session_dump = login.session.dump()
|
||||
else:
|
||||
session.lasso_session_dump = None
|
||||
user = self.lookup_user(session, login)
|
||||
if user:
|
||||
session.set_user(user.id)
|
||||
|
@ -104,11 +108,11 @@ class RootDirectory(Directory):
|
|||
def lookup_user(self, session, login):
|
||||
ni = login.nameIdentifier.content
|
||||
session.name_identifier = ni
|
||||
for user in storage.get_storage().values('users'):
|
||||
if ni in user.name_identifiers:
|
||||
break
|
||||
nis = NameIdentifier.select(NameIdentifier.q.name_identifier == ni)
|
||||
if nis.count():
|
||||
user = nis[0].user
|
||||
else:
|
||||
if lasso.WSF_SUPPORT and misc.cfg.get('misc', {}).get('grab-user-with-wsf', False):
|
||||
if False and lasso.WSF_SUPPORT and misc.cfg.get('misc', {}).get('grab-user-with-wsf', False):
|
||||
disco = lasso.Discovery(login.server)
|
||||
disco.setSessionFromDump(session.lasso_session_dump)
|
||||
disco.initQuery()
|
||||
|
@ -150,18 +154,15 @@ class RootDirectory(Directory):
|
|||
|
||||
if email and name:
|
||||
user = User()
|
||||
user.id = email
|
||||
user.email = email
|
||||
user.name = name
|
||||
user.name_identifiers = [login.nameIdentifier.content]
|
||||
NameIdentifier(name_identifier = login.nameIdentifier.content, user = user)
|
||||
user.lasso_dump = login.identity.dump()
|
||||
storage.get_storage().store(user)
|
||||
return user
|
||||
|
||||
return None
|
||||
|
||||
user.lasso_dump = login.identity.dump()
|
||||
storage.get_storage().store(user)
|
||||
return user
|
||||
|
||||
def singleLogout(self):
|
||||
|
@ -196,8 +197,8 @@ class RootDirectory(Directory):
|
|||
if session.lasso_session_dump:
|
||||
logout.setSessionFromDump(session.lasso_session_dump)
|
||||
if session.user:
|
||||
if not session.user.startswith('anonymous-'):
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
if not str(session.user).startswith('anonymous-'):
|
||||
user = User.Get(session.user)
|
||||
if user.lasso_dump:
|
||||
logout.setIdentityFromDump(user.lasso_dump)
|
||||
elif session.lasso_anonymous_identity_dump:
|
||||
|
@ -228,9 +229,9 @@ class RootDirectory(Directory):
|
|||
if session.lasso_session_dump:
|
||||
logout.setSessionFromDump(session.lasso_session_dump)
|
||||
if session.user:
|
||||
if not session.user.startswith('anonymous-'):
|
||||
if not str(session.user).startswith('anonymous-'):
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
user = User.get(session.user)
|
||||
except KeyError:
|
||||
get_session_manager().expire_session()
|
||||
return redirect('/')
|
||||
|
@ -306,7 +307,7 @@ class RootDirectory(Directory):
|
|||
def fedterm(self, defederation, session):
|
||||
defederation.setSessionFromDump(session.lasso_session_dump)
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
user = User.get(session.user)
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
|
@ -323,7 +324,6 @@ class RootDirectory(Directory):
|
|||
user.lasso_dump = None
|
||||
else:
|
||||
user.lasso_dump = defederation.identity.dump()
|
||||
storage.get_storage().store(user)
|
||||
|
||||
if defederation.isSessionDirty:
|
||||
if defederation.session:
|
||||
|
|
108
wcs/roles.py
108
wcs/roles.py
|
@ -1,16 +1,104 @@
|
|||
import storage
|
||||
from sqlobject import *
|
||||
|
||||
class Role(storage.Storable):
|
||||
def get_logged_users_role():
|
||||
return Role.select(AND(Role.q.name == 'Logged Users', Role.q.system == True))[0]
|
||||
|
||||
class RoleEmail(SQLObject):
|
||||
email = StringCol(length = 100)
|
||||
role = ForeignKey('Role')
|
||||
_cacheValues = False
|
||||
|
||||
|
||||
class Role(SQLObject):
|
||||
key = 'id'
|
||||
names = 'roles'
|
||||
_cacheValues = False
|
||||
|
||||
id = None
|
||||
name = None
|
||||
details = None
|
||||
emails = None
|
||||
name = StringCol(length = 100)
|
||||
details = StringCol(default = None)
|
||||
emails = MultipleJoin('RoleEmail', joinMethodName = 'emails')
|
||||
system = BoolCol(default = False)
|
||||
|
||||
def __init__(self):
|
||||
self.id = ''
|
||||
self.name = ''
|
||||
self.details = ''
|
||||
users = RelatedJoin('User')
|
||||
formdefs = RelatedJoin('FormDef')
|
||||
consultations = RelatedJoin('Consultation')
|
||||
|
||||
def initTable(cls):
|
||||
role = Role(name = N_('Logged Users'))
|
||||
role.details = 'System Group for Logged Users'
|
||||
role.system = True
|
||||
initTable = classmethod(initTable)
|
||||
|
||||
def migrateOldData(cls):
|
||||
import storage
|
||||
from users import User
|
||||
from formdef import FormDef
|
||||
from consultationdef import Consultation
|
||||
|
||||
init_method = cls.__init__
|
||||
cls.__init__ = lambda x: x
|
||||
roles = storage.get_storage().values('roles')
|
||||
items = [x.__dict__ for x in roles]
|
||||
cls.__init__ = init_method
|
||||
|
||||
new_ids_mapping = [('site-admin', 'site-admin')]
|
||||
for item in items:
|
||||
role = Role(name = item['name'])
|
||||
role.details = item.get('details')
|
||||
for email in item.get('emails', []):
|
||||
RoleEmail(email = email, role = role)
|
||||
new_ids_mapping.append( (item['id'], role.id) )
|
||||
|
||||
## fixing other tables to get the new ids
|
||||
# users
|
||||
user_init_method = User.__init__
|
||||
User.__init__ = lambda x: x
|
||||
users = storage.get_storage().values('users')
|
||||
for user in users:
|
||||
current_roles = user.__dict__['roles'][:]
|
||||
user.__dict__['roles'] = []
|
||||
for role in current_roles:
|
||||
if not role in [x[0] for x in new_ids_mapping]:
|
||||
continue # unknown role, skipping
|
||||
user.__dict__['roles'].append([x[1] for x in new_ids_mapping if x[0] == role][0])
|
||||
storage.get_storage().store(user)
|
||||
User.__init__ = user_init_method
|
||||
|
||||
# formdefs
|
||||
formdef_init_method = FormDef.__init__
|
||||
FormDef.__init__ = lambda x: x
|
||||
formdefs = storage.get_storage().values('formdefs')
|
||||
for formdef in formdefs:
|
||||
role = formdef.__dict__['receiver']
|
||||
if not role in [x[0] for x in new_ids_mapping]:
|
||||
formdef.__dict__['receiver'] = -1
|
||||
else:
|
||||
formdef.__dict__['receiver'] = [x[1] for x in new_ids_mapping if x[0] == role][0]
|
||||
|
||||
current_roles = formdef.__dict__.get('roles', [])[:]
|
||||
formdef.__dict__['roles'] = []
|
||||
for role in current_roles:
|
||||
if not role in [x[0] for x in new_ids_mapping]:
|
||||
continue # unknown role, skipping
|
||||
formdef.__dict__['roles'].append([x[1] for x in new_ids_mapping if x[0] == role][0])
|
||||
storage.get_storage().store(formdef)
|
||||
FormDef.__init__ = formdef_init_method
|
||||
|
||||
# consultations
|
||||
consultation_init_method = Consultation.__init__
|
||||
Consultation.__init__ = lambda x: x
|
||||
consultations = storage.get_storage().values('consultations')
|
||||
for consultation in consultations:
|
||||
role = consultation.__dict__['receiver']
|
||||
consultation.__dict__['receiver'] = [x[1] for x in new_ids_mapping if x[0] == role][0]
|
||||
current_roles = formdef.__dict__.get('roles', [])[:]
|
||||
consultation.__dict__['roles'] = []
|
||||
for role in current_roles:
|
||||
if not role in [x[0] for x in new_ids_mapping]:
|
||||
continue # unknown role, skipping
|
||||
consultation.__dict__['roles'].append([x[1] for x in new_ids_mapping \
|
||||
if x[0] == role][0])
|
||||
storage.get_storage().store(consultation)
|
||||
Consultation.__init__ = consultation_init_method
|
||||
migrateOldData = classmethod(migrateOldData)
|
||||
|
||||
|
|
50
wcs/root.ptl
50
wcs/root.ptl
|
@ -11,10 +11,13 @@ import liberty.root
|
|||
|
||||
import errors
|
||||
import misc
|
||||
import storage
|
||||
import template
|
||||
from form import *
|
||||
|
||||
from users import User
|
||||
from formdata import FormData
|
||||
from anonylink import AnonymityLink
|
||||
|
||||
class RootDirectory(Directory):
|
||||
_q_exports = ["", "admin", "forms", "consultations", "login", "logout", "liberty", "token"]
|
||||
|
||||
|
@ -59,36 +62,31 @@ class RootDirectory(Directory):
|
|||
session = get_session()
|
||||
if session.lasso_anonymous_identity_dump:
|
||||
lasso_dump = session.lasso_anonymous_identity_dump
|
||||
elif session.user and not session.user.startswith('anonymous-'):
|
||||
current_user = storage.get_storage().retrieve('users', session.user)
|
||||
elif session.user and not str(session.user).startswith('anonymous-'):
|
||||
current_user = User.get(session.user)
|
||||
lasso_dump = current_user.lasso_dump
|
||||
else:
|
||||
return template.error_page("No Lasso Identity Dump (???)")
|
||||
token = form.get_widget('token').parse()
|
||||
for user in storage.get_storage().values('users'):
|
||||
if user.identification_token == token:
|
||||
user.identification_token = None
|
||||
if not user.name_identifiers:
|
||||
user.name_identifiers = []
|
||||
user.name_identifiers.append(str(session.name_identifier))
|
||||
user.lasso_dump = str(lasso_dump)
|
||||
old_name = session.user
|
||||
session.set_user(user.id)
|
||||
storage.get_storage().store(user)
|
||||
users_with_token = User.select(User.q.identification_token == token)
|
||||
if users_with_token.count() == 0:
|
||||
return template.error_page(_('Unknown Token'))
|
||||
|
||||
user = users_with_token[0]
|
||||
|
||||
NameIdentifier(name_identifier = session.name_identifier, user = user)
|
||||
user.lasso_dump = str(lasso_dump)
|
||||
|
||||
old_name = session.user
|
||||
session.set_user(user.id)
|
||||
|
||||
for formdef in storage.get_storage().values('formdefs'):
|
||||
formnames = "form-" + formdef.id
|
||||
for filled in storage.get_storage().values(formnames):
|
||||
if filled.user_id == old_name:
|
||||
filled.user_id = user.id
|
||||
storage.get_storage().store(filled)
|
||||
for consultationdef in storage.get_storage().values('consultations'):
|
||||
consultationnames = "consultation-" + consultationdef.id
|
||||
for filled in storage.get_storage().values(consultationnames):
|
||||
if filled.user_id == old_name:
|
||||
filled.user_id = user.id
|
||||
storage.get_storage().store(filled)
|
||||
break
|
||||
for formdata in FormData.select(FormData.q.userID == old_name):
|
||||
formdata.user = user
|
||||
|
||||
for anonylink in AnonymityLink.select(
|
||||
AnonymityLink.q.name_identifier == session.name_identifier):
|
||||
anonylink.formdata.user = user
|
||||
|
||||
return redirect('.')
|
||||
|
||||
|
||||
|
|
134
wcs/sessions.py
134
wcs/sessions.py
|
@ -1,67 +1,117 @@
|
|||
from sqlobject import *
|
||||
|
||||
from quixote.session import Session, SessionManager
|
||||
import storage
|
||||
from quixote.util import randbytes
|
||||
|
||||
class BasicSession(Session, storage.Storable):
|
||||
key = 'id'
|
||||
names = 'sessions'
|
||||
from extracols import DictPickleCol, ListPickleCol
|
||||
|
||||
class SqlSession(SQLObject):
|
||||
_cacheValue = False
|
||||
|
||||
session_id = StringCol(notNone = True, alternateID = True, unique = True, length = 255)
|
||||
user = StringCol(default = None)
|
||||
remote_address = StringCol(default = None, length=30)
|
||||
creation_time = FloatCol(default = None)
|
||||
access_time = FloatCol(default = None)
|
||||
|
||||
name_identifier = StringCol(length = 100, default = None)
|
||||
anonymous_key = StringCol(length = 100, default = None)
|
||||
|
||||
after_url = StringCol(default = None)
|
||||
lasso_session_dump = StringCol(default = None)
|
||||
lasso_anonymous_identity_dump = StringCol(default = None)
|
||||
|
||||
tempfiles = DictPickleCol(default = None)
|
||||
form_tokens = ListPickleCol(default = None)
|
||||
|
||||
def _init(self, *args, **kw):
|
||||
return SQLObject._init(self, *args, **kw)
|
||||
|
||||
|
||||
class BasicSession(Session):
|
||||
name_identifier = None
|
||||
after_url = None
|
||||
anonymous_id = None
|
||||
anonymous_key = None
|
||||
tempfiles = None
|
||||
lasso_session_dump = None
|
||||
lasso_anonymous_identity_dump = None
|
||||
tempfiles = None
|
||||
|
||||
def has_info(self):
|
||||
return self.name_identifier or self.after_url or self.anonymous_id or \
|
||||
return self.name_identifier or self.after_url or self.anonymous_key or \
|
||||
self.tempfiles or self.lasso_session_dump or \
|
||||
self.lasso_anonymous_identity_dump or Session.has_info(self)
|
||||
is_dirty = has_info
|
||||
|
||||
def get_anonymous_key(self, generate = False):
|
||||
if self.anonymous_key:
|
||||
return self.anonymous_key
|
||||
if generate:
|
||||
self.anonymous_key = randbytes(20)
|
||||
return self.anonymous_key
|
||||
|
||||
class StorageSessionManager(SessionManager):
|
||||
def __init__(self):
|
||||
self.storage = storage.get_storage()
|
||||
SessionManager.__init__(self, session_class=BasicSession)
|
||||
|
||||
def forget_changes(self, session):
|
||||
pass
|
||||
db_attributes = ['user', 'name_identifier', 'anonymous_key', 'after_url', 'lasso_session_dump',
|
||||
'lasso_anonymous_identity_dump', 'tempfiles']
|
||||
db_underscore_attributes = ['_remote_address', '_creation_time', '_access_time',
|
||||
'_form_tokens']
|
||||
|
||||
def __getitem__(self, session_id):
|
||||
try:
|
||||
return storage.get_storage().retrieve('sessions', session_id)
|
||||
except KeyError:
|
||||
raise KeyError
|
||||
|
||||
def get(self, session_id, default = None):
|
||||
try:
|
||||
return storage.get_storage().retrieve('sessions', session_id)
|
||||
except KeyError:
|
||||
return default
|
||||
|
||||
def commit_changes(self, session):
|
||||
if session and session.id:
|
||||
storage.get_storage().store(session)
|
||||
|
||||
class SqlSessionMapping:
|
||||
def keys(self):
|
||||
return storage.get_storage().keys('sessions')
|
||||
return [x.session_id for x in SqlSession.select()]
|
||||
|
||||
def values(self):
|
||||
return [self.get(k) for k in self.keys()]
|
||||
return [self._from_db(x) for x in SqlSession.select()]
|
||||
|
||||
def items(self):
|
||||
return [(k, self.get(k)) for k in self.keys()]
|
||||
return [(x.session_id, self._from_db(x)) for x in SqlSession.select()]
|
||||
|
||||
def has_key(self, session_id):
|
||||
return session_id in self.keys()
|
||||
def _from_db(self, sqlsession):
|
||||
session = BasicSession(sqlsession.session_id)
|
||||
for attr in db_attributes:
|
||||
setattr(session, attr, getattr(sqlsession, attr))
|
||||
for attr in db_underscore_attributes:
|
||||
setattr(session, attr, getattr(sqlsession, attr[1:]))
|
||||
return session
|
||||
|
||||
def __setitem__(self, session_id, session):
|
||||
storage.get_storage().store(session)
|
||||
|
||||
def __delitem__(self, session_id):
|
||||
if not session_id:
|
||||
return
|
||||
def _to_db(self, session):
|
||||
try:
|
||||
storage.get_storage().remove_id('sessions', session_id)
|
||||
except OSError:
|
||||
raise KeyError
|
||||
sqlsession = SqlSession.bySession_id(session.id)
|
||||
except SQLObjectNotFound:
|
||||
sqlsession = SqlSession(session_id = session.id)
|
||||
|
||||
kw = {}
|
||||
for attr in db_attributes:
|
||||
kw[attr] = getattr(session, attr)
|
||||
for attr in db_underscore_attributes:
|
||||
kw[attr[1:]] = getattr(session, attr)
|
||||
sqlsession.set(**kw)
|
||||
|
||||
def get(self, session_id, default = None):
|
||||
if session_id is None:
|
||||
return default
|
||||
try:
|
||||
return self._from_db(SqlSession.bySession_id(session_id))
|
||||
except SQLObjectNotFound:
|
||||
return default
|
||||
|
||||
def __getitem__(self, k):
|
||||
return self.get(k)
|
||||
|
||||
def has_key(self, k):
|
||||
return (self.get(k) is not None)
|
||||
|
||||
def __setitem__(self, k, v):
|
||||
pass
|
||||
|
||||
def __delitem__(self, k):
|
||||
SqlSession.bySession_id(k).destroySelf()
|
||||
|
||||
|
||||
class SqlSessionManager(SessionManager):
|
||||
def __init__(self):
|
||||
SessionManager.__init__(self, BasicSession, SqlSessionMapping())
|
||||
|
||||
def commit_changes(self, session):
|
||||
if session and session.has_info():
|
||||
self.sessions._to_db(session)
|
||||
|
|
|
@ -24,6 +24,12 @@ class FilesStorage:
|
|||
if self.base_dir and not os.path.exists(self.base_dir):
|
||||
os.mkdir(self.base_dir)
|
||||
|
||||
def rename_table(self, obname, newname):
|
||||
dirname = os.path.join(self.base_dir, str(obname))
|
||||
newdirname = os.path.join(self.base_dir, str(newname))
|
||||
if os.path.exists(dirname):
|
||||
os.rename(dirname, newdirname)
|
||||
|
||||
def keys(self, obname):
|
||||
dirname = os.path.join(self.base_dir, str(obname))
|
||||
if not os.path.exists(dirname):
|
||||
|
@ -43,7 +49,7 @@ class FilesStorage:
|
|||
raise KeyError()
|
||||
|
||||
def store(self, object):
|
||||
obname = object.get_table_name()
|
||||
obname = object.names
|
||||
dirname = os.path.join(self.base_dir, obname)
|
||||
if not os.path.exists(dirname):
|
||||
os.mkdir(dirname)
|
||||
|
|
91
wcs/users.py
91
wcs/users.py
|
@ -1,15 +1,86 @@
|
|||
import storage
|
||||
from sqlobject import *
|
||||
|
||||
class User(storage.Storable):
|
||||
class NameIdentifier(SQLObject):
|
||||
name_identifier = StringCol()
|
||||
user = ForeignKey('User')
|
||||
_cacheValues = False
|
||||
|
||||
|
||||
class User(SQLObject):
|
||||
key = 'id'
|
||||
names = 'users'
|
||||
_cacheValues = False
|
||||
|
||||
def __init__(self):
|
||||
self.id = ''
|
||||
self.name = ''
|
||||
self.email = ''
|
||||
self.roles = []
|
||||
self.name_identifiers = []
|
||||
self.identification_token = None
|
||||
self.lasso_dump = None
|
||||
name = StringCol(default = None, length = 100)
|
||||
email = StringCol(default = None, length = 100)
|
||||
roles = RelatedJoin('Role')
|
||||
name_identifiers = MultipleJoin('NameIdentifier', joinMethodName = 'name_identifiers')
|
||||
identification_token = StringCol(default = None)
|
||||
lasso_dump = StringCol(default = None)
|
||||
is_admin = BoolCol(default = False)
|
||||
|
||||
def migrateOldData(cls):
|
||||
import storage
|
||||
from roles import Role
|
||||
from formdef import FormDef
|
||||
from formdata import FormData
|
||||
from consultationdef import Consultation
|
||||
init_method = cls.__init__
|
||||
cls.__init__ = lambda x: x
|
||||
users = storage.get_storage().values('users')
|
||||
items = [x.__dict__ for x in users]
|
||||
cls.__init__ = init_method
|
||||
|
||||
items.sort(lambda x,y: cmp(x['id'], y['id']))
|
||||
new_ids_mapping = []
|
||||
for item in items:
|
||||
user = User(name = item['name'])
|
||||
user.email = item.get('email')
|
||||
user.identification_token = item.get('identification_token')
|
||||
user.lasso_dump = item.get('lasso_dump')
|
||||
if 'site-admin' in item.get('roles', []):
|
||||
user.is_admin = True
|
||||
for ni in item.get('name_identifiers', []):
|
||||
NameIdentifier(name_identifier = ni, user = user)
|
||||
for role in item.get('roles', []):
|
||||
if role == 'site-admin':
|
||||
continue
|
||||
user.addRole(Role.get(role))
|
||||
new_ids_mapping.append( (item['id'], user.id) )
|
||||
|
||||
## Fixing other tables to get the new id
|
||||
formdef_init_method = FormDef.__init__
|
||||
FormDef.__init__ = lambda x: x
|
||||
consultation_init_method = Consultation.__init__
|
||||
Consultation.__init__ = lambda x: x
|
||||
formdata_init_method = FormData.__init__
|
||||
FormData.__init__ = lambda x: x
|
||||
formdefs = storage.get_storage().values('formdefs')
|
||||
consultations = storage.get_storage().values('consultations')
|
||||
for elem in formdefs + consultations:
|
||||
if isinstance(elem, FormDef):
|
||||
formdataname = 'form-%s' % elem.__dict__['id']
|
||||
elif isinstance(elem, Consultation):
|
||||
formdataname = 'consultation-%s' % elem.__dict__['id']
|
||||
else:
|
||||
raise "unknown"
|
||||
for formdata in storage.get_storage().values(formdataname):
|
||||
if hasattr(formdata, 'user_id') and formdata.user_id:
|
||||
try:
|
||||
formdata.user_id = [x[1] for x in new_ids_mapping \
|
||||
if x[0] == formdata.user_id][0]
|
||||
except IndexError:
|
||||
pass
|
||||
if formdata.__dict__.has_key('evolution'):
|
||||
for evo in formdata.__dict__['evolution']:
|
||||
if not hasattr(evo, 'who') or not evo.who:
|
||||
continue
|
||||
evo.who = [x[1] for x in new_ids_mapping if x[0] == evo.who][0]
|
||||
storage.get_storage().store(formdata)
|
||||
|
||||
FormData.__init__ = formdata_init_method
|
||||
FormDef.__init__ = formdef_init_method
|
||||
Consultation.__init__ = consultation_init_method
|
||||
|
||||
migrateOldData = classmethod(migrateOldData)
|
||||
|
||||
|
|
Loading…
Reference in New Issue