class IWorkflowRequestUrgencyInfo(Interface): """Workflow request urgency info""" urgent_request = Bool( title=_("Urgent request?"), description=_("Please use this option only when really needed..."), required=True, default=False)
def check_expiration_date(self): """Check expiration date""" if self.publication_expiration_date is not None: if self.publication_effective_date is None: raise Invalid( _("Can't define publication end date without publication " "start date!")) if self.publication_effective_date >= self.publication_expiration_date: raise Invalid( _("Publication end date must be defined after publication " "start date!"))
def check_push_end_date(self): """Check push end date""" if self.push_end_date is not None: if self.publication_effective_date is None: raise Invalid( _("Can't define push end date without publication start date!" )) if self.publication_effective_date >= self.push_end_date: raise Invalid( _("Push end date must be defined after publication start date!" )) if self.publication_expiration_date is not None: if self.publication_expiration_date < self.push_end_date: raise Invalid( _("Push end date must be null or defined before publication " "end date!"))
def label(self): """Label getter""" translate = self.request.localizer.translate state = IWorkflowState(self.context) return translate(_("Version {id} - {state}")).format( id=state.version_id, state=translate(self.workflow.get_state_label(state.state)))
class IWorkflowManagedContent(IAttributeAnnotatable): """Workflow managed content""" content_class = Attribute("Content class") workflow_name = Choice( title=_("Workflow name"), description=_("Name of workflow utility managing this content"), required=True, vocabulary=WORKFLOWS_VOCABULARY) view_permission = Choice( title=_("View permission"), description=_("This permission will be required to display content"), vocabulary='PyAMS permissions', default=VIEW_PERMISSION, required=False)
class IWorkflowTransitionInfo(Interface): """Workflow transition info This interface is actually used to provide transition ID in workflow management forms. """ transition_id = TextLine(title=_("Transition ID"), required=True)
class IWorkflowState(Interface): """Store state on workflow object. Defined as an adapter. """ version_id = Int(title=_("Version ID")) state = TextLine(title=_("Version state")) state_date = Datetime( title=_("State date"), description=_("Date at which the current state was applied")) state_principal = PrincipalField( title=_("State principal"), description=_("ID of the principal which defined current " "state")) state_urgency = Bool(title=_("Urgent request?"), required=True, default=False) history = List(title="Workflow states history", value_type=Object(schema=IWorkflowStateHistoryItem)) def get_first_state_date(self, states): """Get first date at which given state was set"""
def publication(self): """Publication label used to display workflow publication state""" request = check_request() translate = request.localizer.translate sm = get_utility(ISecurityManager) # pylint: disable=invalid-name return translate(_('{date} by {principal}')).format( date=format_datetime(tztime( IWorkflowPublicationInfo(self).publication_date), request=request), principal=translate(sm.get_principal(self.publisher).title))
class WorkflowVersionHistoryDateColumn(I18nColumnMixin, DateColumn): """Workflow version history date column""" i18n_header = _("Date") attr_name = 'date' css_classes = {'td': 'nowrap'} weight = 1 formatter = SH_DATETIME_FORMAT
class WorkflowVersionHistoryCommentColumn(I18nColumnMixin, GetAttrColumn): """Workflow version history comment column""" i18n_header = _("Comment") attr_name = 'comment' weight = 15 def get_value(self, obj): # pylint: disable=no-self-use """Comment column value getter""" return text_to_html(obj.comment or '--')
class WorkflowVersionHistoryView(TableAdminView): """Workflow version history view""" @property def title(self): """Title getter""" translate = self.request.localizer.translate # pylint: disable=no-member return translate(_("Version {version} history")).format( version=IWorkflowState(self.context).version_id) # pylint: disable=no-member table_class = WorkflowVersionHistoryTable table_label = _("History of this version")
class WorkflowVersionHistoryPrincipalColumn(I18nColumnMixin, GetAttrColumn): """Workflow version history principal column""" i18n_header = _("Modifier") attr_name = 'principal' weight = 10 def get_value(self, obj): """Principal column value getter""" principal = get_principal(self.request, obj.principal) if isinstance(principal, MissingPrincipal): return '--' return principal.title
def _get_viewlets(self): translate = self.request.localizer.translate for version in IWorkflowVersions( self.context).get_last_versions(count=0): state = IWorkflowState(version) item = MenuItem(version, self.request, self.view, self) item.label = translate(_("Version {id} - {state}")).format( id=state.version_id, state=translate(self.workflow.get_state_label(state.state))) item.icon_class = 'fas fa-arrow-right' if version is self.context: item.css_class = 'bg-primary text-white' item.href = absolute_url(version, self.request, 'admin#{}'.format(self.request.view_name)) yield 'version_{}'.format(state.version_id), item
def handle_cloned_object(event): """Add comment when an object is cloned""" request = check_request() translate = request.localizer.translate source_state = IWorkflowState(event.source) factory = get_object_factory(IWorkflowStateHistoryItem) if factory is not None: item = factory( date=datetime.utcnow(), principal=request.principal.id, comment=translate( _("Clone created from version {source} (in « {state} » " "state)")).format(source=source_state.version_id, state=translate( IWorkflow( event.source).get_state_label( source_state.state)))) target_state = IWorkflowState(event.object) target_state.history.clear() # pylint: disable=no-member target_state.history.append(item) # pylint: disable=no-member
class WorkflowTransitionsMenu(DropdownMenu): """Workflow transitions menu""" status = 'danger' css_class = 'btn-sm' label = _("Change status...") def _get_viewlets(self): viewlets = [] content = get_parent(self.context, IWorkflowManagedContent) wf = get_utility(IWorkflow, name=content.workflow_name) # pylint: disable=invalid-name if wf is None: return viewlets info = IWorkflowInfo(self.context) for transition_id in info.get_manual_transition_ids(): transition = wf.get_transition_by_id(transition_id) menu = TransitionMenuItem(self.context, self.request, self.view, self, transition) viewlets.append((transition_id, menu)) return sorted(viewlets, key=lambda x: x[1].weight)
class WorkflowVersionHistoryStateColumn(I18nColumnMixin, GetAttrColumn): """Workflow version history source column""" i18n_header = _("New state") attr_name = 'target_state' weight = 5 def get_value(self, obj): """State column value getter""" state = super().get_value(obj) workflow = IWorkflow(self.context, None) if workflow is None: return state try: term = workflow.states.getTerm(state) except LookupError: return state or '--' else: translate = self.request.localizer.translate return translate(term.title)
class IWorkflowPublicationInfo(Interface): """Workflow content publication info This interface is used to specify publication dates applied on a given content. """ publication_date = Datetime( title=_("Publication date"), description=_("Last date at which content was accepted for " "publication"), required=False) publisher = PrincipalField( title=_("Publisher"), description=_("Name of the manager who published the document"), required=False) publication = TextLine(title=_("Publication"), description=_("Last publication date and actor"), required=False, readonly=True) first_publication_date = Datetime( title=_("First publication date"), description=_("First date at which content was accepted " "for publication"), required=False) publication_effective_date = Datetime( title=_("Publication start date"), description=_("Date from which content will be " "visible"), required=False) push_end_date = Datetime( title=_("Push end date"), description=_("Some contents can be pushed by components to " "front-office pages; if you set a date here, this " "content will not be pushed anymore passed this " "date, but will still be available via search engine " "or direct links"), required=False) push_end_date_index = Attribute( "Push end date value used by catalog indexes") @invariant def check_push_end_date(self): """Check push end date""" if self.push_end_date is not None: if self.publication_effective_date is None: raise Invalid( _("Can't define push end date without publication start date!" )) if self.publication_effective_date >= self.push_end_date: raise Invalid( _("Push end date must be defined after publication start date!" )) if self.publication_expiration_date is not None: if self.publication_expiration_date < self.push_end_date: raise Invalid( _("Push end date must be null or defined before publication " "end date!")) publication_expiration_date = Datetime( title=_("Publication end date"), description=_("Date past which content will not be " "visible"), required=False) @invariant def check_expiration_date(self): """Check expiration date""" if self.publication_expiration_date is not None: if self.publication_effective_date is None: raise Invalid( _("Can't define publication end date without publication " "start date!")) if self.publication_effective_date >= self.publication_expiration_date: raise Invalid( _("Publication end date must be defined after publication " "start date!")) displayed_publication_date = Choice( title=_("Displayed publication date"), description=_("The matching date will be displayed in " "front-office"), vocabulary=PYAMS_CONTENT_PUBLICATION_DATES, default=DISPLAY_FIRST_VERSION, required=True) visible_publication_date = Attribute("Visible publication date") def reset(self, complete=True): """Reset all publication info (used by clone features) If 'complete' argument is True, all date fields are reset; otherwise, push and publication end dates are preserved in new versions. """ def is_published(self, check_parent=True): """Is the content published?""" def is_visible(self, request=None, check_parent=True): """Is the content visible?"""
class WorkflowVersionHistoryMenuItem(NavigationMenuItem): """Workflow history menu item""" label = _("Version history") icon_class = 'fas fa-history' href = '#version-history.html'
def title(self): """Title getter""" translate = self.request.localizer.translate # pylint: disable=no-member return translate(_("Version {version} history")).format( version=IWorkflowState(self.context).version_id) # pylint: disable=no-member
class IWorkflowCommentInfo(Interface): """Workflow comment info""" comment = Text(title=_("Comment"), description=_("Comment associated with this operation"), required=False)
def get_state_label(self, state): """Get label matching given state""" try: return self.states.getTerm(state).title except LookupError: return _('-- unknown --')
view_permission = Choice( title=_("View permission"), description=_("This permission will be required to display content"), vocabulary='PyAMS permissions', default=VIEW_PERMISSION, required=False) DISPLAY_FIRST_VERSION = 'first' """Displayed publication date is the first publication date""" DISPLAY_CURRENT_VERSION = 'current' """Displayed publication date is the publication date of the current version""" VERSION_DISPLAY = { DISPLAY_FIRST_VERSION: _("Display first version date"), DISPLAY_CURRENT_VERSION: _("Display current version date") } VERSION_DISPLAY_VOCABULARY = SimpleVocabulary( [SimpleTerm(v, title=t) for v, t in VERSION_DISPLAY.items()]) PYAMS_CONTENT_PUBLICATION_DATES = 'PyAMS_workflow.content.publication_date' """Publication dates vocabulary name""" WORKFLOW_CONTENT_KEY = 'pyams_workflow.content_info' """Annotations key used to store content publication information""" class IWorkflowPublicationInfo(Interface): """Workflow content publication info