Esempio n. 1
0
class IEmailableAdapter(view.EntityAdapter):
    __regid__ = 'IEmailable'
    __select__ = relation_possible('primary_email') | relation_possible(
        'use_email')

    def get_email(self):
        if getattr(self.entity, 'primary_email', None):
            return self.entity.primary_email[0].address
        if getattr(self.entity, 'use_email', None):
            return self.entity.use_email[0].address
        return None

    def allowed_massmail_keys(self):
        """returns a set of allowed email substitution keys

        The default is to return the entity's attribute list but you might
        override this method to allow extra keys.  For instance, a Person
        class might want to return a `companyname` key.
        """
        return set(rschema.type for rschema, attrtype in
                   self.entity.e_schema.attribute_definitions()
                   if attrtype.type not in ('Password', 'Bytes'))

    def as_email_context(self):
        """returns the dictionary as used by the sendmail controller to
        build email bodies.

        NOTE: the dictionary keys should match the list returned by the
        `allowed_massmail_keys` method.
        """
        return dict((attr, getattr(self.entity, attr))
                    for attr in self.allowed_massmail_keys())
Esempio n. 2
0
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)
Esempio n. 3
0
 def test_rqlst_1(self):
     with self.admin_access.web_request() as req:
         selector = relation_possible('in_group')
         select = self.vreg.parse(req, 'Any X WHERE X is CWUser').children[0]
         score = selector(None, req, rset=1,
                          select=select, filtered_variable=select.defined_vars['X'])
         self.assertEqual(score, 1)
Esempio n. 4
0
class HasTextFacet(facetbase.AbstractFacet):
    __select__ = relation_possible('has_text',
                                   'subject') & match_context_prop()
    __regid__ = 'has_text-facet'
    rtype = 'has_text'
    role = 'subject'
    order = 0

    @property
    def wdgclass(self):
        return facetbase.FacetStringWidget

    @property
    def title(self):
        return self._cw._('has_text')

    def get_widget(self):
        """return the widget instance to use to display this facet

        default implentation expects a .vocabulary method on the facet and
        return a combobox displaying this vocabulary
        """
        return self.wdgclass(self)

    def add_rql_restrictions(self):
        """add restriction for this facet into the rql syntax tree"""
        value = self._cw.form.get(self.__regid__)
        if not value:
            return
        self.select.add_constant_restriction(self.filtered_variable,
                                             'has_text', value, 'String')
Esempio n. 5
0
 def test_rqlst_2(self):
     with self.admin_access.web_request() as req:
         selector = relation_possible('in_group')
         select = self.vreg.parse(req, 'Any 1, COUNT(X) WHERE X is CWUser, X creation_date XD, '
                                  'Y creation_date YD, Y is CWGroup '
                                  'HAVING DAY(XD)=DAY(YD)').children[0]
         score = selector(None, req, rset=1,
                          select=select, filtered_variable=select.defined_vars['X'])
         self.assertEqual(score, 1)
Esempio n. 6
0
 def test_ambiguous(self):
     # Ambiguous relations are :
     # (Service, fabrique_par, Personne) and (Produit, fabrique_par, Usine)
     # There used to be a crash here with a bad rdef choice in the strict
     # checking case.
     selector = relation_possible('fabrique_par', role='object',
                                  target_etype='Personne', strict=True)
     with self.admin_access.web_request() as req:
         usine = req.create_entity('Usine', lieu=u'here')
         score = selector(None, req, rset=usine.as_rset())
         self.assertEqual(0, score)
Esempio n. 7
0
class WFHistoryView(EntityView):
    __regid__ = 'wfhistory'
    __select__ = (relation_possible('wf_info_for', role='object')
                  & score_entity(lambda x: x.cw_adapt_to('IWorkflowable').
                                 workflow_history))

    title = _('Workflow history')

    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'})
