def objectStateChanged(self, object, event): """ object: origin domain workflowed object event: bungeni.core.workflow.states.WorkflowTransitionEvent .object # origin domain workflowed object .source # souirce state .destination # destination state .transition # transition .comment # """ change_data = self._get_change_data() # if note, attach it on object (if object supports such an attribute) if change_data["note"]: if hasattr(object, "note"): object.note = change_data["note"] # update object's workflow status date (if supported by object) if hasattr(object, "status_date"): object.status_date = change_data["date_active"] or datetime.now() # as a "base" description, use human readable workflow state title wf = IWorkflow(object) # !+ adapters.get_workflow(object) description = wf.get_state(event.destination).title # extras, that may be used e.g. to elaborate description at runtime extras = { "source": event.source, "destination": event.destination, "transition": event.transition.id, "comment": change_data["note"] } return self._objectChanged("workflow", object, description=description, extras=extras, date_active=change_data["date_active"])
def change_data_items(self): """Get change data items, reverse-sorted by date (most recent first). """ interaction = getInteraction() # slight performance optimization changes = [] def append_visible_changes_on_item(item): for c in domain.get_changes(item, *self.include_change_actions): if interaction.checkPermission("zope.View", c): changes.append(c) # !+ align checkPermission zope.View with listings of sub item types... # changes direct on head item if "head" in self.include_change_types: append_visible_changes_on_item(self.head) # changes on sub-items -- only Parliamentary Content may have sub-items if interfaces.IBungeniParliamentaryContent.providedBy(self.head): hwf = IWorkflow(self.head) # changes on item signatories if "signatory" in self.include_change_types: signatories = [ s for s in self.head.item_signatories if interaction.checkPermission("zope.View", s) ] for s in signatories: append_visible_changes_on_item(s) # changes on item attachments if ("attachment" in self.include_change_types and hwf.has_feature("attachment") #!+IFeatureAttachment? ): attachments = [ f for f in self.head.attachments if interaction.checkPermission("zope.View", f) ] for f in attachments: append_visible_changes_on_item(f) # changes on item events if ("event" in self.include_change_types # and workflow.has_feature("event"): #!+IEventable? # at least no recursion, on events on events... and not interfaces.IEvent.providedBy(self.head)): events = [ e for e in self.head.sa_events if interaction.checkPermission("zope.View", e) ] for e in events: append_visible_changes_on_item(e) # sort aggregated changes by date_active changes = [ dc[1] for dc in reversed(sorted([(c.date_active, c) for c in changes])) ] return changes '''
def schedule_sitting_items(context): # !+fireTransitionToward(mr, dec-2010) sequence of fireTransitionToward # calls was introduced in r5818, 28-jan-2010 -- here the code is reworked # to be somewhat more sane, and added logging of both SUCCESS and of # FAILURE of each call to fireTransitionToward(). # # The check/logging should be removed once it is understood whether # NoTransitionAvailableError is *always* raised (i.e. fireTransitionToward is # broken) or it is indeed raised correctly when it should be. def fireTransitionScheduled(item, check_security=False): try: IWorkflowController(item).fireTransitionToward( "scheduled", check_security=False) raise RuntimeWarning( """It has WORKED !!! fireTransitionToward("scheduled")""") except (NoTransitionAvailableError, RuntimeWarning): debug.log_exc_info(sys.exc_info(), log.error) for schedule in context.item_schedule: wf = IWorkflow(schedule.item, None) if wf is None: continue try: if wf.get_state("scheduled"): fireTransitionScheduled(schedule.item) except InvalidStateError: pass
def schedule_sitting_items(context): # !+fireTransitionToward(mr, dec-2010) sequence of fireTransitionToward # calls was introduced in r5818, 28-jan-2010 -- here the code is reworked # to be somewhat more sane, and added logging of both SUCCESS and of # FAILURE of each call to fireTransitionToward(). # # The check/logging should be removed once it is understood whether # NoTransitionAvailableError is *always* raised (i.e. fireTransitionToward is # broken) or it is indeed raised correctly when it should be. def fireTransitionScheduled(item, check_security=False): try: IWorkflowController(item).fireTransitionToward("scheduled", check_security=False) raise RuntimeWarning( """It has WORKED !!! fireTransitionToward("scheduled")""") except (NoTransitionAvailableError, RuntimeWarning): debug.log_exc_info(sys.exc_info(), log.error) for schedule in context.item_schedule: wf = IWorkflow(schedule.item, None) if wf is None: continue try: if wf.get_state("scheduled"): fireTransitionScheduled(schedule.item) except InvalidStateError: pass
def get_sitting_items(sitting, request, include_actions=False): items = [] if (sitting.status in IWorkflow(sitting).get_state_ids( keys=["draft_agenda", "published_agenda"])): order = "planned_order" else: order = "real_order" schedulings = map(removeSecurityProxy, sitting.items.batch(order_by=order, limit=None)) for scheduling in schedulings: item = ProxyFactory(location_wrapped(scheduling.item, sitting)) props = IDCDescriptiveProperties.providedBy(item) and item or \ IDCDescriptiveProperties(item) discussions = tuple(scheduling.discussions.values()) discussion = discussions and discussions[0] or None truncated_discussion = None if ((discussion is not None) and (discussion.body is not None)): #truncate discussion to first hundred characters t_discussion = discussion.body[0:100] try: #truncate discussion to first two lines index = t_discussion.index("<br>") index2 = t_discussion.index("<br>", index + 4) truncated_discussion = t_discussion[0:index2] + "..." except ValueError: truncated_discussion = t_discussion + "..." state_title = IWorkflow(item).get_state(item.status).title item = removeSecurityProxy(item) record = { "title": props.title, "description": props.description, "name": stringKey(scheduling), "status": item.status, "type": item.type.capitalize, "state_title": state_title, "heading": True if item.type == "heading" else False, #"category_id": scheduling.category_id, #"category": scheduling.category, "discussion": discussion, "truncated_discussion": truncated_discussion, "delete_url": "%s/delete" % url.absoluteURL(scheduling, request), "url": url.absoluteURL(item, request), } if include_actions: record["actions"] = get_scheduling_actions(scheduling, request) record["workflow"] = get_workflow_actions(item, request) discussion_actions = get_discussion_actions(discussion, request) if discussion_actions: assert len(discussion_actions) == 1 record["discussion_action"] = discussion_actions[0] else: record["discussion_action"] = None items.append(record) return items
def documentInDraft(self): """Assume destinations of transitions with no sources are draft """ wf = IWorkflow(self.pi_instance, None) if wf: return (self.pi_instance.status in [tr.destination for tr in wf.get_transitions_from(None)] ) return False
def documentInDraft(self): """Assume destinations of transitions with no sources are draft """ wf = IWorkflow(self.pi_instance, None) if wf: return (self.pi_instance.status in [ tr.destination for tr in wf.get_transitions_from(None) ]) return False
def change_data_items(self): """Get change data items, reverse-sorted by date (most recent first). """ interaction = getInteraction() changes = [] def append_visible_changes_on_item(item): permission = view_permission(item) for c in domain.get_changes(item, *self.include_change_actions): if checkPermission(permission, c): changes.append(c) # changes direct on head item if "head" in self.include_change_types: append_visible_changes_on_item(self.head) # changes on sub-items -- only Parliamentary Content may have sub-items if interfaces.IBungeniParliamentaryContent.providedBy(self.head): hwf = IWorkflow(self.head) # changes on item signatories if "signatory" in self.include_change_types: signatories = [ s for s in self.head.item_signatories if interaction.checkPermission("bungeni.signatory.View", s) ] for s in signatories: append_visible_changes_on_item(s) # changes on item attachments if ("attachment" in self.include_change_types and hwf.has_feature("attachment") #!+IFeatureAttachment? ): attachments = [ f for f in self.head.attachments if interaction.checkPermission("bungeni.attachment.View", f) ] for f in attachments: append_visible_changes_on_item(f) # changes on item events if ("event" in self.include_change_types # and workflow.has_feature("event"): #!+IEventable? # at least no recursion, on events on events... and not interfaces.IEvent.providedBy(self.head) ): events = [ e for e in self.head.sa_events if interaction.checkPermission("bungeni.event.View", e) ] for e in events: append_visible_changes_on_item(e) # sort aggregated changes by date_active changes = [ dc[1] for dc in reversed(sorted([ (c.date_active, c) for c in changes ])) ] return changes '''
def generate_preview(self): sitting = removeSecurityProxy(self.context) wf = IWorkflow(sitting) sittings = [data.ExpandedSitting(sitting)] generator = generators.ReportGeneratorXHTML(self.get_template()) if sitting.status in wf.get_state_ids(tagged=["publishedminutes"]): title = generator.title = _(u"Sitting Votes and Proceedings") else: title = generator.title = _(u"Sitting Agenda") generator.context = data.ReportContext(sittings=sittings, title=title) return generator.generateReport()
def getMenuItems(self, context, request): """Return menu item entries in a TAL-friendly form.""" if (not interfaces.IWorkspaceOrAdminSectionLayer.providedBy(request) or interfaces.IFormEditLayer.providedBy(request) or IVersion.providedBy(context) ): return () #!+wfc.workflow wf = IWorkflow(context, None) if wf is None: return () #state = IWorkflowController(context).state_controller.get_status() wfc = IWorkflowController(context) wf = wfc.workflow # !+wfc.workflow tids = wfc.getManualTransitionIds() parliament_id = getCurrentParliamentId() _url = url.absoluteURL(context, request) site_url2 = url.absoluteURL(getSite(), request) results = [] for tid in tids: state_transition = wf.get_transition(tid) #Compares the current url to homepage to determine whether #we are on workspace or not. #Fix for bug 319 #Someone should probably review this. if _url == site_url2: transition_url = site_url2 + \ "/archive/browse/parliaments/obj-" + \ str(parliament_id) + \ "/change_workflow_state?" + \ "transition=%s&next_url=..." % tid else: transition_url = _url + \ "/change_workflow_state?"\ "transition=%s&next_url=..." % tid extra = {"id": "workflow-transition-%s" % tid, "separator": None, "class": ""} state_title = translate(str(state_transition.title), domain="bungeni", context=request) results.append( dict(title=state_title, description="", action=transition_url, selected=False, transition_id=tid, icon=None, extra=extra, submenu=None)) return results
def as_json(self): is_text = IScheduleText.implementedBy(self.domain_class) date_formatter = date.getLocaleFormatter(common.get_request(), "date", "medium") items = [ dict( item_type=self.item_type, item_id=orm.object_mapper(item).primary_key_from_instance( item)[0], item_title=IDCDescriptiveProperties(item).title, status=(IWorkflow(item).get_state(item.status).title if not is_text else None), status_date=(date_formatter.format(item.submission_date) if (hasattr(item, "submission_date") and getattr(item, "submission_date")) else None), registry_number=(item.registry_number if hasattr( item, "registry_number") else None), item_mover=(IDCDescriptiveProperties(item.owner).title if hasattr(item, "owner") else None), item_uri="%s-%d" % (self.item_type, orm.object_mapper(item).primary_key_from_instance(item)[0])) for item in self.query() ] items = sorted(items, key=lambda item: item.get("status_date"), reverse=True) return json.dumps(dict(items=items))
def _get(discriminator): """Get the TypeInfo instance for discriminator, that may be any of: type_key: str (the lowercase underscore-separated of domain cls name) workflow: an instance of Workflow, provides IWorkflow interface: provides IInterface domain model: provides IBungeniContent domain model instance: type provides IBungeniContent descriptor: provides IModelDescriptor Raise KeyError if no entry matched. Usage: capi.get_type_info(discriminator) """ if discriminator is None: m = "type_info._get discriminator is None" log.error(m) raise ValueError(m) discri = removeSecurityProxy(discriminator) getter = None # !+IALCHEMISTCONTENT normalize trickier discriminator cases to type_key if IIModelInterface.providedBy(discri): discri = naming.type_key("table_schema_interface_name", discri.__name__) elif IInterface.providedBy(discri): discri = naming.type_key("model_interface_name", discri.__name__) elif type(discri) is type and issubclass(discri, domain.Entity): discri = naming.polymorphic_identity(discri) elif isinstance(discri, domain.Entity): discri = naming.polymorphic_identity(type(discri)) if isinstance(discri, basestring): getter = _get_by_type_key #elif IInterface.providedBy(discri): # getter = _get_by_interface #!+elif interfaces.IBungeniContent.implementedBy(discri): #elif issubclass(discri, domain.Entity): # getter = _get_by_model #!+elif interfaces.IBungeniContent.providedBy(discri): #elif isinstance(discri, domain.Entity): # getter = _get_by_instance elif IWorkflow.providedBy(discri): getter = _get_by_workflow elif IModelDescriptor.implementedBy(discri): getter = _get_by_descriptor_model if getter is not None: ti = getter(discri) if ti is not None: return ti else: m = "No type registered for discriminator: %r" % (discriminator) else: m = "Invalid type info lookup discriminator: %r" % (discriminator) from bungeni.utils import probing log.debug(probing.interfaces(discriminator)) log.debug(m) raise KeyError(m)
def _get(discriminator): """Get the TypeInfo instance for discriminator, that may be any of: type_key: str (the lowercase underscore-separated of domain cls name) workflow: an instance of Workflow, provides IWorkflow interface: provides IInterface domain model: provides IBungeniContent domain model instance: type provides IBungeniContent descriptor: provides IModelDescriptor Raise KeyError if no entry matched. Usage: capi.get_type_info(discriminator) """ if discriminator is None: m = "type_info._get discriminator is None" log.error(m) raise ValueError(m) discri = removeSecurityProxy(discriminator) getter = None # !+IALCHEMISTCONTENT normalize trickier discriminator cases to type_key if IIModelInterface.providedBy(discri): discri = naming.type_key("table_schema_interface_name", discri.__name__) elif IInterface.providedBy(discri): discri = naming.type_key("model_interface_name", discri.__name__) elif type(discri) is type and issubclass(discri, domain.Entity): discri = naming.polymorphic_identity(discri) elif isinstance(discri, domain.Entity): discri = naming.polymorphic_identity(type(discri)) if isinstance(discri, basestring): getter = _get_by_type_key #elif IInterface.providedBy(discri): # getter = _get_by_interface #!+elif interfaces.IBungeniContent.implementedBy(discri): #elif issubclass(discri, domain.Entity): # getter = _get_by_model #!+elif interfaces.IBungeniContent.providedBy(discri): #elif isinstance(discri, domain.Entity): # getter = _get_by_instance elif IWorkflow.providedBy(discri): getter = _get_by_workflow elif IModelDescriptor.implementedBy(discri): getter = _get_by_descriptor_model if getter is not None: ti = getter(discri) if ti is not None: return ti else: m = "No type registered for discriminator: %r" % (discriminator) else: m = "Invalid type info lookup discriminator: %r" % (discriminator) from bungeni.ui.utils import debug log.debug(debug.interfaces(discriminator)) log.debug(m) raise KeyError(m)
def __new__(cls, context, request): # this is currently the only way to make sure this menu only # "adapts" to a workflowed context; the idea is that the # component lookup will fail, which will propagate back to the # original lookup request workflow = IWorkflow(context, None) if workflow is None: return return object.__new__(cls, context, request)
def default_reports(sitting, event): wf = IWorkflow(sitting) if sitting.status in wf.get_state_ids(tagged=["published"]): sitting = removeSecurityProxy(sitting) sittings = [ExpandedSitting(sitting)] report_context = ReportContext(sittings=sittings) report = domain.Report() session = Session() # !+GROUP_AS_OWNER(mr, apr-2012) we assume for now that the "owner" of # the report is the currently logged in user. report.owner_id = get_db_user_id() report.created_date = datetime.datetime.now() report.group_id = sitting.group_id # generate using html template in bungeni_custom vocabulary = component.queryUtility( schema.interfaces.IVocabularyFactory, "bungeni.vocabulary.ReportXHTMLTemplates" ) preview_template = filter( lambda t: t.title=="Sitting Agenda", vocabulary.terms )[0] doc_template = preview_template.value generator = generators.ReportGeneratorXHTML(doc_template) generator.context = report_context report.language = generator.language if sitting.status in wf.get_state_ids(tagged=["publishedminutes"]): report.short_title = generator.title = _(u"Sitting Votes and " u" Proceedings" ) else: report.short_title = generator.title = _(u"Sitting Agenda") report.body = generator.generateReport() session.add(report) session.flush() notify(ObjectCreatedEvent(report)) sr = domain.SittingReport() sr.report = report sr.sitting = sitting session.add(sr) session.flush() notify(ObjectCreatedEvent(sr))
def get_status(self, item_type): workspace_config = component.getUtility(IWorkspaceTabsUtility) roles = get_workspace_roles() + OBJECT_ROLES domain_class = workspace_config.get_domain(item_type) results = set() for role in roles: status = workspace_config.get_status(role, domain_class, self.context.__name__) if status: for s in status: results.add(s) translated = dict() for result in results: workflow = IWorkflow(domain_class()) status_title = translate(str(workflow.get_state(result).title), domain="bungeni", context=self.request) translated[result] = status_title return translated
def default_reports(sitting, event): wf = IWorkflow(sitting) if sitting.status in wf.get_state_ids(tagged=["published"]): sitting = removeSecurityProxy(sitting) report_type = "sitting_agenda" report_title = _("report_title_sitting_agenda", default=u"Sitting Agenda") if sitting.status in wf.get_state_ids(tagged=["publishedminutes"]): report_type = "sitting_minutes" report_title = _("report_title_votes_and_proceedings", default=u"Sitting Votes and Proceedings") sittings = [ExpandedSitting(sitting)] report = domain.Report() session = Session() # !+GROUP_AS_OWNER(mr, apr-2012) we assume for now that the "owner" of # the report is the currently logged in user. report.owner_id = get_db_user_id() report.created_date = datetime.datetime.now() report.group_id = sitting.group_id # generate using html template in bungeni_custom vocab = vocabulary.report_xhtml_template_factory term = vocab.getTermByFileName(report_type) doc_template = term and term.value or vocab.terms[0].value generator = generators.ReportGeneratorXHTML(doc_template) generator.title = report_title report_title_i18n = translate(report_title, target_language=generator.language) report_context = ReportContext(sittings=sittings, title=report_title_i18n) generator.context = report_context report.title = report_title_i18n report.language = generator.language report.body = generator.generateReport() session.add(report) session.flush() notify(ObjectCreatedEvent(report)) sr = domain.SittingReport() sr.report = report sr.sitting = sitting session.add(sr) session.flush() notify(ObjectCreatedEvent(sr))
def getMenuItems(self, context, request): """Return menu item entries in a TAL-friendly form. !+TAL-friendly(mr, sep-2011) means what? """ if (not interfaces.IWorkspaceOrAdminSectionLayer.providedBy(request) or interfaces.IFormEditLayer.providedBy(request) or IVersion.providedBy(context)): return () #!+wfc.workflow wf = IWorkflow(context, None) if wf is None: return () #state = IWorkflowController(context).state_controller.get_status() wfc = IWorkflowController(context) wf = wfc.workflow tids = wfc.getManualTransitionIds() _url = url.absoluteURL(context, request) results = [] for tid in tids: transit_url = \ "%s/change_workflow_state?transition_id=%s&next_url=..." % ( _url, tid) extra = { "id": "workflow-transition-%s" % tid, "separator": None, "class": "" } state_title = translate(str(wf.get_transition(tid).title), domain="bungeni", context=request) results.append( dict(title=state_title, description="", action=transit_url, selected=False, transition_id=tid, icon=None, extra=extra, submenu=None)) return results
def get_status(self, item_type): workspace_config = component.getUtility(IWorkspaceTabsUtility) roles = get_workspace_roles() + OBJECT_ROLES domain_class = workspace_config.get_domain(item_type) results = set() for role in roles: status = workspace_config.get_status( role, domain_class, self.context.__name__) if status: for s in status: results.add(s) translated = dict() for result in results: workflow = IWorkflow(domain_class()) status_title = translate( str(workflow.get_state(result).title), domain="bungeni", context=self.request ) translated[result] = status_title return translated
def get_filter_config(tag="tobescheduled"): return dict([(item_type, { "label": _(u"choose status"), "menu": [{ "text": IWorkflow( domain.DOMAIN_CLASSES[item_type]()).get_state(status).title, "value": status } for status in get_workflow(item_type).get_state_ids(tagged=[tag])] }) for item_type in get_schedulable_types().keys()])
def getMenuItems(self, context, request): """Return menu item entries in a TAL-friendly form. !+TAL-friendly(mr, sep-2011) means what? """ if (not interfaces.IWorkspaceOrAdminSectionLayer.providedBy(request) or interfaces.IFormEditLayer.providedBy(request) or IVersion.providedBy(context) ): return () #!+wfc.workflow wf = IWorkflow(context, None) if wf is None: return () #state = IWorkflowController(context).state_controller.get_status() wfc = IWorkflowController(context) wf = wfc.workflow tids = wfc.getManualTransitionIds() _url = url.absoluteURL(context, request) results = [] for tid in tids: transit_url = ("%s/change_workflow_state?transition_id=%s&" "next_url=./workflow-redirect" % (_url, tid) ) extra = {"id": "workflow-transition-%s" % tid, "separator": None, "class": ""} state_title = translate(wf.get_transition(tid).title, domain="bungeni", context=request) results.append( dict(title=state_title, description="", action=transit_url, selected=False, transition_id=tid, icon=None, extra=extra, submenu=None)) return results
def extra(self): wf = IWorkflow(self.context, None) if wf is None: return {"id": self.id} status = self.context.status state_title = translate(misc.get_wf_state(self.context), domain="bungeni", context=self.request) return { "id": self.id, "class": "state-%s" % status, "state": status, "stateTitle": state_title }
def change_data_items(self): """Get change data items, reverse-sorted by date (most recent first). """ interaction = getInteraction() head_wf = IWorkflow(self.head) changes = [] def append_visible_changes_on_item(item): permission = view_permission(item) for c in domain.get_changes(item, *self.param_audit_actions): if checkPermission(permission, c): changes.append(c) def include_feature_changes(feature_name, SUPPORTED_FEATURE): # !+ interfaces.IFeatureX.providedBy(self.head) return ( (not SUPPORTED_FEATURE or head_wf.has_feature(feature_name)) and feature_name in self.param_include_subtypes) def append_visible_changes_on_sub_items(sub_type_key, items_attr, SUPPORTED_FEATURE=True # !+ ): if include_feature_changes(sub_type_key, SUPPORTED_FEATURE): pid = "bungeni.%s.View" % (sub_type_key) items = [ item for item in getattr(self.head, items_attr) if interaction.checkPermission(pid, item) ] for item in items: append_visible_changes_on_item(item) # changes direct on head item append_visible_changes_on_item(self.head) # changes on sub-items append_visible_changes_on_sub_items("signatory", "sa_signatories") append_visible_changes_on_sub_items("attachment", "attachments") append_visible_changes_on_sub_items("event", "sa_events") if interfaces.IDoc.providedBy(self.head): append_visible_changes_on_sub_items("group_assignment", "sa_group_assignments") elif interfaces.IGroup.providedBy(self.head): append_visible_changes_on_sub_items("group_assignment", "sa_group_assignments", SUPPORTED_FEATURE=False) # !+ "group_assignment" is not a "group" feature append_visible_changes_on_sub_items("member", "group_members", SUPPORTED_FEATURE=False) # !+ "member" is not a "group" feature) # sort aggregated changes by date_active changes = [ dc[1] for dc in reversed(sorted([ (c.date_active, c) for c in changes ])) ] return changes '''
def update(self): need("yui-dragdrop") need("yui-container") sitting = self._parent._parent.context scheduled_item_ids = [item.item_id for item in sitting.item_schedule] # add location to items gsm = component.getSiteManager() adapter = gsm.adapters.lookup( (interface.implementedBy(self.model), interface.providedBy(self)), ILocation) date_formatter = self.get_date_formatter("date", "medium") items = [adapter(item, None) for item in self._query_items()] # for each item, format dictionary for use in template self.items = [ { "title": properties.title, "name": item.__class__.__name__, "description": properties.description, #"date": _(u"$F", mapping={"F": # datetimedict.fromdatetime(item.changes[-1].date)}), #"date":item.changes[-1].date, # not every item has a auditlog (headings) # use last status change instead. "date": self._item_date(item) and date_formatter.format(self._item_date(item)), "state": IWorkflow(item).get_state(item.status).title, "id": self._get_item_key(item), "class": ((self._get_item_key(item) in scheduled_item_ids and "dd-disable") or ""), "url": self._item_url(item), "type": item.type } for item, properties in [( item, (IDCDescriptiveProperties.providedBy(item) and item or IDCDescriptiveProperties(item))) for item in items] ]
def as_json(self): date_formatter = date.getLocaleFormatter(common.get_request(), "date", "medium") items_json = dict(items=[ dict(item_type=self.item_type, item_id=orm.object_mapper(item).primary_key_from_instance( item)[0], item_title=IDCDescriptiveProperties(item).title, status=IWorkflow(item).get_state(item.status).title, status_date=(date_formatter.format(item.submission_date) if hasattr(item, "submission_date") else None), registry_number=(item.registry_number if hasattr( item, "registry_number") else None), item_mover=(IDCDescriptiveProperties(item.owner). title if hasattr(item, "owner") else None), item_uri=IDCDescriptiveProperties(item).uri) for item in self.query() ]) return json.dumps(items_json)
def publish_to_xml(context): """Generates XML for object and saves it to the file. If object contains attachments - XML is saved in zip archive with all attached files. """ include = [] context = removeSecurityProxy(context) if IVersionable.implementedBy(context.__class__): include.append("versions") if IAuditable.implementedBy(context.__class__): include.append("event") data = obj2dict(context, 1, parent=None, include=include, exclude=[ "file_data", "image", "logo_data", "event", "attached_files", "changes" ]) type = IWorkflow(context).name tags = IStateController(context).get_state().tags if tags: data["tags"] = tags permissions = get_object_state_rpm(context).permissions data["permissions"] = get_permissions_dict(permissions) data["changes"] = [] for change in getattr(context, "changes", []): change_dict = obj2dict(change, 0, parent=context) change_permissions = get_head_object_state_rpm(change).permissions change_dict["permissions"] = get_permissions_dict(change_permissions) data["changes"].append(change_dict) # list of files to zip files = [] # setup path to save serialized data path = os.path.join(setupStorageDirectory(), type) if not os.path.exists(path): os.makedirs(path) # xml file path file_path = os.path.join(path, stringKey(context)) has_attachments = False if IAttachmentable.implementedBy(context.__class__): attached_files = getattr(context, "attached_files", None) if attached_files: has_attachments = True # add xml file to list of files to zip files.append("%s.xml" % (file_path)) data["attached_files"] = [] for attachment in attached_files: # serializing attachment attachment_dict = obj2dict( attachment, 1, parent=context, exclude=["file_data", "event", "versions", "changes"]) permissions = get_object_state_rpm(attachment).permissions attachment_dict["permissions"] = \ get_permissions_dict(permissions) # saving attachment to tmp with tmp(delete=False) as f: f.write(attachment.file_data) files.append(f.name) attachment_dict["saved_file"] = \ os.path.split(f.name)[-1] data["attached_files"].append(attachment_dict) # saving xml file with open("%s.xml" % (file_path), "w") as file: file.write(serialize(data, name=type)) # zipping xml and attached files # unzipped files are removed if has_attachments: zip = ZipFile("%s.zip" % (file_path), "w") for f in files: zip.write(f, os.path.split(f)[-1]) os.remove(f) zip.close()
def publish_to_xml(context): """Generates XML for object and saves it to the file. If object contains attachments - XML is saved in zip archive with all attached files. """ #create a fake interaction to ensure items requiring a participation #are serialized #!+SERIALIZATION(mb, Jan-2013) review this approach try: zope.security.management.getInteraction() except zope.security.interfaces.NoInteraction: principal = zope.security.testing.Principal('user', 'manager', ()) zope.security.management.newInteraction( create_participation(principal)) include = [] # list of files to zip files = [] # data dict to be published data = {} context = zope.security.proxy.removeSecurityProxy(context) if interfaces.IFeatureVersion.providedBy(context): include.append("versions") if interfaces.IFeatureAudit.providedBy(context): include.append("event") exclude = ["data", "event", "attachments", "changes"] # include binary fields and include them in the zip of files for this object for column in class_mapper(context.__class__).columns: if column.type.__class__ == Binary: exclude.append(column.key) content = getattr(context, column.key, None) if content: bfile = tmp(delete=False) bfile.write(content) files.append(bfile.name) data[column.key] = dict( saved_file=os.path.basename(bfile.name)) bfile.close() data.update( obj2dict(context, 1, parent=None, include=include, exclude=exclude)) obj_type = IWorkflow(context).name tags = IStateController(context).get_state().tags if tags: data["tags"] = tags permissions = get_object_state_rpm(context).permissions data["permissions"] = get_permissions_dict(permissions) data["changes"] = [] for change in getattr(context, "changes", []): change_dict = obj2dict(change, 0, parent=context) change_permissions = get_head_object_state_rpm(change).permissions change_dict["permissions"] = get_permissions_dict(change_permissions) data["changes"].append(change_dict) # setup path to save serialized data path = os.path.join(setupStorageDirectory(), obj_type) if not os.path.exists(path): os.makedirs(path) # xml file path file_path = os.path.join(path, stringKey(context)) if interfaces.IFeatureAttachment.providedBy(context): attachments = getattr(context, "attachments", None) if attachments: data["attachments"] = [] for attachment in attachments: # serializing attachment attachment_dict = obj2dict( attachment, 1, parent=context, exclude=["data", "event", "versions"]) permissions = get_object_state_rpm(attachment).permissions attachment_dict["permissions"] = \ get_permissions_dict(permissions) # saving attachment to tmp attached_file = tmp(delete=False) attached_file.write(attachment.data) attached_file.flush() attached_file.close() files.append(attached_file.name) attachment_dict["saved_file"] = os.path.basename( attached_file.name) data["attachments"].append(attachment_dict) # zipping xml, attached files plus any binary fields # also remove the temporary files if files: #generate temporary xml file temp_xml = tmp(delete=False) temp_xml.write(serialize(data, name=obj_type)) temp_xml.close() #write attachments/binary fields to zip zip_file = ZipFile("%s.zip" % (file_path), "w") for f in files: zip_file.write(f, os.path.basename(f)) os.remove(f) #write the xml zip_file.write(temp_xml.name, "%s.xml" % os.path.basename(file_path)) zip_file.close() #placed remove after zip_file.close !+ZIP_FILE_CRC_FAILURE os.remove(temp_xml.name) else: # save serialized xml to file with open("%s.xml" % (file_path), "w") as xml_file: xml_file.write(serialize(data, name=obj_type)) xml_file.close() #publish to rabbitmq outputs queue connection = get_mq_connection() if not connection: return channel = connection.channel() publish_file_path = "%s.%s" % (file_path, ("zip" if files else "xml")) channel.basic_publish(exchange=SERIALIZE_OUTPUT_EXCHANGE, routing_key=SERIALIZE_OUTPUT_ROUTING_KEY, body=simplejson.dumps({ "type": "file", "location": publish_file_path }), properties=pika.BasicProperties( content_type="text/plain", delivery_mode=2)) #clean up - remove any files if zip was created if files: prev_xml_file = "%s.%s" % (file_path, "xml") if os.path.exists(prev_xml_file): os.remove(prev_xml_file)
def publish_to_xml(context): """Generates XML for object and saves it to the file. If object contains attachments - XML is saved in zip archive with all attached files. """ context = zope.security.proxy.removeSecurityProxy(context) obj_type = IWorkflow(context).name #locking lock_name = "%s-%s" % (obj_type, stringKey(context)) with LockStore.get_lock(lock_name): #root key (used to cache files to zip) root_key = make_key() #create a fake interaction to ensure items requiring a participation #are serialized #!+SERIALIZATION(mb, Jan-2013) review this approach try: zope.security.management.getInteraction() except zope.security.interfaces.NoInteraction: principal = zope.security.testing.Principal('user', 'manager', ()) zope.security.management.newInteraction( create_participation(principal)) include = [] # data dict to be published data = {} if interfaces.IFeatureVersion.providedBy(context): include.append("versions") if interfaces.IFeatureAudit.providedBy(context): include.append("event") exclude = ["data", "event", "attachments"] data.update( obj2dict(context, 1, parent=None, include=include, exclude=exclude, root_key=root_key)) tags = IStateController(context).get_state().tags if tags: data["tags"] = tags permissions = get_object_state_rpm(context).permissions data["permissions"] = get_permissions_dict(permissions) # setup path to save serialized data path = os.path.join(setupStorageDirectory(), obj_type) if not os.path.exists(path): os.makedirs(path) # xml file path file_path = os.path.join(path, stringKey(context)) #files to zip files = [] if interfaces.IFeatureAttachment.providedBy(context): attachments = getattr(context, "attachments", None) if attachments: data["attachments"] = [] for attachment in attachments: # serializing attachment attachment_dict = obj2dict( attachment, 1, parent=context, exclude=["data", "event", "versions"]) # saving attachment to tmp attached_file = tmp(delete=False) attached_file.write(attachment.data) attached_file.flush() attached_file.close() files.append(attached_file.name) attachment_dict["saved_file"] = os.path.basename( attached_file.name) data["attachments"].append(attachment_dict) #add explicit origin chamber for this object (used to partition data in #if more than one parliament exists) data["origin_parliament"] = get_origin_parliament(context) #add any additional files to file list files = files + PersistFiles.get_files(root_key) # zipping xml, attached files plus any binary fields # also remove the temporary files if files: #generate temporary xml file temp_xml = tmp(delete=False) temp_xml.write(serialize(data, name=obj_type)) temp_xml.close() #write attachments/binary fields to zip with ZipFile("%s.zip" % (file_path), "w") as zip_file: for f in files: zip_file.write(f, os.path.basename(f)) # write the xml zip_file.write(temp_xml.name, "%s.xml" % os.path.basename(file_path)) files.append(temp_xml.name) else: # save serialized xml to file with open("%s.xml" % (file_path), "w") as xml_file: xml_file.write(serialize(data, name=obj_type)) xml_file.close() # publish to rabbitmq outputs queue connection = bungeni.core.notifications.get_mq_connection() if not connection: return channel = connection.channel() publish_file_path = "%s.%s" % (file_path, ("zip" if files else "xml")) channel.basic_publish(exchange=SERIALIZE_OUTPUT_EXCHANGE, routing_key=SERIALIZE_OUTPUT_ROUTING_KEY, body=simplejson.dumps({ "type": "file", "location": publish_file_path }), properties=pika.BasicProperties( content_type="text/plain", delivery_mode=2)) #clean up - remove any files if zip was/was not created if files: files.append("%s.%s" % (file_path, "xml")) else: files.append("%s.%s" % (file_path, "zip")) remove_files(files) #clear the cache PersistFiles.clear_files(root_key)
def publish_to_xml(context): """Generates XML for object and saves it to the file. If object contains attachments - XML is saved in zip archive with all attached files. """ context = zope.security.proxy.removeSecurityProxy(context) obj_type = IWorkflow(context).name #locking random_name_sfx = generate_random_filename() context_file_name = "%s-%s" % (stringKey(context), random_name_sfx) #lock_name = "%s-%s" %(obj_type, context_file_name) #!+LOCKING(AH, 25-01-2014) disabling file locking #! locking was reqiured when the serializer used ta constant file name #! for an object. Now serialized file names are unique, and non repeated #with LockStore.get_lock(lock_name): # #root key (used to cache files to zip) root_key = make_key() # create a fake interaction to ensure items requiring a participation # are serialized #!+SERIALIZATION(mb, Jan-2013) review this approach try: zope.security.management.getInteraction() except zope.security.interfaces.NoInteraction: principal = zope.security.testing.Principal("user", "manager", ()) zope.security.management.newInteraction(create_participation(principal)) include = [] # data dict to be published data = {} if IFeatureVersion.providedBy(context): include.append("versions") if IFeatureEvent.providedBy(context): include.append("event") exclude = ["data", "event", "attachments"] updated_dict = obj2dict(context, 1, parent=None, include=include, exclude=exclude, root_key=root_key ) data.update( updated_dict ) tags = IStateController(context).get_state().tags if tags: data["tags"] = tags permissions = get_object_state_rpm(context).permissions data["permissions"] = get_permissions_dict(permissions) # setup path to save serialized data path = os.path.join(setupStorageDirectory(), obj_type) log.info("Setting up path to write to : %s", path) if not os.path.exists(path): # # !+THREADSAFE(AH, 2014-09-24) making makedirs threadsafe, # sometimes between checking for existence and execution # of makedirs() the folder has already been created by # another thread try: os.makedirs(path) except OSError as exc: if exc.errno == errno.EEXIST and os.path.isdir(path): log.info("Error Folder : %s already exists, ignoring exception ", path) else: raise # xml file path file_path = os.path.join(path, context_file_name) # files to zip files = [] if IFeatureAttachment.providedBy(context): attachments = getattr(context, "attachments", None) if attachments: data["attachments"] = [] for attachment in attachments: # serializing attachment attachment_dict = obj2dict(attachment, 1, parent=context, exclude=["data", "event", "versions"]) # saving attachment to tmp attached_file = tmp(delete=False) attached_file.write(attachment.data) attached_file.flush() attached_file.close() files.append(attached_file.name) attachment_dict["saved_file"] = os.path.basename( attached_file.name ) data["attachments"].append(attachment_dict) # add explicit origin chamber for this object (used to partition data # in if more than one chamber exists) if obj_type == "Legislature": data["origin_chamber"] = None else: data["origin_chamber"] = get_origin_chamber(context) # add any additional files to file list files = files + PersistFiles.get_files(root_key) # zipping xml, attached files plus any binary fields # also remove the temporary files if files: # generate temporary xml file temp_xml = tmp(delete=False) temp_xml.write(serialize(data, name=obj_type)) temp_xml.close() # write attachments/binary fields to zip with ZipFile("%s.zip" % (file_path), "w") as zip_file: for f in files: zip_file.write(f, os.path.basename(f)) # write the xml zip_file.write(temp_xml.name, "%s.xml" % os.path.basename(file_path)) files.append(temp_xml.name) else: # save serialized xml to file with open("%s.xml" % (file_path), "w") as xml_file: xml_file.write(serialize(data, name=obj_type)) xml_file.close() # publish to rabbitmq outputs queue connection = bungeni.core.notifications.get_mq_connection() if not connection: return channel = connection.channel() #channel.confirm_delivery() publish_file_path = "%s.%s" %(file_path, ("zip" if files else "xml")) #channel_delivery = channel.basic_publish( exchange=SERIALIZE_OUTPUT_EXCHANGE, routing_key=SERIALIZE_OUTPUT_ROUTING_KEY, body=simplejson.dumps({"type": "file", "location": publish_file_path }), properties=pika.BasicProperties(content_type="text/plain", delivery_mode=2 ) ) #if channel_delivery: # log.info("Message published to exchange %s with key %s for %s" % # (SERIALIZE_OUTPUT_EXCHANGE, SERIALIZE_OUTPUT_ROUTING_KEY, publish_file_path)) #else: # log.error("Message publication failed for %r", publish_file_path) #clean up - remove any files if zip was/was not created if files: files.append("%s.%s" %(file_path, "xml")) else: files.append("%s.%s" %(file_path, "zip")) remove_files(files) # clear the cache PersistFiles.clear_files(root_key)
class ChangeDataProvider(object): def __init__(self, context): self.head = removeSecurityProxy(context) self.head_workflow = IWorkflow(self.head) self.head_audit_feature = self.head_workflow.get_feature("audit") @property def param_audit_actions(self): return self.head_audit_feature.get_param("audit_actions") @property def param_include_subtypes(self): return self.head_audit_feature.get_param("include_subtypes") @property def param_display_columns(self): return self.head_audit_feature.get_param("display_columns") def change_data_items(self): """Get change data items, reverse-sorted by date (most recent first). """ interaction = getInteraction() head_wf = IWorkflow(self.head) changes = [] def append_visible_changes_on_item(item): permission = view_permission(item) for c in domain.get_changes(item, *self.param_audit_actions): if checkPermission(permission, c): changes.append(c) def include_feature_changes(feature_name, SUPPORTED_FEATURE): # !+ interfaces.IFeatureX.providedBy(self.head) return ( (not SUPPORTED_FEATURE or head_wf.has_feature(feature_name)) and feature_name in self.param_include_subtypes) def append_visible_changes_on_sub_items(sub_type_key, items_attr, SUPPORTED_FEATURE=True # !+ ): if include_feature_changes(sub_type_key, SUPPORTED_FEATURE): pid = "bungeni.%s.View" % (sub_type_key) items = [ item for item in getattr(self.head, items_attr) if interaction.checkPermission(pid, item) ] for item in items: append_visible_changes_on_item(item) # changes direct on head item append_visible_changes_on_item(self.head) # changes on sub-items append_visible_changes_on_sub_items("signatory", "sa_signatories") append_visible_changes_on_sub_items("attachment", "attachments") append_visible_changes_on_sub_items("event", "sa_events") if interfaces.IDoc.providedBy(self.head): append_visible_changes_on_sub_items("group_assignment", "sa_group_assignments") elif interfaces.IGroup.providedBy(self.head): append_visible_changes_on_sub_items("group_assignment", "sa_group_assignments", SUPPORTED_FEATURE=False) # !+ "group_assignment" is not a "group" feature append_visible_changes_on_sub_items("member", "group_members", SUPPORTED_FEATURE=False) # !+ "member" is not a "group" feature) # sort aggregated changes by date_active changes = [ dc[1] for dc in reversed(sorted([ (c.date_active, c) for c in changes ])) ] return changes '''
def __init__(self, context): self.head = removeSecurityProxy(context) self.head_workflow = IWorkflow(self.head) self.head_audit_feature = self.head_workflow.get_feature("audit")