diff -r 058bb3dc685f -r 0b59724cb3f2 cubicweb/web/views/cwproperties.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/views/cwproperties.py Sat Jan 16 13:48:51 2016 +0100
@@ -0,0 +1,442 @@
+# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see .
+"""Specific views for CWProperty (eg site/user preferences"""
+
+__docformat__ = "restructuredtext en"
+from cubicweb import _
+
+from logilab.mtconverter import xml_escape
+
+from logilab.common.decorators import cached
+
+from cubicweb import UnknownProperty
+from cubicweb.predicates import (one_line_rset, none_rset, is_instance,
+ match_user_groups, logged_user_in_rset)
+from cubicweb.view import StartupView
+from cubicweb.web import stdmsgs
+from cubicweb.web.form import FormViewMixIn
+from cubicweb.web.formfields import FIELDS, StringField
+from cubicweb.web.formwidgets import (Select, TextInput, Button, SubmitButton,
+ FieldWidget)
+from cubicweb.web.views import uicfg, primary, formrenderers, editcontroller
+from cubicweb.web.views.ajaxcontroller import ajaxfunc
+
+uicfg.primaryview_section.tag_object_of(('*', 'for_user', '*'), 'hidden')
+
+# some string we want to be internationalizable for nicer display of property
+# groups
+_('navigation')
+_('ui')
+_('boxes')
+_('components')
+_('ctxcomponents')
+_('navigation.combobox-limit')
+_('navigation.page-size')
+_('navigation.related-limit')
+_('navigation.short-line-size')
+_('ui.date-format')
+_('ui.datetime-format')
+_('ui.default-text-format')
+_('ui.fckeditor')
+_('ui.float-format')
+_('ui.language')
+_('ui.time-format')
+_('open all')
+_('ui.main-template')
+_('ui.site-title')
+_('ui.encoding')
+_('category')
+
+
+def make_togglable_link(nodeid, label):
+ """builds a HTML link that switches the visibility & remembers it"""
+ return u'%s' % (
+ nodeid, label)
+
+def css_class(someclass):
+ return someclass and 'class="%s"' % someclass or ''
+
+
+class CWPropertyPrimaryView(primary.PrimaryView):
+ __select__ = is_instance('CWProperty')
+ skip_none = False
+
+
+class SystemCWPropertiesForm(FormViewMixIn, StartupView):
+ """site-wide properties edition form"""
+ __regid__ = 'systempropertiesform'
+ __select__ = none_rset() & match_user_groups('managers')
+ form_buttons = [SubmitButton()]
+
+ title = _('site configuration')
+ category = 'startupview'
+
+ def linkable(self):
+ return True
+
+ def url(self):
+ """return the url associated with this view. We can omit rql here"""
+ return self._cw.build_url('view', vid=self.__regid__)
+
+ def _cookie_name(self, somestr):
+ return str('%s_property_%s' % (self._cw.vreg.config.appid, somestr))
+
+ def _group_status(self, group, default=u'hidden'):
+ """return css class name 'hidden' (collapsed), or '' (open)"""
+ cookies = self._cw.get_cookie()
+ cookiename = self._cookie_name(group)
+ cookie = cookies.get(cookiename)
+ if cookie is None:
+ self._cw.set_cookie(cookiename, default, maxage=None)
+ status = default
+ else:
+ status = cookie.value
+ return status
+
+ def call(self, **kwargs):
+ self._cw.add_js(('cubicweb.preferences.js',
+ 'cubicweb.edition.js', 'cubicweb.ajax.js'))
+ self._cw.add_css('cubicweb.preferences.css')
+ values = self.defined_keys
+ mainopts, groupedopts = self.group_properties()
+ # precompute all forms first to consume error message
+ mainforms, groupedforms = self.build_forms(mainopts, groupedopts)
+ _ = self._cw._
+ self.w(u'
%s
\n' % _(self.title))
+ for label, group, form in sorted((_(g), g, f)
+ for g, f in mainforms.items()):
+ self.wrap_main_form(group, label, form)
+ for label, group, objects in sorted((_(g), g, o)
+ for g, o in groupedforms.items()):
+ self.wrap_grouped_form(group, label, objects)
+
+ @property
+ @cached
+ def cwprops_rset(self):
+ return self._cw.execute('Any P,K,V WHERE P is CWProperty, P pkey K, '
+ 'P value V, NOT P for_user U')
+
+ @property
+ def defined_keys(self):
+ values = {}
+ for i, entity in enumerate(self.cwprops_rset.entities()):
+ values[entity.pkey] = i
+ return values
+
+ def group_properties(self):
+ mainopts, groupedopts = {}, {}
+ vreg = self._cw.vreg
+ # "self._regid__=='systempropertiesform'" to skip site wide properties on
+ # user's preference but not site's configuration
+ for key in vreg.user_property_keys(self.__regid__=='systempropertiesform'):
+ parts = key.split('.')
+ if parts[0] in vreg and len(parts) >= 3:
+ # appobject configuration
+ reg = parts[0]
+ propid = parts[-1]
+ oid = '.'.join(parts[1:-1])
+ groupedopts.setdefault(reg, {}).setdefault(oid, []).append(key)
+ else:
+ mainopts.setdefault(parts[0], []).append(key)
+ return mainopts, groupedopts
+
+ def build_forms(self, mainopts, groupedopts):
+ mainforms, groupedforms = {}, {}
+ for group, keys in mainopts.items():
+ mainforms[group] = self.form(group, keys, False)
+ for group, objects in groupedopts.items():
+ groupedforms[group] = {}
+ for oid, keys in objects.items():
+ groupedforms[group][oid] = self.form(group + '_' + oid, keys, True)
+ return mainforms, groupedforms
+
+ def entity_for_key(self, key):
+ values = self.defined_keys
+ if key in values:
+ entity = self.cwprops_rset.get_entity(values[key], 0)
+ else:
+ entity = self._cw.vreg['etypes'].etype_class('CWProperty')(self._cw)
+ entity.eid = next(self._cw.varmaker)
+ entity.cw_attr_cache['pkey'] = key
+ entity.cw_attr_cache['value'] = self._cw.vreg.property_value(key)
+ return entity
+
+ def form(self, formid, keys, splitlabel=False):
+ form = self._cw.vreg['forms'].select(
+ 'composite', self._cw, domid=formid, action=self._cw.build_url(),
+ form_buttons=self.form_buttons,
+ onsubmit="return validatePrefsForm('%s')" % formid,
+ submitmsg=self._cw._('changes applied'))
+ path = self._cw.relative_path()
+ if '?' in path:
+ path, params = path.split('?', 1)
+ form.add_hidden('__redirectparams', params)
+ form.add_hidden('__redirectpath', path)
+ for key in keys:
+ self.form_row(form, key, splitlabel)
+ renderer = self._cw.vreg['formrenderers'].select('cwproperties', self._cw,
+ display_progress_div=False)
+ data = []
+ form.render(w=data.append, renderer=renderer)
+ return u'\n'.join(data)
+
+ def form_row(self, form, key, splitlabel):
+ entity = self.entity_for_key(key)
+ if splitlabel:
+ label = key.split('.')[-1]
+ else:
+ label = key
+ subform = self._cw.vreg['forms'].select('base', self._cw, entity=entity,
+ mainform=False)
+ subform.append_field(PropertyValueField(name='value', label=label, role='subject',
+ eidparam=True))
+ subform.add_hidden('pkey', key, eidparam=True, role='subject')
+ form.add_subform(subform)
+ return subform
+
+ def wrap_main_form(self, group, label, form):
+ status = css_class(self._group_status(group))
+ self.w(u'
' % (group, status))
+ sorted_objects = sorted((self._cw.__('%s_%s' % (group, o)), o, f)
+ for o, f in objects.items())
+ for label, oid, form in sorted_objects:
+ self.wrap_object_form(group, oid, label, form)
+ self.w(u'