class CWPropertiesForm(SystemCWPropertiesForm): """user's preferences properties edition form""" __regid__ = 'propertiesform' __select__ = ((none_rset() & match_user_groups('users', 'managers')) | (one_line_rset() & match_user_groups('users') & logged_user_in_rset()) | (one_line_rset() & match_user_groups('managers') & is_instance('CWUser'))) title = _('user preferences') @property def user(self): if self.cw_rset is None: return self._cw.user return self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) @property @cached def cwprops_rset(self): return self._cw.execute( 'Any P,K,V WHERE P is CWProperty, P pkey K, P value V,' 'P for_user U, U eid %(x)s', {'x': self.user.eid}) def form_row(self, form, key, splitlabel): subform = super(CWPropertiesForm, self).form_row(form, key, splitlabel) # if user is in the managers group and the property is being created, # we have to set for_user explicitly if not subform.edited_entity.has_eid() and self.user.matching_groups( 'managers'): subform.add_hidden('for_user', self.user.eid, eidparam=True, role='subject') return subform
class PDFExportView(EntityView): __regid__ = 'pdfexport' __select__ = has_reportlab & one_line_rset() & is_instance( 'Refund', 'Expense') title = _('pdf export') content_type = 'application/pdf' templatable = False binary = True def cell_call(self, row, col): # import error to avoid import error if reportlab isn't available _ = self._cw._ writer = PDFWriter(self._cw.vreg.config) entity = self.cw_rset.get_entity(row, col) entity.complete() # XXX reportlab needs HOME and getcwd to find fonts home_backup = os.environ.get('HOME') getcwd_backup = os.getcwd try: os.environ['HOME'] = 'wtf' os.getcwd = lambda: 'wtf' # NOTE: we could use self.w.__self__ directly stream = BytesIO() writer.write(entity, stream) self.w(stream.getvalue()) finally: if home_backup: os.environ['HOME'] = home_backup os.getcwd = getcwd_backup
class LinkToEntityAction(Action): """base class for actions consisting to create a new object with an initial relation set to an entity. Additionally to EntityAction behaviour, this class is parametrized using .rtype, .role and .target_etype attributes to check if the action apply and if the logged user has access to it (see :class:`~cubicweb.selectors.partial_relation_possible` selector documentation for more information). """ __select__ = (match_search_state('normal') & one_line_rset() & partial_relation_possible(action='add', strict=True)) submenu = 'addrelated' # to be defined in concrete classes target_etype = rtype = None def url(self): ttype = self.target_etype entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) linkto = '%s:%s:%s' % (self.rtype, entity.eid, target(self)) return self._cw.vreg["etypes"].etype_class(ttype).cw_create_url( self._cw, __redirectpath=entity.rest_path(), __linkto=linkto, __redirectvid=self._cw.form.get('__redirectvid', ''))
class WorkflowActions(action.Action): """fill 'workflow' sub-menu of the actions box""" __regid__ = 'workflow' __select__ = (action.Action.__select__ & one_line_rset() & relation_possible('in_state')) submenu = _('workflow') order = 10 def fill_menu(self, box, menu): entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) menu.label = u'%s: %s' % (self._cw._( 'state'), entity.cw_adapt_to('IWorkflowable').printable_state) menu.append_anyway = True super(WorkflowActions, self).fill_menu(box, menu) def actual_actions(self): entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) iworkflowable = entity.cw_adapt_to('IWorkflowable') hastr = False for tr in iworkflowable.possible_transitions(): url = entity.absolute_url(vid='statuschange', treid=tr.eid) yield self.build_action(self._cw._(tr.name), url) hastr = True # don't propose to see wf if user can't pass any transition if hastr: wfurl = iworkflowable.current_workflow.absolute_url() yield self.build_action(self._cw._('view workflow'), wfurl) if iworkflowable.workflow_history: wfurl = entity.absolute_url(vid='wfhistory') yield self.build_action(self._cw._('view history'), wfurl)
class WorkflowTabTextView(PrimaryTab): __regid__ = 'wf_tab_info' __select__ = PrimaryTab.__select__ & one_line_rset() & is_instance( 'Workflow') 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 TabPersonneArtisan(tabs.EntityRelationView): __regid__ = 'tab_personne_artisan' __select__ = one_line_rset( ) & tabs.EntityRelationView.__select__ & is_instance('Personne') title = None rtype = 'artisan' role = 'object' def cell_call(self, row, col): entity = self.cw_rset.get_entity(row, col) subst = {'eid': entity.eid} rql = 'Any T, D, PRIX, PRIXTRANS, T, T ORDERBY CI, T WHERE T travaux D, T prix_ensemble PRIXTRANS?, D salaire_argent PRIX?, D artisan P, P eid %(eid)s, T compte C, C inventaire CI' rset = self._cw.execute(rql, subst) self.wview('table', rset, 'null', title=_('Artisan pour'), headers=(u'Transaction', u'Intervention', u'Prix (travail)', u'Prix (transaction)', u'Achats', u'Destinataires'), cellvids={ 0: 'outofcontext', 1: 'incontext', 4: 'transaction_achats', 5: 'transaction_destinataires' })
class MergeComponent(component.EntityCtxComponent): __regid__ = 'mergepersonne' __select__ = (one_line_rset() & component.EntityCtxComponent.__select__ & is_instance('Personne')) context = 'navcontentbottom' title = _('merge personnes') def render_body(self, w): self._cw.add_js(( 'cubes.myosotis.merge.js', 'cubicweb.widgets.js', #'jquery.autocomplete.js', 'jquery.js', )) self._cw.add_onload('initMergePersonnes();') #self._cw.add_css('jquery.autocomplete.css') entity = self.entity w(u'<div id="personnemergeformholder%s">' % entity.eid) w(u'<h5>%s</h5>' % self._cw._('Identity of the Personne to merge')) w(u'<input type="hidden" id="personneeid" value="%s"/>' % entity.eid) w(u'<input id="acmergepersonne" type="text" class="widget" cubicweb:dataurl="%s" ' u'cubicweb:loadtype="auto" cubicweb:wdgtype="LazySuggestField" name="selected-personne"/>' % xml_escape( self._cw.build_url( 'json', fname='unrelated_merge_personnes', arg=entity.eid))) w(u'<div id="personne_entities_holder"></div>') w(u'<div id="sgformbuttons" class="hidden">') w(u'<input class="validateButton" type="button" value="%s" onclick="javascript:mergePersonnes(%s);"/>' % (self._cw._('merge (keeping %s)') % xml_escape(entity.dc_title()), entity.eid)) w(u'<input class="validateButton" type="button" value="%s" onclick="javascript:cancelSelectedMergePersonne(%s)"/>' % (self._cw._(stdmsgs.BUTTON_CANCEL[0]), entity.eid)) w(u'</div>') w(u'</div>')
class TabPersonneIntervention(tabs.EntityRelationView): __regid__ = 'tab_personne_intervention' __select__ = one_line_rset( ) & tabs.EntityRelationView.__select__ & is_instance('Personne') rtype = 'intervenant' role = 'object' title = None def cell_call(self, row, col): entity = self.cw_rset.get_entity(row, col) subst = {'eid': entity.eid} rql = ( 'Any T, I, T ORDERBY CI, T WHERE T intervenants I, I intervenant X, X eid %(eid)s, T compte C, C inventaire CI' ) rset = self._cw.execute(rql, subst) self.wview( 'table', rset, 'null', headers=('Transaction', 'Interventions', 'Vendeurs'), cellvids={ 0: 'outofcontext', 1: 'intervenant_flags', 2: 'transaction_vendeurs' }, title=_('Intervient sur'), )
class RSSEntityFeedURL(Component): __regid__ = 'rss_feed_url' __select__ = one_line_rset() & adaptable('IFeed') def feed_url(self): entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) return entity.cw_adapt_to('IFeed').rss_feed_url()
class TravailBreadCrumbAdapter(IBreadCrumbsAdapter): __select__ = one_line_rset() & is_instance( 'Travail') & has_related_entities('travaux', 'object') def parent_entity(self): if self.entity.reverse_travaux: return self.entity.reverse_travaux[0]
class OccupationBreadCrumbAdapter(IBreadCrumbsAdapter): __select__ = one_line_rset() & is_instance( 'Occupation') & has_related_entities('personne') def parent_entity(self): if self.entity.personne: return self.entity.personne[0]
class SearchForAssociationView(EntityView): """view called by the edition view when the user asks to search for something to link to the edited eid """ __regid__ = 'search-associate' __select__ = (one_line_rset() & match_search_state('linksearch') & non_final_entity()) title = _('search for association') def cell_call(self, row, col): rset, vid, divid, paginate = self.filter_box_context_info() self.cw_rset = rset self.w(u'<div id="%s">' % divid) self.paginate() self.wview(vid, rset, 'noresult') self.w(u'</div>') @cached def filter_box_context_info(self): entity = self.cw_rset.get_entity(0, 0) role, eid, rtype, etype = self._cw.search_state[1] assert entity.eid == int(eid) # the default behaviour is to fetch all unrelated entities and display # them. Use fetch_order and not fetch_unrelated_order as sort method # since the latter is mainly there to select relevant items in the combo # box, it doesn't give interesting result in this context rql, args = entity.cw_unrelated_rql(rtype, etype, role, ordermethod='fetch_order', vocabconstraints=False) rset = self._cw.execute(rql, args) return rset, 'list', "search-associate-content", True
class EntityBoxTemplate(BoxTemplate): """base class for boxes related to a single entity""" __select__ = BoxTemplate.__select__ & one_line_rset() context = 'incontext' def call(self, row=0, col=0, **kwargs): """classes inheriting from EntityBoxTemplate should define cell_call""" self.cell_call(row, col, **kwargs)
class ExcelTSExportAction(action.Action): __regid__ = 'tsexportaction' title = _('export to excel') __select__ = one_line_rset() & is_instance('TimeSeries', 'NonPeriodicTimeSeries') def url(self): return self.cw_rset.get_entity(0, 0).absolute_url(vid='tsxlexport')
class CompanyTree(EntityView): __regid__ = 'companytree' __select__ = one_line_rset() & is_instance('Company') def cell_call(self, row, col): entity = self.cw_rset.get_entity(row, col) root_company = entity.cw_adapt_to('ITree').root() self.wview('treeview', root_company.as_rset(), subvid='oneline-selectable', onscreen=entity.eid)
class FollowAction(action.Action): __regid__ = 'follow' __select__ = one_line_rset() & is_instance('Bookmark') title = _('follow') category = 'mainactions' def url(self): return self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0).actual_url()
class WorkflowGraphView(DotGraphView): __regid__ = 'wfgraph' __select__ = EntityView.__select__ & one_line_rset() & is_instance( 'Workflow') def build_visitor(self, entity): return WorkflowVisitor(entity) def build_dotpropshandler(self): return WorkflowDotPropsHandler(self._cw)
class UserPreferencesEntityAction(action.Action): __regid__ = 'prefs' __select__ = (one_line_rset() & is_instance('CWUser') & match_user_groups('owners', 'managers')) title = _('preferences') category = 'mainactions' def url(self): user = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) return user.absolute_url(vid='propertiesform')
class PDFAction(action.Action): __regid__ = 'pdfaction' __select__ = has_reportlab & one_line_rset() & is_instance( 'Expense', 'Refund') title = _('generate pdf document') category = 'mainactions' def url(self): return self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0).absolute_url(vid='pdfexport')
class CopyAction(action.Action): __regid__ = 'copy' __select__ = (action.Action.__select__ & one_line_rset() & has_permission('add')) title = _('copy') category = 'moreactions' order = 30 def url(self): entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) return entity.absolute_url(vid='copy')
class ManagePermissionsAction(action.Action): __regid__ = 'managepermission' __select__ = (action.Action.__select__ & one_line_rset() & non_final_entity() & match_user_groups('managers')) title = _('manage permissions') category = 'moreactions' order = 15 def url(self): return self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0).absolute_url(vid='security')
class ModifyAction(action.Action): __regid__ = 'edit' __select__ = (action.Action.__select__ & one_line_rset() & has_editable_relation()) title = _('modify') category = 'mainactions' order = 10 def url(self): entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) return entity.absolute_url(vid='edition')
class CWSourceSyncAction(action.Action): __regid__ = 'cw.source-sync' __select__ = (action.Action.__select__ & match_user_groups('managers') & one_line_rset() & is_instance('CWSource') & score_entity(lambda x: x.name != 'system')) title = _('synchronize') category = 'mainactions' order = 20 def url(self): entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) return entity.absolute_url(vid=self.__regid__)
class EntityCtxComponent(CtxComponent): """base class for boxes related to a single entity""" __select__ = CtxComponent.__select__ & non_final_entity() & one_line_rset() context = 'incontext' contextual = True def __init__(self, *args, **kwargs): super(EntityCtxComponent, self).__init__(*args, **kwargs) try: entity = kwargs['entity'] except KeyError: entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) self.entity = entity def layout_select_args(self): args = super(EntityCtxComponent, self).layout_select_args() args['entity'] = self.entity return args @property def domid(self): return domid(self.__regid__) + str(self.entity.eid) def lazy_view_holder(self, w, entity, oid, registry='views'): """add a holder and return a URL that may be used to replace this holder by the html generate by the view specified by registry and identifier. Registry defaults to 'views'. """ holderid = '%sHolder' % self.domid w(u'<div id="%s"></div>' % holderid) params = self.cw_extra_kwargs.copy() params.pop('view', None) params.pop('entity', None) form = params.pop('formparams', {}) if entity.has_eid(): eid = entity.eid else: eid = None form['etype'] = entity.cw_etype form['tempEid'] = entity.eid args = [json_dumps(x) for x in (registry, oid, eid, params)] return self._cw.ajax_replace_url(holderid, fname='render', arg=args, **form)
class CWSourceSyncView(EntityView): __regid__ = 'cw.source-sync' __select__ = (match_user_groups('managers') & one_line_rset() & is_instance('CWSource') & score_entity(lambda x: x.name != 'system')) title = _('synchronize') def entity_call(self, entity): import_log_eid = self._cw.call_service('source-sync', source_eid=entity.eid) msg = self._cw._( 'Synchronization has been requested, refresh this page in a few ' 'minutes.') import_log = self._cw.entity_from_eid(import_log_eid) url = import_log.absolute_url(__message=msg) raise Redirect(url)
class ChangeStateFormView(form.FormViewMixIn, EntityView): __regid__ = 'statuschange' title = _('status change') __select__ = (one_line_rset() & match_form_params('treid') & adaptable('IWorkflowable')) def cell_call(self, row, col): entity = self.cw_rset.get_entity(row, col) transition = self._cw.entity_from_eid(self._cw.form['treid']) form = self.get_form(entity, transition) self.w(u'<h4>%s %s</h4>\n' % (self._cw._(transition.name), entity.view('oneline'))) msg = self._cw._('status will change from %(st1)s to %(st2)s') % { 'st1': entity.cw_adapt_to('IWorkflowable').printable_state, 'st2': self._cw._(transition.destination(entity).name) } self.w(u'<p>%s</p>\n' % msg) form.render(w=self.w) def redirectpath(self, entity): return entity.rest_path() def get_form(self, entity, transition, **kwargs): # XXX used to specify both rset/row/col and entity in case implements # selector (and not is_instance) is used on custom form form = self._cw.vreg['forms'].select( 'changestate', self._cw, entity=entity, transition=transition, redirect_path=self.redirectpath(entity), **kwargs) trinfo = self._cw.vreg['etypes'].etype_class('TrInfo')(self._cw) trinfo.eid = next(self._cw.varmaker) subform = self._cw.vreg['forms'].select('edition', self._cw, entity=trinfo, mainform=False) subform.field_by_name('wf_info_for', 'subject').value = entity.eid trfield = subform.field_by_name('by_transition', 'subject') trfield.widget = fwdgs.HiddenInput() trfield.value = transition.eid form.add_subform(subform) return form
class TabPersonneRattachement(tabs.EntityRelationView): __regid__ = 'tab_personne_rattachement' __select__ = one_line_rset( ) & tabs.EntityRelationView.__select__ & is_instance('Personne') title = None rtype = 'rattache_a' role = 'object' def cell_call(self, row, col): entity = self.cw_rset.get_entity(row, col) subst = {'eid': entity.eid} rql = 'Any O, P ORDERBY N WHERE O personne P, O rattache_a X, X eid %(eid)s, P identite N' rset = self._cw.execute(rql, subst) self.wview( 'table', rset, 'null', title=_('Rattachements'), )
class EntityVComponent(Component, metaclass=class_deprecated): """abstract base class for additinal components displayed in content headers and footer according to: * the displayed entity's type * a context (currently 'header' or 'footer') it should be configured using .accepts, .etype, .rtype, .target and .context class attributes """ __deprecation_warning__ = '[3.10] *VComponent classes are deprecated, use *CtxComponent instead (%(cls)s)' __registry__ = 'ctxcomponents' __select__ = one_line_rset() cw_property_defs = { _('visible'): dict(type='Boolean', default=True, help=_('display the component or not')), _('order'): dict(type='Int', default=99, help=_('display order of the component')), _('context'): dict(type='String', default='navtop', vocabulary=(_('navtop'), _('navbottom'), _('navcontenttop'), _('navcontentbottom'), _('ctxtoolbar')), help=_('context where this component should be displayed')), } context = 'navcontentbottom' def call(self, view=None): if self.cw_rset is None: self.entity_call(self.cw_extra_kwargs.pop('entity')) else: self.cell_call(0, 0, view=view) def cell_call(self, row, col, view=None): self.entity_call(self.cw_rset.get_entity(row, col), view=view) def entity_call(self, entity, view=None): raise NotImplementedError()
class ViewSameCWEType(action.Action): """when displaying the schema of a CWEType, offer to list entities of that type """ __regid__ = 'entitiesoftype' __select__ = one_line_rset() & is_instance('CWEType') & score_entity( lambda x: not x.final) category = 'mainactions' order = 40 @property def etype(self): return self.cw_rset.get_entity(0, 0).name @property def title(self): return self._cw.__('view all %s') % display_name( self._cw, self.etype, 'plural').lower() def url(self): return self._cw.build_url(self.etype)
class DownloadView(EntityView): """download view this view is replacing the deprecated 'download' controller and allow downloading of entities providing the necessary interface """ __regid__ = 'download' __select__ = one_line_rset() & adaptable('IDownloadable') templatable = False content_type = 'application/octet-stream' binary = True http_cache_manager = httpcache.EntityHTTPCacheManager add_to_breadcrumbs = False def set_request_content_type(self): """overriden to set the correct filetype and filename""" entity = self.cw_rset.complete_entity(self.cw_row or 0, self.cw_col or 0) adapter = entity.cw_adapt_to('IDownloadable') encoding = adapter.download_encoding() if encoding in BINARY_ENCODINGS: contenttype = 'application/%s' % encoding encoding = None else: contenttype = adapter.download_content_type() self._cw.set_content_type(contenttype or self.content_type, filename=adapter.download_file_name(), encoding=encoding, disposition='attachment') def call(self): entity = self.cw_rset.complete_entity(self.cw_row or 0, self.cw_col or 0) adapter = entity.cw_adapt_to('IDownloadable') self.w(adapter.download_data()) def last_modified(self): return self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0).modification_date