class CWGroupUsersTable(tableview.RsetTableView): __regid__ = 'cwgroup.users' __select__ = is_instance('CWUser') headers = (_(u'user'), _(u'first name'), _(u'last name'), _(u'creation date'), _(u'last login time')) layout_args = {'display_filter': 'top'} finalvid = 'editable-final'
def call(self): _ = self._cw._ user = self._cw.user self.w(u'<h1>%s</h1>' % self._cw.property_value('ui.site-title')) # email addresses not linked rql = 'Any X WHERE NOT P use_email X' title = u'email addresses not linked to a person' rset = self._cw.execute(rql) if rset: self.w(u'<p><a href="%s">%s %s</a></p>' % (xml_escape( self._cw.build_url(rql=rql, vtitle=title)), len(rset), title)) # email threads not linked to an application rql = 'Any T WHERE T is EmailThread, NOT T topic X' title = u'message threads without topic' rset = self._cw.execute(rql) if rset: self.w(u'<p><a href="%s">%s %s</a></p>' % (xml_escape( self._cw.build_url(rql=rql, vtitle=title)), len(rset), title)) # candidatures en attente rset = self._cw.execute('Any A,P,group_concat(TN),E,B ' 'GROUPBY A,P,E,B,CD ORDERBY CD ' 'WHERE A is Application, A in_state X, ' 'X name "received", ' 'A for_person P, P has_studied_in E?, ' 'P birthday B, T? tags A, T name TN, ' 'A creation_date CD') if rset: self.w(u'<h2>%s</h2>' % _('Juger candidatures')) self.wview('table', rset, 'null') else: self.w(u'<p>%s</p>' % _('aucune candidature en attente'))
class Bookmark(EntityType): """bookmarks are used to have user's specific internal links""" __permissions__ = { 'read': ( 'managers', 'users', 'guests', ), 'add': ( 'managers', 'users', ), 'delete': ( 'managers', 'owners', ), 'update': ( 'managers', 'owners', ), } title = String(required=True, maxsize=128, internationalizable=True) path = String(maxsize=2048, required=True, description=_("relative url of the bookmarked page")) bookmarked_by = SubjectRelation('CWUser', description=_("users using this bookmark"))
def test_swf_magic_tr(self): with self.admin_access.shell() as shell: # sub-workflow subwf = add_wf(shell, 'CWGroup', name='subworkflow') xsigning = subwf.add_state('xsigning', initial=True) xaborted = subwf.add_state('xaborted') xsigned = subwf.add_state('xsigned') xabort = subwf.add_transition('xabort', (xsigning, ), xaborted) xsign = subwf.add_transition('xsign', (xsigning, ), xsigned) # main workflow twf = add_wf(shell, 'CWGroup', name='mainwf', default=True) created = twf.add_state(_('created'), initial=True) identified = twf.add_state(_('identified')) released = twf.add_state(_('released')) twf.add_wftransition(_('identify'), subwf, created, [(xaborted, None), (xsigned, identified)]) twf.add_wftransition(_('release'), subwf, identified, [(xaborted, None)]) shell.commit() with self.admin_access.web_request() as req: group = req.create_entity('CWGroup', name=u'grp1') req.cnx.commit() iworkflowable = group.cw_adapt_to('IWorkflowable') for trans, nextstate in (('identify', 'xsigning'), ('xabort', 'created'), ('identify', 'xsigning'), ('xsign', 'identified'), ('release', 'xsigning'), ('xabort', 'identified')): iworkflowable.fire_transition(trans) req.cnx.commit() group.cw_clear_all_caches() self.assertEqual(iworkflowable.state, nextstate)
class CWUser(WorkflowableEntityType): """define a CubicWeb user""" __permissions__ = { 'read': ('managers', 'users', ERQLExpression('X identity U')), 'add': ('managers', ), 'delete': ('managers', ), 'update': ( 'managers', ERQLExpression('X identity U, NOT U in_group G, G name "guests"'), ), } login = String( required=True, unique=True, maxsize=64, description=_('unique identifier used to connect to the application')) upassword = Password( required=True) # password is a reserved word for mysql firstname = String(maxsize=64) surname = String(maxsize=64) last_login_time = TZDatetime(description=_('last connection date')) in_group = SubjectRelation( 'CWGroup', cardinality='+*', constraints=[RQLConstraint('NOT O name "owners"')], description=_('groups grant permissions to the user'))
def grouped_permissions_table(self, rschema): # group relation definitions with identical permissions perms = {} for rdef in rschema.rdefs.values(): rdef_perms = [] for action in rdef.ACTIONS: groups = sorted(rdef.get_groups(action)) exprs = sorted(e.expression for e in rdef.get_rqlexprs(action)) rdef_perms.append((action, (tuple(groups), tuple(exprs)))) rdef_perms = tuple(rdef_perms) if rdef_perms in perms: perms[rdef_perms].append((rdef.subject, rdef.object)) else: perms[rdef_perms] = [(rdef.subject, rdef.object)] # set layout permissions in a table for each group of relation # definition w = self.w _ = self._cw._ w(u'<div style="margin: 0px 1.5em">') tmpl = u'<strong>%s</strong> %s <strong>%s</strong>' for perm, rdefs in perms.items(): w(u'<div>%s</div>' % u', '.join(tmpl % (_(s.type), _(rschema.type), _(o.type)) for s, o in rdefs)) # accessing rdef from previous loop by design: only used to get # ACTIONS self.permissions_table(rdef, dict(perm)) w(u'</div>')
def permissions_table(self, erschema, permissions=None): self._cw.add_css('cubicweb.acl.css') w = self.w _ = self._cw._ w(u'<table class="%s">' % self.cssclass) w(u'<tr><th>%s</th><th>%s</th><th>%s</th></tr>' % (_("permission"), _('granted to groups'), _('rql expressions'))) for action in erschema.ACTIONS: w(u'<tr><td>%s</td><td>' % _(action)) if permissions is None: groups = erschema.get_groups(action) rqlexprs = sorted(e.expression for e in erschema.get_rqlexprs(action)) else: groups = permissions[action][0] rqlexprs = permissions[action][1] # XXX get group entity and call it's incontext view groups = [ u'<a class="%s" href="%s">%s</a>' % (group, self._cw.build_url('cwgroup/%s' % group), label) for label, group in sorted((_(g), g) for g in groups) ] w(u'<br/>'.join(groups)) w(u'</td><td>') w(u'<br/>'.join(rqlexprs)) w(u'</td></tr>\n') w(u'</table>')
def call(self, txuuid, public=True, redirect_path=None, redirect_params=None): _ = self._cw._ txinfo = self._cw.cnx.transaction_info(txuuid) try: #XXX Under some unknown circumstances txinfo.user_eid=-1 user = self._cw.entity_from_eid(txinfo.user_eid) except UnknownEid: user = None undo_url = self.build_undo_link(txuuid, redirect_path=redirect_path, redirect_params=redirect_params) txinfo_dict = dict(dt=self._cw.format_date(txinfo.datetime, time=True), user_eid=txinfo.user_eid, user=user and user.view('outofcontext') or _("undefined user"), txuuid=txuuid, undo_link=undo_url) self.w(_("By %(user)s on %(dt)s [%(undo_link)s]") % txinfo_dict) tx_actions = txinfo.actions_list(public=public) if tx_actions: self.wview(self.item_vid, None, tx_actions=tx_actions)
class State(EntityType): """used to associate simple states to an entity type and/or to define workflows """ __permissions__ = PUB_SYSTEM_ENTITY_PERMS __unique_together__ = [('name', 'state_of')] name = String(required=True, indexed=True, internationalizable=True, maxsize=256) description = RichString( default_format='text/rest', description=_('semantic description of this state')) # XXX should be on BaseTransition w/ AND/OR selectors when we will # implements #345274 allowed_transition = SubjectRelation( 'BaseTransition', cardinality='**', constraints=[ RQLConstraint( 'S state_of WF, O transition_of WF', msg=_( 'state and transition don\'t belong the the same workflow') ) ], description=_('allowed transitions from this state')) state_of = SubjectRelation( 'Workflow', cardinality='1*', composite='object', inlined=True, description=_('workflow to which this state belongs'))
class SubWorkflowExitPoint(EntityType): """define how we get out from a sub-workflow""" subworkflow_state = SubjectRelation( 'State', cardinality='1*', constraints=[ RQLConstraint( 'T subworkflow_exit S, T subworkflow WF, O state_of WF', msg=_('exit state must be a subworkflow state')) ], description=_('subworkflow state')) destination_state = SubjectRelation( 'State', cardinality='?*', constraints=[ RQLConstraint( 'T subworkflow_exit S, T transition_of WF, O state_of WF', msg= _('destination state must be in the same workflow as our parent transition' )) ], description=_( 'destination state. No destination state means that transition ' 'should go back to the state from which we\'ve entered the ' 'subworkflow.'))
class Workflow(EntityType): __permissions__ = PUB_SYSTEM_ENTITY_PERMS name = String(required=True, indexed=True, internationalizable=True, maxsize=256) description = RichString( default_format='text/rest', description=_('semantic description of this workflow')) workflow_of = SubjectRelation( 'CWEType', cardinality='+*', description=_('entity types which may use this workflow'), constraints=[RQLConstraint('O final FALSE')]) initial_state = SubjectRelation( 'State', cardinality='?*', constraints=[ RQLConstraint('O state_of S', msg=_('state doesn\'t belong to this workflow')) ], description=_('initial state for this workflow'))
class RegistrationForm(forms.FieldsForm): """ Create an anonymous registration form. """ __regid__ = "registration" domid = "registrationForm" title = _("Registration form") form_buttons = [formwidgets.SubmitButton()] @property def action(self): return self._cw.build_url(u"registration_sendmail") # Properly name fields according to validation errors that may be raised by # the register_user service login = formfields.StringField(widget=formwidgets.TextInput(), role="subject", label=_("Login"), help=_("Please enter your CEA login."), required=True) upassword = formfields.StringField(widget=formwidgets.PasswordInput(), role="subject", required=True) captcha = formfields.StringField( widget=captcha.CaptchaWidget(), required=True, label=_("Captcha"), help=_("Please copy the letters from the image"))
def vocabulary(self, form): entity = form.edited_entity _ = form._cw._ if entity.has_eid(): return [(_(entity.pkey), entity.pkey)] choices = entity._cw.vreg.user_property_keys() return [(u'', u'')] + sorted(zip((_(v) for v in choices), choices))
def cell_call(self, row, col): _ = self._cw._ entity = self.cw_rset.get_entity(row, col) self.w(u'<div>') if self.show_eid: self.w(u'%s #%s - ' % (entity.dc_type(), entity.eid)) if entity.modification_date != entity.creation_date: self.w(u'<span>%s</span> ' % _('latest update on')) self.w(u'<span class="value">%s</span>, ' % self._cw.format_date(entity.modification_date)) # entities from external source may not have a creation date (eg ldap) if entity.creation_date: self.w(u'<span>%s</span> ' % _('created on')) self.w(u'<span class="value">%s</span>' % self._cw.format_date(entity.creation_date)) if entity.creator: if entity.creation_date: self.w(u' <span>%s</span> ' % _('by')) else: self.w(u' <span>%s</span> ' % _('created_by')) self.w(u'<span class="value">%s</span>' % entity.creator.name()) source = entity.cw_source[0] if source.name != 'system': self.w(u' (<span>%s</span>' % _('cw_source')) self.w(u' <span class="value">%s</span>)' % source.view('oneline')) source_def = self._cw.source_defs()[source.name] if source_def.get('use-cwuri-as-url'): self.w(u' <a href="%s">%s</span>' % (entity.cwuri, self._cw._('view original'))) self.w(u'</div>')
def cell_call(self, row, col, view=None, title=title): _ = self._cw._ eid = self.cw_rset[row][col] sel = 'Any FS,TS,C,D' rql = ' ORDERBY D DESC WHERE WF wf_info_for X,'\ 'WF from_state FS, WF to_state TS, WF comment C,'\ 'WF creation_date D' if self._cw.vreg.schema.eschema('CWUser').has_perm(self._cw, 'read'): sel += ',U,WF' rql += ', WF owned_by U?' headers = (_('from_state'), _('to_state'), _('comment'), _('date'), _('CWUser')) else: sel += ',WF' headers = (_('from_state'), _('to_state'), _('comment'), _('date')) sel += ',FSN,TSN,CF' rql = '%s %s, FS name FSN, TS name TSN, WF comment_format CF, X eid %%(x)s' % ( sel, rql) try: rset = self._cw.execute(rql, {'x': eid}) except Unauthorized: return if rset: if title: self.w(u'<h2>%s</h2>\n' % _(title)) self.wview('table', rset, headers=headers, cellvids={2: 'editable-final'})
class CWEType(EntityType): """define an entity type, used to build the instance schema""" __permissions__ = PUB_SYSTEM_ENTITY_PERMS name = String(required=True, indexed=True, internationalizable=True, unique=True, maxsize=64) description = RichString(internationalizable=True, description=_('semantic description of this entity type')) # necessary to filter using RQL final = Boolean(default=False, description=_('automatic'))
def __call__(self): entity = self.entity if self.event == 'before_delete_entity' and entity.name == 'owners': raise validation_error(entity, {None: _("can't be deleted")}) elif self.event == 'before_update_entity' \ and 'name' in entity.cw_edited: oldname, newname = entity.cw_edited.oldnewvalue('name') if oldname == 'owners' and newname != oldname: raise validation_error( entity, {('name', 'subject'): _("can't be changed")})
def render_body(self, w): _ = self._cw._ entity = self.entity accounts = [act.view('oneline') for act in entity.paid_by_accounts()] self.field(_('account to refund'), ','.join(accounts), w) self.field(_('total'), entity.total, w) rset = self._cw.execute( 'Any E,ET,EC,EA WHERE X has_lines E, X eid %(x)s, ' 'E title ET, E currency EC, E amount EA', {'x': entity.eid}) self._cw.view('table', rset, w=w)
class CWETypePrimaryView(tabs.TabbedPrimaryView): __select__ = is_instance('CWEType') tabs = [ _('cwetype-description'), _('cwetype-box'), _('cwetype-workflow'), _('cwetype-views'), _('cwetype-permissions') ] default_tab = 'cwetype-description'
class SiteInfoView(tabs.TabsMixin, StartupView): __regid__ = 'siteinfo' title = _('Site information') tabs = [_('info'), _('registry'), _('gc')] default_tab = 'info' def call(self, **kwargs): """The default view representing the instance's management""" self.w(u'<h1>%s</h1>' % self._cw._(self.title)) self.render_tabs(self.tabs, self.default_tab)
def cell_call(self, row, col): _ = self._cw._ entity = self.cw_rset.get_entity(self.cw_row, self.cw_col) if entity.require_group: self.w(u'<div>%s%s %s</div>' % (_('groups'), _(" :"), u', '.join( (g.view('incontext') for g in entity.require_group)))) if entity.condition: self.w(u'<div>%s%s %s</div>' % (_('conditions'), _(" :"), u'<br/>'.join( (e.dc_title() for e in entity.condition))))
def render_entity_attributes(self, entity): _ = self._cw._ self.w(u'<div>%s</div>' % (entity.printable_value('description'))) self.w(u'<span>%s%s</span>' % (_("workflow_of").capitalize(), _(" :"))) html = [] for e in entity.workflow_of: view = e.view('outofcontext') if entity.eid == e.default_workflow[0].eid: view += u' <span>[%s]</span>' % _('default_workflow') html.append(view) self.w(', '.join(v for v in html)) self.w(u'<h2>%s</h2>' % _("Transition_plural")) rset = self._cw.execute( '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')))
class CWAttribute(EntityType): """define a final relation: link a final relation type from a non final entity to a final entity type. used to build the instance schema """ __permissions__ = PUB_SYSTEM_ENTITY_PERMS relation_type = SubjectRelation('CWRType', cardinality='1*', constraints=[RQLConstraint('O final TRUE')], composite='object') from_entity = SubjectRelation('CWEType', cardinality='1*', constraints=[RQLConstraint('O final FALSE')], composite='object') to_entity = SubjectRelation('CWEType', cardinality='1*', constraints=[RQLConstraint('O final TRUE')], composite='object') constrained_by = SubjectRelation('CWConstraint', cardinality='*1', composite='subject') cardinality = String(maxsize=2, internationalizable=True, vocabulary=[_('?1'), _('11')], description=_('subject/object cardinality')) ordernum = Int(description=('control subject entity\'s relations order'), default=0) formula = String(maxsize=2048) indexed = Boolean(description=_('create an index for quick search on this attribute')) fulltextindexed = Boolean(description=_('index this attribute\'s value in the plain text index')) internationalizable = Boolean(description=_('is this attribute\'s value translatable')) defaultval = Bytes(description=_('default value as gziped pickled python object')) extra_props = Bytes(description=_('additional type specific properties')) description = RichString(internationalizable=True, description=_('semantic description of this attribute'))
class UsersAndGroupsManagementView(tabs.TabsMixin, StartupView): __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')] default_tab = 'cw.users-management' def call(self, **kwargs): """The default view representing the instance's management""" self.w(u'<h1>%s</h1>' % self._cw._(self.title)) self.render_tabs(self.tabs, self.default_tab)
def cell_call(self, row, col): entity = self.cw_rset.get_entity(row, col) _ = self._cw._ self.w('<div>%s</div>' % _('Non exhaustive list of views that may ' 'apply to entities of this type')) views = [(view.content_type, view.__regid__, _(view.title)) for view in self.possible_views(entity.name)] self.wview('pyvaltable', pyvalue=sorted(views), headers=(_(u'content type'), _(u'view identifier'), _(u'view title')))
def state_header(self): state = self._cw.search_state if state[0] == 'normal': return _ = self._cw._ value = self._cw.view('oneline', self._cw.eid_rset(state[1][1])) msg = ' '.join( (_("searching for"), display_name(self._cw, state[1][3]), _("to associate with"), value, _("by relation"), '"', display_name(self._cw, state[1][2], state[1][0]), '"')) return self.w(u'<div class="stateMessage">%s</div>' % msg)
class NonPeriodicTimeSeries(_AbstractTimeSeries): """Non Periodic Time Series""" granularity = String(override=True, internationalizable=True, vocabulary=[_('time_vector')], default='time_vector') timestamps = Bytes( required=False, description= _('the array of timestamps. Mandatory but read from the same source as data' ))
class StatusChangeMixIn(object): __regid__ = 'notif_status_change' msgid_timestamp = True message = _('status changed') content = _(""" %(user)s changed status from <%(previous_state)s> to <%(current_state)s> for entity '%(title)s' %(comment)s url: %(url)s """)
class CWDataImport(EntityType): __permissions__ = ENTITY_MANAGERS_PERMISSIONS start_timestamp = TZDatetime() end_timestamp = TZDatetime() log = String() status = String(required=True, internationalizable=True, indexed=True, default='in progress', vocabulary=[_('in progress'), _('success'), _('failed')])
class CWSearch(EntityType): """ An entity used to save a search which may contains resources on the server file system. Attributes ---------- title: String (mandatory) a short description of the file. path: String (mandatory) the rql request that will be saved. expiration_data: Date (mandatory) the expiration date of the current search. result: SubjectRelation (mandatory) a json file with all the server resources associated with the current search - {"rql": rql, "files": [], "nonexistent-files": []} rset: SubjectRelation (mandatory) the result set associated with the current search. rset_type: String (optional, default 'jsonexport') the type of the rset. """ __permissions__ = { "read": ( "managers", ERQLExpression("X owned_by U"), ), "add": ("managers", "users"), "delete": ("managers", "owners"), "update": ("managers", "owners"), } title = String(maxsize=256, required=True, constraints=[ RQLUniqueConstraint( "X title N, S title N, X owned_by U, X is CWSearch", mainvars="X", msg=_("this name is already used")) ], description=_("Please set a unique subset name.")) path = String(required=True, description=_("the rql request we will save (do not edit " "this field).")) expiration_date = Date(required=True, indexed=True) # json which contains resultset and filepath result = SubjectRelation("File", cardinality="1*", inlined=True, composite="subject") rset = SubjectRelation("File", cardinality="1*", inlined=True, composite="subject") # view regid to show rset rset_type = String(required=True, default="jsonexport", maxsize=50)
def call(self): """ Change the login button in the header. """ self._cw.add_css("cubicweb.pictograms.css") self._html = u""" <a type='button' class='btn btn-default btn-sm' title="%s" data-toggle="modal" href="#loginModal">%s</a>""" title = u"<span class='glyphicon icon-login'>%s</span>" % _("Login") self.w(self._html % (_("login / password"), title)) self._cw.view("logform", rset=self.cw_rset, id=self.loginboxid, klass="%s hidden" % self.loginboxid, title=False, showmessage=False, w=self.w, showonload=False)
def page_title(self): """ Returns a title according to the result set - used for the title in the HTML header. """ rset = self.cw_rset regex = "Any [a-zA-Z] Where [a-zA-Z] is [a-zA-Z]{1,20}" rql = "" if rset is not None: rql = rset.rql if rset is not None and rset.rowcount and rset.rowcount == 1: try: entity = rset.complete_entity(0, 0) title = entity.cw_etype except: title = _("NotAnEntity") elif hasattr(self, "title"): title = self.title elif len(re.findall(regex, rql)) == 1: title = rql.split()[-1] else: title = _("NoMatch") return title
def render(self, w): w(u"<a href='{0}' type='button' class='btn btn-default " "btn-sm'>".format(self._cw.build_url( "view", vid="shiirdor.users-groups-import"))) w(u"<span class='glyphicon glyphicon-import'>{0}</span>" "</a>".format(_(" Import users&groups")))
def render(self, w): w(u"<a href='{0}' type='button' class='btn btn-default " "btn-sm'>".format(self._cw.build_url("logout"))) w(u"<span class='glyphicon glyphicon-log-out'>{0}</span>" "</a>".format(_(" Logout")))
def render(self, w): self._cw.add_css("cubicweb.pictograms.css") w(u"<a href='{0}' type='button' class='btn btn-default " "btn-sm'>".format(self._cw.build_url("register"))) w(u"<span class='glyphicon icon-user-add'>{0}</span>" "</a>".format(_("Register")))
def render(self, w): w(u"<a href='{0}' type='button' class='btn btn-default " "btn-sm'>".format( self._cw.build_url("view", vid="schiirdor.sync-management"))) w(u"<span class='glyphicon glyphicon-transfer'>{0}</span>" "</a>".format(_(" Sync")))
def render(self, w): w(u"<a href='{0}' type='button' class='btn btn-default " "btn-sm'>".format(self._cw.build_url( "view", vid="shiirdor.groups-management"))) w(u"<span class='glyphicon glyphicon-lock'>{0}</span>" "</a>".format(_(" Create groups")))