web/views/eproperties.py
branchtls-sprint
changeset 691 35133d86970b
parent 688 cddfbdee0eb3
child 728 a95b284150d1
equal deleted inserted replaced
688:cddfbdee0eb3 691:35133d86970b
     5 :copyright: 2007-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     5 :copyright: 2007-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
     6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
     7 """
     7 """
     8 __docformat__ = "restructuredtext en"
     8 __docformat__ = "restructuredtext en"
     9 
     9 
    10 from cubicweb.selectors import implements
    10 from logilab.mtconverter import html_escape
       
    11 
       
    12 from logilab.common.decorators import cached
       
    13 
       
    14 from cubicweb.selectors import (one_line_rset, none_rset, implements,
       
    15                                 match_user_groups, chainfirst, chainall)
       
    16 from cubicweb.common.utils import UStringIO
       
    17 from cubicweb.common.view import StartupView
       
    18 from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param, stdmsgs
    11 from cubicweb.web.views import baseviews
    19 from cubicweb.web.views import baseviews
       
    20 from cubicweb.web.form import FormMixIn
       
    21 
       
    22 _ = unicode
       
    23 
       
    24 # some string we want to be internationalizable for nicer display of eproperty
       
    25 # groups
       
    26 _('navigation')
       
    27 _('ui')
       
    28 _('actions')
       
    29 _('boxes')
       
    30 _('components')
       
    31 _('contentnavigation')
    12 
    32 
    13 class EPropertyPrimaryView(baseviews.PrimaryView):
    33 class EPropertyPrimaryView(baseviews.PrimaryView):
    14     __selectors__ = implements('EProperty')
    34     __selectors__ = implements('EProperty')
    15     skip_none = False
    35     skip_none = False
       
    36 
       
    37 
       
    38 def make_togglable_link(nodeid, label, cookiename):
       
    39     """builds a HTML link that switches the visibility & remembers it"""
       
    40     action = u"javascript: toggle_and_remember_visibility('%s', '%s')" % \
       
    41         (nodeid, cookiename)
       
    42     return u'<a href="%s">%s</a>' % (action, label)
       
    43 
       
    44 def css_class(someclass):
       
    45     return someclass and 'class="%s"' % someclass or ''
       
    46 
       
    47 class SystemEPropertiesForm(FormMixIn, StartupView):
       
    48     id = 'systemepropertiesform'
       
    49     __selectors__ = (none_rset, match_user_groups('managers'))
       
    50 
       
    51     title = _('site configuration')
       
    52     controller = 'edit'
       
    53     category = 'startupview'
       
    54 
       
    55     def linkable(self):
       
    56         return True
       
    57 
       
    58     def url(self):
       
    59         """return the url associated with this view. We can omit rql here"""
       
    60         return self.build_url('view', vid=self.id)
       
    61 
       
    62     def _cookie_name(self, somestr):
       
    63         return str('%s_property_%s' % (self.config.appid, somestr))
       
    64 
       
    65     def _group_status(self, group, default=u'hidden'):
       
    66         cookies = self.req.get_cookie()
       
    67         cookiename = self._cookie_name(group)
       
    68         cookie = cookies.get(cookiename)
       
    69         if cookie is None:
       
    70             cookies[cookiename] = default
       
    71             self.req.set_cookie(cookies, cookiename, maxage=None)
       
    72             status = default
       
    73         else:
       
    74             status = cookie.value
       
    75         return status
       
    76 
       
    77     def call(self, **kwargs):
       
    78         """The default view representing the application's index"""
       
    79         self.req.add_js(('cubicweb.edition.js', 'cubicweb.preferences.js'))
       
    80         self.req.add_css('cubicweb.preferences.css')
       
    81         vreg = self.vreg
       
    82         values = self.defined_keys
       
    83         groupedopts = {}
       
    84         mainopts = {}
       
    85         # "self.id=='systemepropertiesform'" to skip site wide properties on
       
    86         # user's preference but not site's configuration
       
    87         for key in vreg.user_property_keys(self.id=='systemepropertiesform'):
       
    88             parts = key.split('.')
       
    89             if parts[0] in vreg:
       
    90                 # appobject configuration
       
    91                 reg, oid, propid = parts
       
    92                 groupedopts.setdefault(reg, {}).setdefault(oid, []).append(key)
       
    93             else:
       
    94                 mainopts.setdefault(parts[0], []).append(key)
       
    95         # precompute form to consume error message
       
    96         for group, keys in mainopts.items():
       
    97             mainopts[group] = self.form(keys, False)
       
    98         for group, objects in groupedopts.items():
       
    99             for oid, keys in objects.items():
       
   100                 groupedopts[group][oid] = self.form(keys, True)
       
   101 
       
   102         w = self.w
       
   103         req = self.req
       
   104         _ = req._
       
   105         w(u'<h1>%s</h1>\n' % _(self.title))
       
   106         w(self.error_message())
       
   107         for label, group, form in sorted((_(g), g, f)
       
   108                                          for g, f in mainopts.iteritems()):
       
   109             status = css_class(self._group_status(group)) #'hidden' (collapsed), or '' (open) ?
       
   110             w(u'<h2 class="propertiesform">%s</h2>\n' %
       
   111               (make_togglable_link('fieldset_' + group, label,
       
   112                                    self._cookie_name(group))))
       
   113             w(u'<div id="fieldset_%s" %s>' % (group, status))
       
   114             w(u'<fieldset class="subentity">')
       
   115             w(form)
       
   116             w(u'</fieldset></div>')
       
   117         for label, group, objects in sorted((_(g), g, o)
       
   118                                             for g, o in groupedopts.iteritems()):
       
   119             status = css_class(self._group_status(group))
       
   120             w(u'<h2 class="propertiesform">%s</h2>\n' %
       
   121               (make_togglable_link('fieldset_' + group, label,
       
   122                                    self._cookie_name(group))))
       
   123             w(u'<div id="fieldset_%s" %s>' % (group, status))
       
   124             for label, oid, form in sorted((self.req.__('%s_%s' % (group, o)), o, f)
       
   125                                            for o, f in objects.iteritems()):
       
   126                 w(u'<fieldset class="subentity">')
       
   127                 w(u'<legend class="componentTitle">%s</legend>\n' % label)
       
   128                 docmsgid = '%s_%s_description' % (group, oid)
       
   129                 doc = _(docmsgid)
       
   130                 if doc != docmsgid:
       
   131                     w(u'<p class="description">%s</p>' % html_escape(doc))
       
   132                 w(form)
       
   133                 w(u'</fieldset>')
       
   134             w(u'</div>')
       
   135 
       
   136     @property
       
   137     @cached
       
   138     def eprops_rset(self):
       
   139         return self.req.execute('Any P,K,V WHERE P is EProperty, P pkey K, P value V, NOT P for_user U')
       
   140 
       
   141     @property
       
   142     def defined_keys(self):
       
   143         values = {}
       
   144         for i, entity in enumerate(self.eprops_rset.entities()):
       
   145             values[entity.pkey] = i
       
   146         return values
       
   147 
       
   148     def entity_for_key(self, key):
       
   149         values = self.defined_keys
       
   150         if key in values:
       
   151             entity = self.eprops_rset.get_entity(values[key], 0)
       
   152         else:
       
   153             entity = self.vreg.etype_class('EProperty')(self.req, None, None)
       
   154             entity.eid = self.req.varmaker.next()
       
   155             entity['value'] = self.vreg.property_value(key)
       
   156         return entity
       
   157 
       
   158     def form(self, keys, splitlabel=False):
       
   159         stream = UStringIO()
       
   160         w = stream.write
       
   161         w(u'<form action="%s" method="post">\n' % self.build_url())
       
   162         w(u'<fieldset>\n')
       
   163         w(u'<input type="hidden" name="__errorurl" value="%s"/>\n'
       
   164           % html_escape(self.req.url()))
       
   165         w(u'<input type="hidden" name="__form_id" value="%s"/>\n' % self.id)
       
   166         path = self.req.relative_path()
       
   167         if '?' in path:
       
   168             path, params = path.split('?', 1)
       
   169             w(u'<input type="hidden" name="__redirectparams" value="%s"/>\n'
       
   170               % html_escape(params))
       
   171         w(u'<input type="hidden" name="__redirectpath" value="%s"/>\n' % path)
       
   172         #w(u'<input type="hidden" name="__redirectrql" value=""/>\n')
       
   173         w(u'<input type="hidden" name="__message" value="%s"/>\n'
       
   174           % self.req._('changes applied'))
       
   175         w(u'<table><tr><td>\n')
       
   176 
       
   177         w(u'<table>\n')
       
   178         for key in keys:
       
   179             w(u'<tr>\n')
       
   180             self.form_row(w, key, splitlabel)
       
   181             w(u'</tr>\n')
       
   182         w(u'</table>\n')
       
   183         w(u'</td></tr><tr><td>\n')
       
   184         w(self.button_ok())
       
   185         w(self.button_cancel())
       
   186         w(u'</td></tr></table>\n')
       
   187         w(u'</fieldset>\n')
       
   188         w(u'</form>\n')
       
   189         return stream.getvalue()
       
   190 
       
   191     def form_row(self, w, key, splitlabel):
       
   192         entity = self.entity_for_key(key)
       
   193         eid = entity.eid
       
   194         if splitlabel:
       
   195             w(u'<td class="label">%s</td>' % self.req._(key.split('.')[-1]))
       
   196         else:
       
   197             w(u'<td class="label">%s</td>' % self.req._(key))
       
   198         wdg = self.vreg.property_value_widget(key, req=self.req)
       
   199         error = wdg.render_error(entity)
       
   200         w(u'<td class="%s">' % (error and 'error' or ''))
       
   201         w(error)
       
   202         self.form_row_hiddens(w, entity, key)
       
   203         w(wdg.edit_render(entity))
       
   204         w(u'</td>\n')
       
   205         w(u'<td>%s</td>' % wdg.render_help(entity))
       
   206         return entity
       
   207 
       
   208     def form_row_hiddens(self, w, entity, key):
       
   209         eid = entity.eid
       
   210         w(u'<input type="hidden" name="eid" value="%s"/>' % eid)
       
   211         w(u'<input type="hidden" name="%s" value="EProperty"/>' % eid_param('__type', eid))
       
   212         w(u'<input type="hidden" name="%s" value="%s"/>' % (eid_param('pkey', eid), key))
       
   213         w(u'<input type="hidden" name="%s" value="%s"/>' % (eid_param('edits-pkey', eid), ''))
       
   214 
       
   215 
       
   216 
       
   217 def is_user_prefs(cls, req, rset, row, col):
       
   218     return req.user.eid == rset[row or 0 ][col or 0]
       
   219 
       
   220 
       
   221 class EPropertiesForm(SystemEPropertiesForm):
       
   222     id = 'epropertiesform'
       
   223     __selectors__ = (
       
   224         implements('EUser'),
       
   225         # we don't want guests to be able to come here
       
   226         match_user_groups('users', 'managers'), 
       
   227         chainfirst(none_rset),
       
   228                    chainall(one_line_rset, is_user_prefs),
       
   229                    chainall(one_line_rset, match_user_groups('managers'))
       
   230         )
       
   231     
       
   232     title = _('preferences')
       
   233 
       
   234     @property
       
   235     def user(self):
       
   236         if self.rset is None:
       
   237             return self.req.user
       
   238         return self.rset.get_entity(self.row or 0, self.col or 0)
       
   239 
       
   240     @property
       
   241     @cached
       
   242     def eprops_rset(self):
       
   243         return self.req.execute('Any P,K,V WHERE P is EProperty, P pkey K, P value V,'
       
   244                                 'P for_user U, U eid %(x)s', {'x': self.user.eid})
       
   245 
       
   246     def form_row_hiddens(self, w, entity, key):
       
   247         super(EPropertiesForm, self).form_row_hiddens(w, entity, key)
       
   248         # if user is in the managers group and the property is being created,
       
   249         # we have to set for_user explicitly
       
   250         if not entity.has_eid() and self.user.matching_groups('managers'):
       
   251             eid = entity.eid
       
   252             w(u'<input type="hidden" name="%s" value="%s"/>'
       
   253               % (eid_param('edits-for_user', eid), INTERNAL_FIELD_VALUE))
       
   254             w(u'<input type="hidden" name="%s" value="%s"/>'
       
   255               % (eid_param('for_user', eid), self.user.eid))
       
   256