Esempio n. 8
0
class IWorkflowableAdapter(EntityAdapter):
    """base adapter providing workflow helper methods for workflowable entities.
    """
    __regid__ = 'IWorkflowable'
    __select__ = relation_possible('in_state')

    @cached
    def cwetype_workflow(self):
        """return the default workflow for entities of this type"""
        # XXX CWEType method
        wfrset = self._cw.execute(
            'Any WF WHERE ET default_workflow WF, '
            'ET name %(et)s', {'et': self.entity.cw_etype})
        if wfrset:
            return wfrset.get_entity(0, 0)
        self.warning("can't find any workflow for %s", self.entity.cw_etype)
        return None

    @property
    def main_workflow(self):
        """return current workflow applied to this entity"""
        if self.entity.custom_workflow:
            return self.entity.custom_workflow[0]
        return self.cwetype_workflow()

    @property
    def current_workflow(self):
        """return current workflow applied to this entity"""
        return self.current_state and self.current_state.workflow or self.main_workflow

    @property
    def current_state(self):
        """return current state entity"""
        return self.entity.in_state and self.entity.in_state[0] or None

    @property
    def state(self):
        """return current state name"""
        try:
            return self.current_state.name
        except AttributeError:
            self.warning('entity %s has no state', self.entity)
            return None

    @property
    def printable_state(self):
        """return current state name translated to context's language"""
        state = self.current_state
        if state:
            return self._cw._(state.name)
        return u''

    @property
    def workflow_history(self):
        """return the workflow history for this entity (eg ordered list of
        TrInfo entities)
        """
        return self.entity.reverse_wf_info_for

    def latest_trinfo(self):
        """return the latest transition information for this entity"""
        try:
            return self.workflow_history[-1]
        except IndexError:
            return None

    def possible_transitions(self, type='normal'):
        """generates transition that MAY be fired for the given entity,
        expected to be in this state
        used only by the UI
        """
        if self.current_state is None or self.current_workflow is None:
            return
        rset = self._cw.execute(
            'Any T,TT, TN WHERE S allowed_transition T, S eid %(x)s, '
            'T type TT, T type %(type)s, '
            'T name TN, T transition_of WF, WF eid %(wfeid)s', {
                'x': self.current_state.eid,
                'type': type,
                'wfeid': self.current_workflow.eid
            })
        for tr in rset.entities():
            if tr.may_be_fired(self.entity.eid):
                yield tr

    def subworkflow_input_trinfo(self):
        """return the TrInfo which has be recorded when this entity went into
        the current sub-workflow
        """
        if self.main_workflow.eid == self.current_workflow.eid:
            return  # doesn't make sense
        subwfentries = []
        for trinfo in self.workflow_history:
            if (trinfo.transition and trinfo.previous_state.workflow.eid !=
                    trinfo.new_state.workflow.eid):
                # entering or leaving a subworkflow
                if (subwfentries and subwfentries[-1].new_state.workflow.eid
                        == trinfo.previous_state.workflow.eid
                        and subwfentries[-1].previous_state.workflow.eid
                        == trinfo.new_state.workflow.eid):
                    # leave
                    del subwfentries[-1]
                else:
                    # enter
                    subwfentries.append(trinfo)
        if not subwfentries:
            return None
        return subwfentries[-1]

    def subworkflow_input_transition(self):
        """return the transition which has went through the current sub-workflow
        """
        return getattr(self.subworkflow_input_trinfo(), 'transition', None)

    def _add_trinfo(self, comment, commentformat, treid=None, tseid=None):
        kwargs = {}
        if comment is not None:
            kwargs['comment'] = comment
            if commentformat is not None:
                kwargs['comment_format'] = commentformat
        kwargs['wf_info_for'] = self.entity
        if treid is not None:
            kwargs['by_transition'] = self._cw.entity_from_eid(treid)
        if tseid is not None:
            kwargs['to_state'] = self._cw.entity_from_eid(tseid)
        return self._cw.create_entity('TrInfo', **kwargs)

    def _get_transition(self, tr):
        assert self.current_workflow
        if isinstance(tr, str):
            _tr = self.current_workflow.transition_by_name(tr)
            assert _tr is not None, 'not a %s transition: %s' % (
                self.__regid__, tr)
            tr = _tr
        return tr

    def fire_transition(self, tr, comment=None, commentformat=None):
        """change the entity's state by firing given transition (name or entity)
        in entity's workflow
        """
        tr = self._get_transition(tr)
        return self._add_trinfo(comment, commentformat, tr.eid)

    def fire_transition_if_possible(self,
                                    tr,
                                    comment=None,
                                    commentformat=None):
        """change the entity's state by firing given transition (name or entity)
        in entity's workflow if this transition is possible
        """
        tr = self._get_transition(tr)
        if any(tr_ for tr_ in self.possible_transitions()
               if tr_.eid == tr.eid):
            self.fire_transition(tr, comment, commentformat)

    def change_state(self,
                     statename,
                     comment=None,
                     commentformat=None,
                     tr=None):
        """change the entity's state to the given state (name or entity) in
        entity's workflow. This method should only by used by manager to fix an
        entity's state when their is no matching transition, otherwise
        fire_transition should be used.
        """
        assert self.current_workflow
        if hasattr(statename, 'eid'):
            stateeid = statename.eid
        else:
            state = self.current_workflow.state_by_name(statename)
            if state is None:
                raise WorkflowException('not a %s state: %s' %
                                        (self.__regid__, statename))
            stateeid = state.eid
        # XXX try to find matching transition?
        return self._add_trinfo(comment, commentformat, tr and tr.eid,
                                stateeid)

    def set_initial_state(self, statename):
        """set a newly created entity's state to the given state (name or entity)
        in entity's workflow. This is useful if you don't want it to be the
        workflow's initial state.
        """
        assert self.current_workflow
        if hasattr(statename, 'eid'):
            stateeid = statename.eid
        else:
            state = self.current_workflow.state_by_name(statename)
            if state is None:
                raise WorkflowException('not a %s state: %s' %
                                        (self.__regid__, statename))
            stateeid = state.eid
        self._cw.execute('SET X in_state S WHERE X eid %(x)s, S eid %(s)s', {
            'x': self.entity.eid,
            's': stateeid
        })