# HG changeset patch # User Sylvain Thénault # Date 1507292675 -7200 # Node ID 3fa6c9ef2f5121ea8a8057331e3d9c6504acde5a # Parent 2fc04786dd369f9375d00562fea9da8141b4cd38 [cleanup] Fix some flake8 errors and drop upper bound of copyright along the way. autoform module is not added to flake8-ok-files since there are some remaining errors to be handled, but that's still a start. diff -r 2fc04786dd36 -r 3fa6c9ef2f51 cubicweb/schema.py --- a/cubicweb/schema.py Fri Oct 06 11:45:52 2017 +0200 +++ b/cubicweb/schema.py Fri Oct 06 14:24:35 2017 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2016 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -19,9 +19,8 @@ from __future__ import print_function -import pkgutil import re -from os.path import join, basename +from os.path import join from hashlib import md5 from logging import getLogger from warnings import warn @@ -29,7 +28,6 @@ from six import PY2, text_type, string_types, add_metaclass from six.moves import range -from logilab.common import tempattr from logilab.common.decorators import cached, clear_cache, monkeypatch, cachedproperty from logilab.common.logging_ext import set_log_methods from logilab.common.deprecation import deprecated @@ -44,14 +42,15 @@ cstr_json_dumps, cstr_json_loads) from yams.reader import (CONSTRAINTS, PyFileReader, SchemaLoader, cleanup_sys_modules, fill_schema_from_namespace) +from yams.buildobjs import _add_relation as yams_add_relation -from rql import parse, nodes, RQLSyntaxError, TypeResolverException +from rql import parse, nodes, stmts, RQLSyntaxError, TypeResolverException from rql.analyze import ETypeResolver import cubicweb +from cubicweb import server from cubicweb import ETYPE_NAME_MAP, ValidationError, Unauthorized, _ -from cubicweb import server PURE_VIRTUAL_RTYPES = set(('identity', 'has_text',)) VIRTUAL_RTYPES = set(('eid', 'identity', 'has_text',)) @@ -602,6 +601,8 @@ a given form """ return display_name(req, self.type, form, context) + + ERSchema.display_name = ERSchema_display_name @@ -621,6 +622,8 @@ return frozenset(g for g in self.permissions[action] if isinstance(g, string_types)) except KeyError: return () + + PermissionMixIn.get_groups = get_groups @@ -640,6 +643,8 @@ return tuple(g for g in self.permissions[action] if not isinstance(g, string_types)) except KeyError: return () + + PermissionMixIn.get_rqlexprs = get_rqlexprs @@ -656,6 +661,8 @@ orig_set_action_permissions(self, action, tuple(permissions)) clear_cache(self, 'get_rqlexprs') clear_cache(self, 'get_groups') + + orig_set_action_permissions = PermissionMixIn.set_action_permissions PermissionMixIn.set_action_permissions = set_action_permissions @@ -673,6 +680,8 @@ if action in ('update', 'delete'): return 'owners' in self.get_groups(action) return False + + PermissionMixIn.has_local_role = has_local_role @@ -681,6 +690,8 @@ self.has_perm(req, 'read')): return False return self.has_local_role(action) or self.has_perm(req, action) + + PermissionMixIn.may_have_permission = may_have_permission @@ -691,6 +702,8 @@ return True except Unauthorized: return False + + PermissionMixIn.has_perm = has_perm @@ -734,6 +747,8 @@ for rqlexpr in self.get_rqlexprs(action)): return raise Unauthorized(action, str(self)) + + PermissionMixIn.check_perm = check_perm @@ -818,7 +833,7 @@ """convenience method that returns the *main* (i.e. the first non meta) attribute defined in the entity schema """ - for rschema, _ in self.attribute_definitions(): + for rschema, __ in self.attribute_definitions(): if not (rschema in META_RTYPES or self.is_metadata(rschema)): return rschema @@ -1262,7 +1277,7 @@ # # possible enhancement: check entity being created, it's probably # the main eid unless this is a composite relation - if eidto is None or 'S' in self.mainvars or not 'O' in self.mainvars: + if eidto is None or 'S' in self.mainvars or 'O' not in self.mainvars: maineid = eidfrom qname = role_name(rtype, 'subject') else: @@ -1272,7 +1287,7 @@ msg = session._(self.msg) else: msg = '%(constraint)s %(expression)s failed' % { - 'constraint': session._(self.type()), + 'constraint': session._(self.type()), 'expression': self.expression} raise ValidationError(maineid, {qname: msg}) @@ -1320,9 +1335,6 @@ # workflow extensions ######################################################### -from yams.buildobjs import _add_relation as yams_add_relation - - class workflowable_definition(ybo.metadefinition): """extends default EntityType's metaclass to add workflow relations (i.e. in_state, wf_info_for and custom_workflow). This is the default @@ -1409,7 +1421,8 @@ """ self.info('loading %s schemas', ', '.join(config.cubes())) try: - return super(CubicWebSchemaLoader, self).load(config, config.schema_modnames(), **kwargs) + return super(CubicWebSchemaLoader, self).load( + config, config.schema_modnames(), **kwargs) finally: # we've to cleanup modules imported from cubicweb.schemas as well cleanup_sys_modules([join(cubicweb.CW_SOFTWARE_ROOT, 'schemas')]) @@ -1448,29 +1461,36 @@ return self.regular_formats + tuple(NEED_PERM_FORMATS) return self.regular_formats + # XXX itou for some Statement methods -from rql import stmts - def bw_get_etype(self, name): return orig_get_etype(self, bw_normalize_etype(name)) + + orig_get_etype = stmts.ScopeNode.get_etype stmts.ScopeNode.get_etype = bw_get_etype def bw_add_main_variable_delete(self, etype, vref): return orig_add_main_variable_delete(self, bw_normalize_etype(etype), vref) + + orig_add_main_variable_delete = stmts.Delete.add_main_variable stmts.Delete.add_main_variable = bw_add_main_variable_delete def bw_add_main_variable_insert(self, etype, vref): return orig_add_main_variable_insert(self, bw_normalize_etype(etype), vref) + + orig_add_main_variable_insert = stmts.Insert.add_main_variable stmts.Insert.add_main_variable = bw_add_main_variable_insert def bw_set_statement_type(self, etype): return orig_set_statement_type(self, bw_normalize_etype(etype)) + + orig_set_statement_type = stmts.Select.set_statement_type stmts.Select.set_statement_type = bw_set_statement_type diff -r 2fc04786dd36 -r 3fa6c9ef2f51 cubicweb/web/test/unittest_uicfg.py --- a/cubicweb/web/test/unittest_uicfg.py Fri Oct 06 11:45:52 2017 +0200 +++ b/cubicweb/web/test/unittest_uicfg.py Fri Oct 06 14:24:35 2017 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -15,6 +15,7 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . + import copy import warnings @@ -25,13 +26,13 @@ abaa = uicfg.actionbox_appearsin_addmenu + class UICFGTC(CubicWebTC): def test_default_actionbox_appearsin_addmenu_config(self): self.assertFalse(abaa.etype_get('TrInfo', 'wf_info_for', 'object', 'CWUser')) - class DefinitionOrderTC(CubicWebTC): """This test check that when multiple definition could match a key, only the more accurate apply""" @@ -41,19 +42,19 @@ for rtag in (uicfg.autoform_section, uicfg.autoform_field_kwargs): rtag._old_tagdefs = copy.deepcopy(rtag._tagdefs) new_def = ( - (('*', 'login', '*'), - {'formtype':'main', 'section':'hidden'}), - (('*', 'login', '*'), - {'formtype':'muledit', 'section':'hidden'}), - (('CWUser', 'login', '*'), - {'formtype':'main', 'section':'attributes'}), - (('CWUser', 'login', '*'), - {'formtype':'muledit', 'section':'attributes'}), - (('CWUser', 'login', 'String'), - {'formtype':'main', 'section':'inlined'}), - (('CWUser', 'login', 'String'), - {'formtype':'inlined', 'section':'attributes'}), - ) + (('*', 'login', '*'), + {'formtype': 'main', 'section': 'hidden'}), + (('*', 'login', '*'), + {'formtype': 'muledit', 'section': 'hidden'}), + (('CWUser', 'login', '*'), + {'formtype': 'main', 'section': 'attributes'}), + (('CWUser', 'login', '*'), + {'formtype': 'muledit', 'section': 'attributes'}), + (('CWUser', 'login', 'String'), + {'formtype': 'main', 'section': 'inlined'}), + (('CWUser', 'login', 'String'), + {'formtype': 'inlined', 'section': 'attributes'}), + ) for key, kwargs in new_def: uicfg.autoform_section.tag_subject_of(key, **kwargs) @@ -120,10 +121,12 @@ @tag('uihelper', 'hidden', 'formconfig') def test_uihelper_formconfig(self): afk_get = uicfg.autoform_field_kwargs.get + class CWUserFormConfig(uihelper.FormConfig): etype = 'CWUser' hidden = ('in_group',) fields_order = ('login', 'firstname') + section_conf = uicfg.autoform_section.get('CWUser', 'in_group', '*', 'subject') self.assertCountEqual(section_conf, ['main_hidden', 'muledit_attributes']) self.assertEqual(afk_get('CWUser', 'firstname', 'String', 'subject'), {'order': 1}) diff -r 2fc04786dd36 -r 3fa6c9ef2f51 cubicweb/web/views/autoform.py --- a/cubicweb/web/views/autoform.py Fri Oct 06 11:45:52 2017 +0200 +++ b/cubicweb/web/views/autoform.py Fri Oct 06 14:24:35 2017 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -118,16 +118,10 @@ .. Controlling the generic relation fields """ - -from cubicweb import _ - -from warnings import warn - from six.moves import range from logilab.mtconverter import xml_escape from logilab.common.decorators import iclassmethod, cached -from logilab.common.deprecation import deprecated from logilab.common.registry import NoSelectableObject from cubicweb import neg_role, uilib @@ -185,7 +179,7 @@ return False def process_posted(self, form): - pass # handled by the subform + pass # handled by the subform class InlineEntityEditionFormView(f.FormViewMixIn, EntityView): @@ -237,7 +231,7 @@ **self.cw_extra_kwargs) if self.pform is None: form.restore_previous_post(form.session_key()) - #assert form.parent_form + # assert form.parent_form self.add_hiddens(form, entity) return form @@ -261,7 +255,7 @@ entity = self._entity() rdef = entity.e_schema.rdef(self.rtype, neg_role(self.role), self.petype) card = rdef.role_cardinality(self.role) - if card == '1': # don't display remove link + if card == '1': # don't display remove link return None # if cardinality is 1..n (+), dont display link to remove an inlined form for the first form # allowing to edit the relation. To detect so: @@ -294,7 +288,7 @@ except KeyError: self._cw.data[countkey] = 1 self.form.render(w=self.w, divid=divid, title=title, removejs=removejs, - i18nctx=i18nctx, counter=self._cw.data[countkey] , + i18nctx=i18nctx, counter=self._cw.data[countkey], **kwargs) def form_title(self, entity, i18nctx): @@ -374,21 +368,21 @@ & specified_etype_implements('Any')) _select_attrs = InlineEntityCreationFormView._select_attrs + ('card',) - card = None # make pylint happy - form = None # no actual form wrapped + card = None # make pylint happy + form = None # no actual form wrapped def call(self, i18nctx, **kwargs): self._cw.set_varmaker() divid = "addNew%s%s%s:%s" % (self.etype, self.rtype, self.role, self.peid) self.w(u'
' - % divid) + % divid) js = "addInlineCreationForm('%s', '%s', '%s', '%s', '%s', '%s')" % ( self.peid, self.petype, self.etype, self.rtype, self.role, i18nctx) if self.pform.should_hide_add_new_relation_link(self.rtype, self.card): js = "toggleVisibility('%s'); %s" % (divid, js) __ = self._cw.pgettext self.w(u'+ %s.' - % (self.rtype, self.peid, js, __(i18nctx, 'add a %s' % self.etype))) + % (self.rtype, self.peid, js, __(i18nctx, 'add a %s' % self.etype))) self.w(u'
') @@ -400,6 +394,7 @@ return u'%s:%s:%s' % (eid, rtype, reid) return u'%s:%s:%s' % (reid, rtype, eid) + def toggleable_relation_link(eid, nodeid, label='x'): """return javascript snippet to delete/undelete a relation between two entities @@ -420,6 +415,7 @@ return ['%s:%s:%s' % (subj, rel, obj) for subj, rel, obj in pending if eid is None or eid in (subj, obj)] + def get_pending_deletes(req, eid=None): """shortcut to access req's pending_delete entry @@ -430,6 +426,7 @@ return ['%s:%s:%s' % (subj, rel, obj) for subj, rel, obj in pending if eid is None or eid in (subj, obj)] + def parse_relations_descr(rdescr): """parse a string describing some relations, in the form subjeids:rtype:objeids @@ -443,6 +440,7 @@ for obj in objs.split('_'): yield int(subj), rtype, int(obj) + def delete_relations(req, rdefs): """delete relations from the repository""" # FIXME convert to using the syntax subject:relation:eids @@ -452,6 +450,7 @@ execute(rql, {'x': subj, 'y': obj}) req.set_message(req._('relations deleted')) + def insert_relations(req, rdefs): """insert relations into the repository""" execute = req.execute @@ -468,10 +467,12 @@ peid=peid, petype=petype) return self._call_view(view, i18nctx=i18nctx) + @ajaxfunc(output_type='json') def validate_form(self, action, names, values): return self.validate_form(action, names, values) + @ajaxfunc def cancel_edition(self, errorurl): """cancelling edition from javascript @@ -491,6 +492,7 @@ pendings.append(value) req.session.data[key] = pendings + def _remove_pending(req, eidfrom, rel, eidto, kind): key = 'pending_%s' % kind pendings = req.session.data[key] @@ -499,21 +501,25 @@ pendings.remove(value) req.session.data[key] = pendings + @ajaxfunc(output_type='json') def remove_pending_insert(self, args): eidfrom, rel, eidto = args _remove_pending(self._cw, eidfrom, rel, eidto, 'insert') + @ajaxfunc(output_type='json') def add_pending_inserts(self, tripletlist): for eidfrom, rel, eidto in tripletlist: _add_pending(self._cw, eidfrom, rel, eidto, 'insert') + @ajaxfunc(output_type='json') def remove_pending_delete(self, args): eidfrom, rel, eidto = args _remove_pending(self._cw, eidfrom, rel, eidto, 'delete') + @ajaxfunc(output_type='json') def add_pending_delete(self, args): eidfrom, rel, eidto = args @@ -527,7 +533,6 @@ w = stream.append req = form._cw _ = req._ - __ = _ eid = form.edited_entity.eid w(u'') for rschema, role, related in field.relations_table(form): @@ -541,9 +546,9 @@ w(u'
  • %s%s
  • ' % (viewparams[1], viewparams[0], viewparams[2], viewparams[3])) if not form.force_display and form.maxrelitems < len(related): - link = (u'' - '[%s]' - '' % _('view all')) + link = (u'[%s]' % _('view all')) w(u'
  • %s
  • ' % link) w(u'') w(u'') @@ -619,7 +624,8 @@ if rschema.has_perm(form._cw, 'delete', **haspermkwargs): toggleable_rel_link_func = toggleable_relation_link else: - toggleable_rel_link_func = lambda x, y, z: u'' + def toggleable_rel_link_func(x, y, z): + return u'' for row in range(rset.rowcount): nodeid = relation_id(entity.eid, rschema, role, rset[row][0]) @@ -641,7 +647,7 @@ for pendingid in pending_inserts: eidfrom, rtype, eidto = pendingid.split(':') pendingid = 'id' + pendingid - if int(eidfrom) == entity.eid: # subject + if int(eidfrom) == entity.eid: # subject label = display_name(form._cw, rtype, 'subject', entity.cw_etype) reid = eidto @@ -687,13 +693,14 @@ relname, role = self._cw.form.get('relation').rsplit('_', 1) return u"""\
    - %s
    """ % (hidden and 'hidden' or '', divid, selectid, - xml_escape(json_dumps(entity.eid)), is_cell and 'true' or 'null', relname, - '\n'.join(options)) + xml_escape(json_dumps(entity.eid)), is_cell and 'true' or 'null', + relname, '\n'.join(options)) def _get_select_options(self, entity, rschema, role): """add options to search among all entities of each possible type""" @@ -706,7 +713,7 @@ # NOTE: expect 'limit' arg on choices method of relation field for eview, reid in field.vocabulary(form, limit=limit): if reid is None: - if eview: # skip blank value + if eview: # skip blank value options.append('' % xml_escape(eview)) elif reid != ff.INTERNAL_FIELD_VALUE: @@ -724,7 +731,7 @@ for eschema in targettypes: mode = '%s:%s:%s:%s' % (role, entity.eid, rschema.type, eschema) url = self._cw.build_url(entity.rest_path(), vid='search-associate', - __mode=mode) + __mode=mode) options.append((eschema.display_name(self._cw), '' % ( xml_escape(url), _('Search for'), eschema.display_name(self._cw)))) @@ -784,7 +791,7 @@ for rtype, role in self.editable_attributes(): try: self.field_by_name(str(rtype), role) - continue # explicitly specified + continue # explicitly specified except f.FieldNotFound: # has to be guessed try: @@ -803,7 +810,7 @@ for formview in self.inlined_form_views(): field = self._inlined_form_view_field(formview) self.fields.append(field) - if not field.fieldset in fsio: + if field.fieldset not in fsio: fsio.append(field.fieldset) if self.formtype == 'main': # add the generic relation field if necessary @@ -817,7 +824,7 @@ pass else: self.fields.append(field) - if not field.fieldset in fsio: + if field.fieldset not in fsio: fsio.append(field.fieldset) self.maxrelitems = self._cw.property_value('navigation.related-limit') self.force_display = bool(self._cw.form.get('__force_display')) @@ -949,7 +956,7 @@ relation. """ return (self.should_display_add_new_relation_link( - rschema, existing, card) and + rschema, existing, card) and self.check_inlined_rdef_permissions( rschema, role, tschema, ttype)) @@ -968,7 +975,6 @@ return rdef.has_perm(self._cw, 'add', **rdefkwargs) return rdef.may_have_permission('add', self._cw) - def should_hide_add_new_relation_link(self, rschema, card): """return true if once an inlined creation form is added, the 'add new' link should be hidden @@ -1009,7 +1015,7 @@ pass -## default form ui configuration ############################################## +# default form ui configuration ############################################## _AFS = uicfg.autoform_section # use primary and not generated for eid since it has to be an hidden @@ -1049,6 +1055,7 @@ _AFFK.tag_subject_of(('TrInfo', 'wf_info_for', '*'), {'widget': fw.HiddenInput}) + def registration_callback(vreg): global etype_relation_field diff -r 2fc04786dd36 -r 3fa6c9ef2f51 cubicweb/web/views/cwuser.py --- a/cubicweb/web/views/cwuser.py Fri Oct 06 11:45:52 2017 +0200 +++ b/cubicweb/web/views/cwuser.py Fri Oct 06 14:24:35 2017 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -20,7 +20,7 @@ from cubicweb import _ -from hashlib import sha1 # pylint: disable=E0611 +from hashlib import sha1 # pylint: disable=E0611 from six import text_type from six.moves import range @@ -28,7 +28,6 @@ from logilab.mtconverter import xml_escape from cubicweb import tags -from cubicweb.schema import display_name from cubicweb.predicates import one_line_rset, is_instance, match_user_groups from cubicweb.view import EntityView, StartupView from cubicweb.web import action, formwidgets @@ -39,7 +38,8 @@ _affk = uicfg.autoform_field_kwargs _affk.tag_subject_of(('CWUser', 'in_group', 'CWGroup'), - {'widget': formwidgets.InOutWidget}) + {'widget': formwidgets.InOutWidget}) + class UserPreferencesEntityAction(action.Action): __regid__ = 'prefs' @@ -66,7 +66,7 @@ self.w(u''' '''% self._cw.encoding) + xmlns:foaf="http://xmlns.com/foaf/0.1/"> ''' % self._cw.encoding) for i in range(self.cw_rset.rowcount): self.cell_call(i, 0) self.w(u'\n') @@ -121,6 +121,7 @@ 'U last_login_time LL, G eid %(x)s', {'x': entity.eid}) self.wview('cwgroup.users', rset, 'null') + class CWGroupUsersTable(tableview.RsetTableView): __regid__ = 'cwgroup.users' __select__ = is_instance('CWUser') @@ -135,9 +136,7 @@ __select__ = is_instance('CWGroup') def entity_call(self, entity): - self._cw.add_css(('cubicweb.schema.css','cubicweb.acl.css')) - access_types = ('read', 'delete', 'add', 'update') - w = self.w + self._cw.add_css(('cubicweb.schema.css', 'cubicweb.acl.css')) objtype_access = {'CWEType': ('read', 'delete', 'add', 'update'), 'CWRelation': ('add', 'delete')} rql_cwetype = 'DISTINCT Any X WHERE X %s_permission CWG, X is CWEType, ' \ @@ -170,7 +169,7 @@ # user / groups management views ############################################### class ManageUsersAction(actions.ManagersAction): - __regid__ = 'cwuser' # see rewrite rule /cwuser + __regid__ = 'cwuser' # see rewrite rule /cwuser title = _('users and groups') category = 'manage' @@ -179,7 +178,7 @@ __regid__ = 'cw.users-and-groups-management' __select__ = StartupView.__select__ & match_user_groups('managers') title = _('Users and groups management') - tabs = [_('cw.users-management'), _('cw.groups-management'),] + tabs = [_('cw.users-management'), _('cw.groups-management')] default_tab = 'cw.users-management' def call(self, **kwargs): @@ -191,7 +190,7 @@ class CWUserManagementView(StartupView): __regid__ = 'cw.users-management' __select__ = StartupView.__select__ & match_user_groups('managers') - cache_max_age = 0 # disable caching + cache_max_age = 0 # disable caching # XXX one could wish to display for instance only user's firstname/surname # for non managers but filtering out NULL caused crash with an ldapuser # source. The ldapuser source has been dropped and this code can be updated. @@ -217,24 +216,24 @@ column_renderers = { 'user': tableview.EntityTableColRenderer( - renderfunc=lambda w,x: w(tags.a(x.login, href=x.absolute_url())), + renderfunc=lambda w, x: w(tags.a(x.login, href=x.absolute_url())), sortfunc=lambda x: x.login), 'in_state': tableview.EntityTableColRenderer( - renderfunc=lambda w,x: w(x.cw_adapt_to('IWorkflowable').printable_state), + renderfunc=lambda w, x: w(x.cw_adapt_to('IWorkflowable').printable_state), sortfunc=lambda x: x.cw_adapt_to('IWorkflowable').printable_state), 'in_group': tableview.EntityTableColRenderer( - renderfunc=lambda w,x: x.view('reledit', rtype='in_group', role='subject', w=w)), + renderfunc=lambda w, x: x.view('reledit', rtype='in_group', role='subject', w=w)), 'primary_email': tableview.RelatedEntityColRenderer( - getrelated=lambda x:x.primary_email and x.primary_email[0] or None), + getrelated=lambda x: x.primary_email and x.primary_email[0] or None), 'cw_source': tableview.RelatedEntityColRenderer( getrelated=lambda x: x.cw_source[0]), - } + } class CWGroupsManagementView(StartupView): __regid__ = 'cw.groups-management' __select__ = StartupView.__select__ & match_user_groups('managers') - cache_max_age = 0 # disable caching + cache_max_age = 0 # disable caching rql = ('Any G,GN ORDERBY GN WHERE G is CWGroup, G name GN, NOT G name "owners"') def call(self, **kwargs): @@ -253,6 +252,6 @@ 'group': tableview.MainEntityColRenderer(), 'nb_users': tableview.EntityTableColRenderer( header=_('num. users'), - renderfunc=lambda w,x: w(text_type(x.num_users())), + renderfunc=lambda w, x: w(text_type(x.num_users())), sortfunc=lambda x: x.num_users()), - } + } diff -r 2fc04786dd36 -r 3fa6c9ef2f51 cubicweb/web/views/uicfg.py --- a/cubicweb/web/views/uicfg.py Fri Oct 06 11:45:52 2017 +0200 +++ b/cubicweb/web/views/uicfg.py Fri Oct 06 14:24:35 2017 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. diff -r 2fc04786dd36 -r 3fa6c9ef2f51 cubicweb/web/views/workflow.py --- a/cubicweb/web/views/workflow.py Fri Oct 06 11:45:52 2017 +0200 +++ b/cubicweb/web/views/workflow.py Fri Oct 06 14:24:35 2017 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -25,24 +25,21 @@ from cubicweb import _ import os -from warnings import warn from six import add_metaclass from logilab.mtconverter import xml_escape -from logilab.common.graph import escape from logilab.common.deprecation import class_deprecated from cubicweb import Unauthorized -from cubicweb.predicates import (has_related_entities, one_line_rset, - relation_possible, match_form_params, - score_entity, is_instance, adaptable) +from cubicweb.predicates import (one_line_rset, + relation_possible, match_form_params, + score_entity, is_instance, adaptable) from cubicweb.view import EntityView -from cubicweb.schema import display_name -from cubicweb.web import stdmsgs, action, component, form, action -from cubicweb.web import formfields as ff, formwidgets as fwdgs +from cubicweb.web import stdmsgs, action, component, form +from cubicweb.web import formwidgets as fwdgs from cubicweb.web.views import TmpFileViewMixin -from cubicweb.web.views import uicfg, forms, primary, ibreadcrumbs +from cubicweb.web.views import uicfg, forms, ibreadcrumbs from cubicweb.web.views.tabs import TabbedPrimaryView, PrimaryTab from cubicweb.web.views.dotgraphview import DotGraphView, DotPropsHandler @@ -77,6 +74,7 @@ _afs = uicfg.autoform_section _affk = uicfg.autoform_field_kwargs + # IWorkflowable views ######################################################### class ChangeStateForm(forms.CompositeEntityForm): @@ -84,7 +82,7 @@ # session_key() implementation) __regid__ = domid = 'changestate' - form_renderer_id = 'base' # don't want EntityFormRenderer + form_renderer_id = 'base' # don't want EntityFormRenderer form_buttons = [fwdgs.SubmitButton(), fwdgs.Button(stdmsgs.BUTTON_CANCEL, {'class': fwdgs.Button.css_class + ' cwjs-edition-cancel'})] @@ -132,8 +130,8 @@ class WFHistoryView(EntityView): __regid__ = 'wfhistory' - __select__ = relation_possible('wf_info_for', role='object') & \ - score_entity(lambda x: x.cw_adapt_to('IWorkflowable').workflow_history) + __select__ = (relation_possible('wf_info_for', role='object') + & score_entity(lambda x: x.cw_adapt_to('IWorkflowable').workflow_history)) title = _('Workflow history') @@ -180,6 +178,7 @@ """display incontext view for an entity as well as its current state""" __regid__ = 'incontext-state' __select__ = adaptable('IWorkflowable') + def entity_call(self, entity): iwf = entity.cw_adapt_to('IWorkflowable') self.w(u'%s [%s]' % (entity.view('incontext'), iwf.printable_state)) @@ -238,9 +237,10 @@ _abaa.tag_object_of(('Transition', 'transition_of', 'Workflow'), True) _abaa.tag_object_of(('WorkflowTransition', 'transition_of', 'Workflow'), True) + class WorkflowPrimaryView(TabbedPrimaryView): __select__ = is_instance('Workflow') - tabs = [ _('wf_tab_info'), _('wfgraph'),] + tabs = [_('wf_tab_info'), _('wfgraph')] default_tab = 'wf_tab_info' @@ -253,6 +253,7 @@ self.w(xml_escape(self._cw.view('textincontext', self.cw_rset, row=row, col=col))) + class WorkflowTabTextView(PrimaryTab): __regid__ = 'wf_tab_info' __select__ = PrimaryTab.__select__ & one_line_rset() & is_instance('Workflow') @@ -262,7 +263,7 @@ self.w(u'
    %s
    ' % (entity.printable_value('description'))) self.w(u'%s%s' % (_("workflow_of").capitalize(), _(" :"))) html = [] - for e in entity.workflow_of: + for e in entity.workflow_of: view = e.view('outofcontext') if entity.eid == e.default_workflow[0].eid: view += u' [%s]' % _('default_workflow') @@ -273,10 +274,9 @@ 'Any T,T,DS,T,TT ORDERBY TN WHERE T transition_of WF, WF eid %(x)s,' 'T type TT, T name TN, T destination_state DS?', {'x': entity.eid}) self.wview('table', rset, 'null', - cellvids={ 1: 'trfromstates', 2: 'outofcontext', 3:'trsecurity',}, - headers = (_('Transition'), _('from_state'), - _('to_state'), _('permissions'), _('type') ), - ) + cellvids={1: 'trfromstates', 2: 'outofcontext', 3: 'trsecurity'}, + headers=(_('Transition'), _('from_state'), + _('to_state'), _('permissions'), _('type'))) class TransitionSecurityTextView(EntityView): @@ -293,9 +293,9 @@ in entity.require_group)))) if entity.condition: self.w(u'
    %s%s %s
    ' % - ( _('conditions'), _(" :"), - u'
    '.join((e.dc_title() for e - in entity.condition)))) + (_('conditions'), _(" :"), + u'
    '.join((e.dc_title() for e in entity.condition)))) + class TransitionAllowedTextView(EntityView): __regid__ = 'trfromstates' @@ -317,11 +317,13 @@ for e in getattr(wf, 'reverse_%s' % wfrelation) if rschema.has_perm(req, 'add', **{param: e.eid})) + # TrInfo _afs.tag_subject_of(('TrInfo', 'to_state', '*'), 'main', 'hidden') _afs.tag_subject_of(('TrInfo', 'from_state', '*'), 'main', 'hidden') _afs.tag_attribute(('TrInfo', 'tr_count'), 'main', 'hidden') + # BaseTransition # XXX * allowed_transition BaseTransition # XXX BaseTransition destination_state * @@ -337,12 +339,14 @@ wfeid = eids[0] return _wf_items_for_relation(form._cw, wfeid, 'state_of', field) + _afs.tag_subject_of(('*', 'destination_state', '*'), 'main', 'attributes') _affk.tag_subject_of(('*', 'destination_state', '*'), {'choices': transition_states_vocabulary}) _afs.tag_object_of(('*', 'allowed_transition', '*'), 'main', 'attributes') _affk.tag_object_of(('*', 'allowed_transition', '*'), - {'choices': transition_states_vocabulary}) + {'choices': transition_states_vocabulary}) + # State @@ -350,13 +354,14 @@ entity = form.edited_entity if entity.has_eid(): wfeid = entity.state_of[0].eid - else : + else: eids = form.linked_to.get(('state_of', 'subject')) if not eids: return [] wfeid = eids[0] return _wf_items_for_relation(form._cw, wfeid, 'transition_of', field) + _afs.tag_subject_of(('State', 'allowed_transition', '*'), 'main', 'attributes') _affk.tag_subject_of(('State', 'allowed_transition', '*'), {'choices': state_transitions_vocabulary}) @@ -366,22 +371,29 @@ class WorkflowIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): __select__ = is_instance('Workflow') + # XXX what if workflow of multiple types? def parent_entity(self): return self.entity.workflow_of and self.entity.workflow_of[0] or None + class WorkflowItemIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): __select__ = is_instance('BaseTransition', 'State') + def parent_entity(self): return self.entity.workflow + class TransitionItemIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): __select__ = is_instance('SubWorkflowExitPoint') + def parent_entity(self): return self.entity.reverse_subworkflow_exit[0] + class TrInfoIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): __select__ = is_instance('TrInfo') + def parent_entity(self): return self.entity.for_entity @@ -422,6 +434,7 @@ for outgoingstate in transition.potential_destinations(): yield transition.eid, outgoingstate.eid, transition + class WorkflowGraphView(DotGraphView): __regid__ = 'wfgraph' __select__ = EntityView.__select__ & one_line_rset() & is_instance('Workflow') diff -r 2fc04786dd36 -r 3fa6c9ef2f51 flake8-ok-files.txt --- a/flake8-ok-files.txt Fri Oct 06 11:45:52 2017 +0200 +++ b/flake8-ok-files.txt Fri Oct 06 14:24:35 2017 +0200 @@ -60,6 +60,7 @@ cubicweb/server/test/unittest_session.py cubicweb/server/test/unittest_rqlannotation.py cubicweb/server/test/unittest_utils.py +cubicweb/schema.py cubicweb/sobjects/notification.py cubicweb/sobjects/services.py cubicweb/sobjects/test/unittest_notification.py @@ -103,14 +104,17 @@ cubicweb/web/test/data/entities.py cubicweb/web/test/unittest_application.py cubicweb/web/test/unittest_http_headers.py +cubicweb/web/test/unittest_uicfg.py cubicweb/web/test/unittest_views_basetemplates.py cubicweb/web/test/unittest_views_cwsources.py cubicweb/web/test/unittest_views_json.py cubicweb/web/views/authentication.py +cubicweb/web/views/cwuser.py cubicweb/web/views/editcontroller.py cubicweb/web/views/json.py cubicweb/web/views/searchrestriction.py cubicweb/web/views/staticcontrollers.py +cubicweb/web/views/workflow.py cubicweb/web/views/uicfg.py cubicweb/xy.py cubicweb/pyramid/auth.py