def getSchedulingContexts(self): """Set up scheduling contexts. Currently we include: - committees - plenary """ contexts = [] app = getSite() today = datetime.date.today() committees = app[u"business"]["committees"].values() user_id = get_db_user_id() for committee in committees: if user_id: if ((committee.end_date is None or committee.end_date >= today) and (committee.start_date is None or committee.start_date <= today) and checkPermission("bungeni.agendaitem.Add", committee) and (committee.status == "active")): contexts.append(schedule.CommitteeSchedulingContext(committee)) else: if ((committee.end_date is None or committee.end_date >= today) and (committee.start_date is None or committee.start_date <= today) and (committee.status == "active")): contexts.append(schedule.CommitteeSchedulingContext(committee)) contexts.append(schedule.PlenarySchedulingContext(app)) for context in contexts: context.__name__ = u"calendar" return contexts
def getDefaultVocabularyValue(self): user_id = get_db_user_id() try: self.context.vocabulary.getTerm(user_id) except LookupError: return None return user_id
def is_consented_signatory(self, user_id=None): user_id = user_id or model_utils.get_db_user_id() if user_id: return user_id in [ sgn.user_id for sgn in filter( lambda cs: cs.status in SIGNATORY_CONSENTED_STATES, self.signatories) ] return False
def is_consented_signatory(self, user_id=None): user_id = user_id or model_utils.get_db_user_id() if user_id: return user_id in [ sgn.user_id for sgn in filter( lambda cs:cs.status in SIGNATORY_CONSENTED_STATES, self.signatories) ] return False
def handle_save(self, action, data): report = domain.Report() session = Session() report.body_text = data["body_text"] report.start_date = data["start_date"] report.end_date = data["end_date"] report.note = data["note"] report.report_type = data["report_type"] report.short_name = data["report_type"] owner_id = get_db_user_id() '''!+TODO(Miano, 18/08/2010) The admin user is currently not a db user thus the line above returns None when the admin publishes a report. to go around this if it returns None, just query the db for users and set the owner id to be the first result''' if owner_id is not None: report.owner_id = owner_id else: query = session.query(domain.User) results = query.all() report.owner_id = results[0].user_id report.language = "en" report.created_date = datetime.datetime.now() report.group_id = self.context.group_id session.add(report) notify(ObjectCreatedEvent(report)) # !+INVALIDATE(mr, sep-2010) container.invalidate_caches_for("Report", "add") if "sittings" in data.keys(): try: ids = data["sittings"].split(",") for id_number in ids: sit_id = int(id_number) sitting = session.query(domain.GroupSitting).get(sit_id) sr = domain.SittingReport() sr.report = report sr.sitting = sitting session.add(sr) # !+INVALIDATE(mr, sep-2010) via an event... container.invalidate_caches_for("SittingReport", "add") except: #if no sittings are present in report or some other error occurs pass session.commit() if IGroupSitting.providedBy(self.context): back_link = "./schedule" elif ISchedulingContext.providedBy(self.context): back_link = "./" else: raise NotImplementedError self.request.response.redirect(back_link)
def handle_save(self, action, data): report = domain.Report() session = Session() report.body_text = data["body_text"] report.start_date = data["start_date"] report.end_date = data["end_date"] report.note = data["note"] report.short_name = report.short_name = data["short_name"] owner_id = get_db_user_id() '''!+TODO(Miano, 18/08/2010) The admin user is currently not a db user thus the line above returns None when the admin publishes a report. to go around this if it returns None, just query the db for users and set the owner id to be the first result''' if owner_id is not None: report.owner_id = owner_id else: query = session.query(domain.User) results = query.all() report.owner_id = results[0].user_id # TODO get language from config report.language = "en" report.created_date = datetime.datetime.now() report.group_id = self.context.group_id session.add(report) notify(ObjectCreatedEvent(report)) # !+INVALIDATE(mr, sep-2010) container.invalidate_caches_for("Report", "add") if "sittings" in data.keys(): try: ids = data["sittings"].split(",") for id_number in ids: sit_id = int(id_number) sitting = session.query(domain.GroupSitting).get(sit_id) sr = domain.SittingReport() sr.report = report sr.sitting = sitting session.add(sr) # !+INVALIDATE(mr, sep-2010) via an event... container.invalidate_caches_for("SittingReport", "add") except: #if no sittings are present in report or some other error occurs pass session.commit() if IGroupSitting.providedBy(self.context): back_link = "./schedule" elif ISchedulingContext.providedBy(self.context): back_link = "./" else: raise NotImplementedError self.request.response.redirect(back_link)
def constructQuery(self, context): mp_query = super(MemberOfParliamentDelegationSource, self).constructQuery(context) #XXX clerks cannot yet choose MPs freely user_id = utils.get_db_user_id() if user_id: user_ids = [user_id] for result in delegation.get_user_delegations(user_id): user_ids.append(result.user_id) query = mp_query.filter( domain.MemberOfParliament.user_id.in_(user_ids)) if len(query.all()) > 0: return query return mp_query
def __call__(self): request = self.request context = self.context user_id = get_db_user_id() signatories = context.signatories _filters = {"user_id": user_id} _signatories = signatories.query(**_filters) if len(_signatories) == 1: signatory = _signatories[0] _signatory = signatories.get(signatory.signatory_id) review_url = "/".join( (url.absoluteURL(_signatory, request), u"workflow") ) return request.response.redirect(review_url)
def publishTraverse(self, request, name): # Shortcut for current user workspace if name == u"profile": session = Session() user_id = get_db_user_id(self.context) user = session.query(User)\ .filter(User.user_id==user_id).first() if user is not None: user.__parent__ = self.context user.__name__ = "profile" return user else: return NotFound(self.context, name, request) return super(ProfileTraverser, self).publishTraverse(request, name)
def getSchedulingContexts(self, request): """Set up scheduling contexts. Currently we include: - committees - plenary """ contexts = [] app = getSite() today = datetime.date.today() if interfaces.IWorkspaceSchedulingSectionLayer.providedBy(request): committees = app["workspace"]["scheduling"]["committees"].values() else: committees = app["business"]["committees"].values() user_id = get_db_user_id() for committee in committees: if user_id: if ((committee.end_date is None or committee.end_date >= today) and (committee.start_date is None or committee.start_date <= today) and checkPermission("bungeni.agendaitem.Add", committee) and (committee.status == "active")): contexts.append(schedule.CommitteeSchedulingContext( committee)) else: if ((committee.end_date is None or committee.end_date >= today) and (committee.start_date is None or committee.start_date <= today) and (committee.status == "active")): contexts.append(schedule.CommitteeSchedulingContext( committee)) for context in contexts: context.__name__ = u"schedule" if interfaces.IWorkspaceSchedulingSectionLayer.providedBy(request): contexts.append(schedule.ISchedulingContext( app["workspace"]["scheduling"])) else: contexts.append(schedule.ISchedulingContext( app["business"]["sittings"])) contexts[-1].__name__ = u"" return contexts
def constructQuery(self, context): session = Session() trusted = removeSecurityProxy(context) user_id = getattr(trusted, 'owner_id', None) if user_id is None: user_id = utils.get_db_user_id() parliament_id = self._get_parliament_id(context) if user_id: query = session.query(PartyMembership).filter( sql.and_(PartyMembership.active_p == True, PartyMembership.user_id == user_id, PartyMembership.parent_group_id == parliament_id)) else: query = session.query(domain.PoliticalGroup).filter( domain.PoliticalGroup.parent_group_id == parliament_id) return query
def handle_save(self, action, data): report = domain.Report() session = Session() report.body_text = data['body_text'] report.start_date = data['start_date'] report.end_date = data['end_date'] report.note = data['note'] report.report_type = data['report_type'] report.short_name = data['report_type'] owner_id = get_db_user_id() '''!+TODO(Miano, 18/08/2010) The admin user is currently not a db user thus the line above returns None when the admin publishes a report. to go around this if it returns None, just query the db for users and set the owner id to be the first result''' if owner_id is not None: report.owner_id = owner_id else: query = session.query(domain.User) results = query.all() report.owner_id = results[0].user_id report.language = "en" report.created_date = datetime.datetime.now() report.group_id = self.context.group_id session.add(report) notify(ObjectCreatedEvent(report)) ids = data["sittings"].split(",") for id in ids: try: sit_id = int(id) except: continue sitting = session.query(domain.GroupSitting).get(sit_id) sr = domain.SittingReport() sr.report = report sr.sitting = sitting session.add(sr) session.commit() if IGroupSitting.providedBy(self.context): back_link = './schedule' elif ISchedulingContext.providedBy(self.context): back_link = './' else: raise NotImplementedError self.request.response.redirect(back_link)
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 constructQuery(self, context): session= Session() trusted=removeSecurityProxy(context) user_id = getattr(trusted, 'owner_id', None) if user_id is None: user_id = utils.get_db_user_id() parliament_id = self._get_parliament_id(context) if user_id: query = session.query(PartyMembership ).filter( sql.and_(PartyMembership.active_p == True, PartyMembership.user_id == user_id, PartyMembership.parent_group_id == parliament_id) ) else: query = session.query(domain.PoliticalGroup).filter( domain.PoliticalGroup.parent_group_id == parliament_id) return query
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 handle_publish(self, action, data): self.generated_content = self.generateContent(data) if not hasattr(self.context, "group_id"): context_group_id = ISchedulingContext(self.context).group_id else: context_group_id = self.context.group_id report = domain.Report(short_name=self.title, start_date=self.start_date, end_date=self.end_date, body_text=self.generated_content, owner_id=get_db_user_id(), language=self.language, group_id=context_group_id) session = Session() session.add(report) session.flush() self.status = _(u"Report has been processed and saved") return self.template()
def handle_save(self, action, data): report = domain.Report() session = Session() report.body_text = data["body_text"] report.start_date = data["start_date"] report.end_date = data["end_date"] report.note = data["note"] report.short_name = data["short_name"] report.owner_id = get_db_user_id() report.language = get_default_language() report.created_date = datetime.datetime.now() if not hasattr(self.context, "group_id"): report.group_id = ISchedulingContext(self.context).group_id else: report.group_id = self.context.group_id session.add(report) session.flush() notify(ObjectCreatedEvent(report)) if "sittings" in data.keys(): try: ids = data["sittings"].split(",") for id_number in ids: sit_id = int(id_number) sitting = session.query(domain.GroupSitting).get(sit_id) sr = domain.SittingReport() sr.report = report sr.sitting = sitting session.add(sr) notify(ObjectCreatedEvent(report)) except: #if no sittings are present in report or some other error occurs pass session.flush() if IGroupSitting.providedBy(self.context): back_link = "./schedule" else: back_link = "./" self.request.response.redirect(back_link)
def handle_publish(self, action, data): self.generated_content = self.generateContent(data) if not hasattr(self.context, "group_id"): context_group_id = ISchedulingContext(self.context).group_id else: context_group_id = self.context.group_id report = domain.Report(short_name = self.title, start_date = self.start_date, end_date = self.end_date, body_text = self.generated_content, owner_id = get_db_user_id(), language = self.language, group_id = context_group_id ) session = Session() session.add(report) session.flush() self.status = _(u"Report has been processed and saved") return self.template()
def __call__(self): session = Session() # Current logged in user id user_id = get_db_user_id(self.context) # Looking if there is appropriate object to store # currently editing document data currently_editing_document = session.query(CurrentlyEditingDocument)\ .filter(CurrentlyEditingDocument.user_id == user_id)\ .first() # If not creating one for the current user if not currently_editing_document: currently_editing_document = CurrentlyEditingDocument() currently_editing_document.user_id = user_id session.add(currently_editing_document) # Assigning current document id document_id = self.context.doc_id currently_editing_document.currently_editing_id = document_id # And the current date and time current_datetime = datetime.now() ago_datetime = current_datetime - timedelta(seconds=20) currently_editing_document.editing_date = current_datetime # Fetching amount of users that are being editing the document # taking into account that last time the ajax request was sent # no longer than 20 seconds ago count = session.query(CurrentlyEditingDocument)\ .filter(CurrentlyEditingDocument.currently_editing_id == document_id)\ .filter(CurrentlyEditingDocument.user_id != user_id)\ .filter(CurrentlyEditingDocument.editing_date.between(ago_datetime, current_datetime))\ .count() # Returning the amount, excluding current document editing return str(count)
def __call__(self): session = Session() # Current logged in user id user_id = get_db_user_id(self.context) # Looking if there is appropriate object to store # currently editing document data currently_editing_document = session.query(CurrentlyEditingDocument)\ .filter(CurrentlyEditingDocument.user_id == user_id)\ .first() # If not creating one for the current user if not currently_editing_document: currently_editing_document = CurrentlyEditingDocument() currently_editing_document.user_id = user_id session.add(currently_editing_document) # Assigning current document id document_id = self.context.parliamentary_item_id currently_editing_document.currently_editing_id = document_id # And the current date and time current_datetime = datetime.now() ago_datetime = current_datetime - timedelta(seconds=20) currently_editing_document.editing_date = current_datetime # Fetching amount of users that are being editing the document # taking into account that last time the ajax request was sent # no longer than 20 seconds ago count = session.query(CurrentlyEditingDocument)\ .filter(CurrentlyEditingDocument.currently_editing_id == document_id)\ .filter(CurrentlyEditingDocument.user_id != user_id)\ .filter(CurrentlyEditingDocument.editing_date.between(ago_datetime, current_datetime))\ .count() # Returning the amount, excluding current document editing return str(count)
def getSchedulingContexts(self): """Set up scheduling contexts. Currently we include: - committees - plenary """ contexts = [] app = getSite() today = datetime.date.today() committees = app[u"business"]["committees"].values() user_id = get_db_user_id() for committee in committees: if user_id: if ((committee.end_date is None or committee.end_date >= today) and (committee.start_date is None or committee.start_date <= today) and checkPermission("bungeni.agendaitem.Add", committee) and (committee.status == "active")): contexts.append( schedule.CommitteeSchedulingContext(committee)) else: if ((committee.end_date is None or committee.end_date >= today) and (committee.start_date is None or committee.start_date <= today) and (committee.status == "active")): contexts.append( schedule.CommitteeSchedulingContext(committee)) contexts.append(schedule.PlenarySchedulingContext(app)) for context in contexts: context.__name__ = u"calendar" return contexts
def handle_sign_document(self, action, data): user_id = get_db_user_id() manager = ISignatoryManager(self.context) manager.sign_document(user_id) self.request.response.redirect(self.nextURL())
def _objectChanged(self, change_kind, object, description="", extras=None, date_active=None): """ description: this is a non-localized string as base description of the log item, offers a (building block) for the description of this log item. UI components may use this in any of the following ways: - AS IS, optionally localized - as a building block for an elaborated description e.g. for generating descriptions that are hyperlinks to an event or version objects - ignore it entirely, and generate a custom description via other means e.g. from the "notes" extras dict. extras: !+CHANGE_EXTRAS(mr, dec-2010) a python dict, containing "extra" information about the log item, with the "key/value" entries depending on the change "action"; Specific examples, for actions: workflow: self.objectStateChanged() source destination transition comment new-version: self.objectNewVersion() version_id modified: self.objectModified() comment For now, this dict is serialized (using repr(), values are assumed to be simple strings or numbers) as the value of the notes column, for storing in the db--but if and when the big picture of these extra keys is understood clearly then the changes table may be redesigned to accomodate for a selection of these keys as real table columns. date_active: the UI for some changes allow the user to manually set the date_active -- this is what should be used as the *effective* date i.e. the date to be used for all intents and purposes other than for data auditing. When not user-modified, the value should be equal to date_audit. """ oid, otype = self._getKey(object) user_id = get_db_user_id() assert user_id is not None, _("Audit error. No user logged in.") session = Session() change = self.change_object() change.action = change_kind change.date_audit = datetime.now() if date_active: change.date_active = date_active else: change.date_active = change.date_audit change.user_id = user_id change.description = description change.extras = extras change.content_type = otype change.origin = object session.add(change) session.flush() return change.change_id
def __init__(self, *args, **kwargs): super(ChangePasswordForm, self).__init__(*args, **kwargs) self.session = Session() user_id = get_db_user_id(self.context) self.user = self.session.query(User)\ .filter(User.user_id==user_id).first()
def _can_review_signature(self, action): manager = ISignatoryManager(self.context) return manager.is_signatory(get_db_user_id())
def is_signatory(self, user_id=None): user_id = user_id or model_utils.get_db_user_id() if user_id: return user_id in [sgn.user_id for sgn in self.signatories] return False
def _object_changed(self, action, ob, description="", extras=None, date_active=None): """ description: this is a non-localized string as base description of the log item, offers a (building block) for the description of this log item. UI components may use this in any of the following ways: - AS IS, optionally localized - as a building block for an elaborated description e.g. for generating descriptions that are hyperlinks to an event or version objects - ignore it entirely, and generate a custom description via other means e.g. from the "notes" extras dict. extras: !+CHANGE_EXTRAS(mr, dec-2010) a python dict, containing "extra" information about the log item, with the "key/value" entries depending on the change "action"; Specific examples, for actions: workflow: self.object_workflow() source destination transition comment version: self.object_version() version_id modify: self.object_modify() comment For now, this dict is serialized (using repr(), values are assumed to be simple strings or numbers) as the value of the notes column, for storing in the db--but if and when the big picture of these extra keys is understood clearly then the changes table may be remodeled with dedicated table columns. date_active: the UI for some changes allow the user to manually set the date_active -- this is what should be used as the *effective* date i.e. the date to be used for all intents and purposes other than for data auditing. When not user-modified, the value should be equal to date_audit. """ domain.assert_valid_change_action(action) oid, otype = self._getKey(ob) user_id = get_db_user_id() assert user_id is not None, "Audit error. No user logged in." session = Session() change = self.change_class() change.action = action change.date_audit = datetime.now() if date_active: change.date_active = date_active else: change.date_active = change.date_audit change.user_id = user_id change.description = description change.extras = extras change.content_type = otype change.head = ob # attach change to parent object change.status = ob.status # remember parent's status at time of change # !+SUBITEM_CHANGES_PERMISSIONS(mr, jan-2012) permission on change # records for something like item[@draft]->file[@attached]->fileversion # need to remember also the root item's state, else when item later # becomes visible to clerk and others, the file itself will also become # visible to the clerk (CORRECT) but so will ALL changes on the file # while that file itself was @attached (WRONG!). May best be addressed # when change persistence is reworked along with single document table. session.add(change) session.flush() log.debug("AUDITED [%s] %s" % (action, change.__dict__)) return change.change_id
def _object_changed( self, action, ob, date_active=None, note=None, procedure="a", ): """ date_active: the UI for some changes allow the user to manually set the date_active -- this is what should be used as the *effective* date i.e. the date to be used for all intents and purposes other than for data auditing. When not user-modified, the value should be equal to date_audit. """ domain.assert_valid_change_action(action) user_id = get_db_user_id() assert user_id is not None, "Audit error. No user logged in." # carry over a snapshot of head values def get_field_names_to_audit(kls): names_to_audit = [] table = self.audit_table for column in table.columns: # skip all fields starting with "audit_" if column.name.startswith("audit_"): continue # ok, column must therefore be a proper attribute from ob's class assert column.name in kls.__dict__, \ "Not in class: %s" % column.name # skip all primary keys (audit_head_id managed separately) if column.primary_key: continue names_to_audit.append(column.name) for vp_name, vp_type in kls.extended_properties: names_to_audit.append(vp_name) return names_to_audit def copy_field_values(head_cls, source, dest): for name in get_field_names_to_audit(head_cls): setattr(dest, name, getattr(source, name)) # ensure real head object, in case we are dealing with reversioning # off an Audit instance head_ob = ob if action == "version" and issubclass(ob.__class__, domain.Audit): # ob is an Audit instance, so need its head_ob head_ob = ob.audit_head # audit snapshot - done first, to ensure a valid audit_id... au = self.audit_class() au.audit_head = head_ob # attach audit log item to parent object copy_field_values(head_ob.__class__, ob, au) session = Session() session.add(au) # change/audit record # !+version Version instances are created as Change instances! ch = domain.Change() ch.seq = 0 # !+ reset below, to avoid sqlalchemy violates not-null constraint ch.audit = au # ensures ch.audit_id, ch.note.object_id ch.user_id = user_id ch.action = action ch.seq = self._get_seq(ch) ch.procedure = procedure ch.date_audit = datetime.now() if date_active: ch.date_active = date_active else: ch.date_active = ch.date_audit if note: ch.note = note # !+SUBITEM_CHANGES_PERMISSIONS(mr, jan-2012) permission on change # records for something like item[@draft]->file[@attached]->fileversion # need to remember also the root item's state, else when item later # becomes visible to clerk and others, the file itself will also become # visible to the clerk (CORRECT) but so will ALL changes on the file # while that file itself was @attached (WRONG!). May best be addressed # when change persistence is reworked along with single document table. session.flush() log.debug("AUDIT [%s] %s" % (au, au.__dict__)) log.debug("CHANGE [%s] %s" % (action, ch.__dict__)) return ch
def prepare_user_workspaces(event): """Determine the current principal's workspaces, depending on roles and group memberships. "bungeni.Clerk", "bungeni.Speaker", "bungeni.MP" these roles get a parliament-level workspace "bungeni.Minister" "implied" role (by being a member of a ministry group) gets a ministry-level workspace (for each ministry) "zope.Manager", "bungeni.Admin", "bungeni.Owner", "bungeni.Everybody", "bungeni.Anybody" not relevant for user workspaces, no workspaces !+ should these get an owner-level (user) workspace? """ request = event.request application = event.object # is bungeni.core.app.BungeniApp destination_url_path = url.get_destination_url_path(request) def need_to_prepare_workspaces(obj, req): return ( # need only to do it when traversing "/", # obj should be the BungeniApplication model_interfaces.IBungeniApplication.providedBy(obj) and # user is logged in interfaces.IBungeniAuthenticatedSkin.providedBy(req) and ( # either the request should be for a view within /workspace # note: IWorkspaceSectionLayer is applied to the request by # publication.apply_request_layer_by_url() that therefore must # have already been called interfaces.IWorkspaceSectionLayer.providedBy(req) or interfaces.IWorkspaceSchedulingSectionLayer.providedBy(req) or # or the request is for *the* Home Page (as in this case # we still need to know the user workspaces to be able to # redirect appropriately) interfaces.IHomePageLayer.providedBy(req) ) ) if not need_to_prepare_workspaces(application, request): return # initialize a layer data object, for the views in the layer LD = IAnnotations(request)["layer_data"] = misc.bunch( workspaces=[], # workspace containers !+ unique? # !+ role-based workspaces: (role|group, workspace_container) # these are needed by the views, as we need them also here, we just # remember them to not need to calculate them again user_id=None, user_group_ids=None, government_id=None, ministries=None, # list of ministries (that are also workspaces) ) LD.user_id = get_db_user_id() try: parliament = get_current_parliament(None) assert parliament is not None # force exception # we do get_roles under the current parliament as context, but we # must also ensure that the BungeniApp is present somewhere along # the __parent__ stack: parliament.__parent__ = application roles = get_roles(parliament) # "bungeni.Clerk", "bungeni.Speaker", "bungeni.MP" for role_id in roles: if role_id in ("bungeni.Clerk", "bungeni.Speaker", "bungeni.MP"): log.debug("adding parliament workspace %s (for role %s)" % ( parliament, role_id)) LD.workspaces.append(parliament) # "bungeni.Minister" # need to check for ministry groups to which the principal belongs, and # for each such ministry assign a ministry workspace LD.user_group_ids = get_group_ids_for_user_in_parliament( LD.user_id, parliament.group_id) LD.government_id = get_current_parliament_governments( parliament)[0].group_id # IndexError LD.ministries = get_ministries_for_user_in_government( LD.user_id, LD.government_id) log.debug(""" [prepare_user_workspaces] user_id:%s roles:%s parliament:(%s, %s) government_id:%s ministries:%s""" % ( LD.user_id, roles, parliament.full_name, parliament.group_id, LD.government_id, [(m.full_name, m.group_id) for m in LD.ministries] )) for ministry in LD.ministries: log.debug("adding ministry workspace %s" % ministry) LD.workspaces.append(ministry) except (Exception,): debug.log_exc_info(sys.exc_info(), log_handler=log.info) # ensure unique workspaces, preserving order, retaining same list obj ref LD.workspaces[:] = [ workspace for i,workspace in enumerate(LD.workspaces) if LD.workspaces.index(workspace)==i ] # mark each workspace container with IWorkspaceContainer for workspace in LD.workspaces: interface.alsoProvides(workspace, interfaces.IWorkspaceContainer) log.debug(debug.interfaces(workspace)) log.debug(" [prepare_user_workspaces] %s" % debug.interfaces(request)) log.info(""" [prepare_user_workspaces] DONE: for: [request=%s][path=%s][path_info=%s] request.layer_data: %s""" % ( id(request), destination_url_path, request.get("PATH_INFO"), IAnnotations(request).get("layer_data", None)))
def _object_changed(self, action, ob, date_active=None, note=None, procedure="a", ): """ date_active: the UI for some changes allow the user to manually set the date_active -- this is what should be used as the *effective* date i.e. the date to be used for all intents and purposes other than for data auditing. When not user-modified, the value should be equal to date_audit. """ domain.assert_valid_change_action(action) user_id = get_db_user_id() assert user_id is not None, "Audit error. No user logged in." # carry over a snapshot of head values def get_field_names_to_audit(kls): names_to_audit = [] table = self.audit_table for column in table.columns: # skip all fields starting with "audit_" if column.name.startswith("audit_"): continue # ok, column must therefore be a proper attribute from ob's class assert column.name in kls.__dict__, \ "Not in class: %s" % column.name # skip all primary keys (audit_head_id managed separately) if column.primary_key: continue names_to_audit.append(column.name) for vp_name, vp_type in kls.extended_properties: names_to_audit.append(vp_name) return names_to_audit def copy_field_values(head_cls, source, dest): for name in get_field_names_to_audit(head_cls): setattr(dest, name, getattr(source, name)) # ensure real head object, in case we are dealing with reversioning # off an Audit instance head_ob = ob if action == "version" and issubclass(ob.__class__, domain.Audit): # ob is an Audit instance, so need its head_ob head_ob = ob.audit_head # audit snapshot - done first, to ensure a valid audit_id... au = self.audit_class() au.audit_head = head_ob # attach audit log item to parent object copy_field_values(head_ob.__class__, ob, au) session = Session() session.add(au) # change/audit record # !+version Version instances are created as Change instances! ch = domain.Change() ch.seq = 0 # !+ reset below, to avoid sqlalchemy violates not-null constraint ch.audit = au # ensures ch.audit_id, ch.note.object_id ch.user_id = user_id ch.action = action ch.seq = self._get_seq(ch) ch.procedure = procedure ch.date_audit = datetime.now() if date_active: ch.date_active = date_active else: ch.date_active = ch.date_audit if note: ch.note = note # !+SUBITEM_CHANGES_PERMISSIONS(mr, jan-2012) permission on change # records for something like item[@draft]->file[@attached]->fileversion # need to remember also the root item's state, else when item later # becomes visible to clerk and others, the file itself will also become # visible to the clerk (CORRECT) but so will ALL changes on the file # while that file itself was @attached (WRONG!). May best be addressed # when change persistence is reworked along with single document table. session.flush() log.debug("AUDIT [%s] %s" % (au, au.__dict__)) log.debug("CHANGE [%s] %s" % (action, ch.__dict__)) return ch
def workspace_search(self): """ Search in workspace section, based on views from bungeni.ui.viewlets.workspace """ application = common.get_application() parliament = get_current_parliament(None) parliament.__parent__ = application principal = get_principal() roles = common.get_context_roles(parliament, principal) # minister role, filtering by states and object_type and ministry_id if not roles: user_id = get_db_user_id() government_id = get_current_parliament_governments( parliament)[0].group_id ministries = get_ministries_for_user_in_government( user_id, government_id) if ministries: states = workspace.MinistryArchiveViewlet.states + \ workspace.OralMinistryQuestionsViewlet.states + \ workspace.WrittenMinistryQuestionsViewlet.states + \ workspace.InProgressMinistryItemsViewlet.states states = set(states) ministry_ids = [m.group_id for m in ministries] # filter by object_type (questions only) type_query = self.searcher.query_field('object_type', "Question") query = self.searcher.query_composite(self.searcher.OP_AND, \ (self.query, type_query,)) subqueries = [] for state in states: subqueries.append( self.searcher.query_field('status', state)) state_query = self.searcher.query_composite( self.searcher.OP_OR, subqueries) query = self.searcher.query_composite(self.searcher.OP_AND, \ (query, state_query,)) #filter for ministries ministries_queries = [] for mid in ministry_ids: ministries_queries.append( self.searcher.query_field('ministry_id', str(mid))) m_query = self.searcher.query_composite( self.searcher.OP_OR, ministries_queries) query = self.searcher.query_composite(self.searcher.OP_AND, \ (query, m_query,)) try: results = self.searcher.search( query, 0, self.searcher.get_doccount()) except: results = [] return list(results) # filtering by states and owner if 'bungeni.MP' in roles: states = workspace.MPItemActionRequiredViewlet.states + \ workspace.MPItemDraftViewlet.states + \ workspace.MPItemInProgressViewlet.states + \ workspace.ItemArchiveViewlet.states states = set(states) # filter by owner of PI owner_query = self.searcher.query_field('owner', str(get_db_user_id())) query = self.searcher.query_composite(self.searcher.OP_AND, \ (self.query, owner_query,)) subqueries = [] for state in states: subqueries.append(self.searcher.query_field('status', state)) state_query = self.searcher.query_composite( self.searcher.OP_OR, subqueries) query = self.searcher.query_composite(self.searcher.OP_AND, \ (query, state_query,)) try: results = self.searcher.search(query, 0, self.searcher.get_doccount()) except: results = [] return list(results) # filtering by states if 'bungeni.Clerk' in roles: states = workspace.ClerkItemActionRequiredViewlet.states + \ workspace.ClerkItemsWorkingDraftViewlet.states + \ workspace.ClerkReviewedItemViewlet.states + \ workspace.ItemsApprovedViewlet.states + \ workspace.ItemsPendingScheduleViewlet.states + \ workspace.ItemsScheduledViewlet.states + \ workspace.AllItemArchiveViewlet.states states = set(states) subqueries = [] for state in states: subqueries.append(self.searcher.query_field('status', state)) state_query = self.searcher.query_composite( self.searcher.OP_OR, subqueries) query = self.searcher.query_composite(self.searcher.OP_AND, \ (self.query, state_query,)) try: results = self.searcher.search(query, 0, self.searcher.get_doccount()) except: results = [] return list(results) # no results return False
def prepare_user_workspaces(event): """Determine the current principal's workspaces, depending on roles and group memberships. "bungeni.Clerk", "bungeni.Speaker", "bungeni.MP" these roles get a parliament-level workspace "bungeni.Minister" "implied" role (by being a member of a ministry group) gets a ministry-level workspace (for each ministry) "zope.Manager", "bungeni.Admin", "bungeni.Owner", "bungeni.Authenticated", "bungeni.Anonymous" not relevant for user workspaces, no workspaces !+ should these get an owner-level (user) workspace? """ request = event.request application = event.object # is bungeni.core.app.BungeniApp destination_url_path = url.get_destination_url_path(request) def need_to_prepare_workspaces(obj, req): return ( # need only to do it when traversing "/", # obj should be the BungeniApplication model_interfaces.IBungeniApplication.providedBy(obj) and # user is logged in interfaces.IBungeniAuthenticatedSkin.providedBy(req) and ( # either the request should be for a view within /workspace # note: IWorkspaceSectionLayer is applied to the request by # publication.apply_request_layer_by_url() that therefore must # have already been called interfaces.IWorkspaceSectionLayer.providedBy(req) or interfaces.IWorkspaceSchedulingSectionLayer.providedBy(req) or # or the request is for *the* Home Page (as in this case # we still need to know the user workspaces to be able to # redirect appropriately) interfaces.IHomePageLayer.providedBy(req))) if not need_to_prepare_workspaces(application, request): return # initialize a layer data object, for the views in the layer LD = IAnnotations(request)["layer_data"] = misc.bunch( workspaces=[], # workspace containers !+ unique? # !+ role-based workspaces: (role|group, workspace_container) # these are needed by the views, as we need them also here, we just # remember them to not need to calculate them again user_id=None, user_group_ids=None, government_id=None, ministries=None, # list of ministries (that are also workspaces) ) LD.user_id = get_db_user_id() try: parliament = get_current_parliament(None) assert parliament is not None # force exception # we do get_context_roles under the current parliament as context, but # we must also ensure that the BungeniApp is present somewhere along # the __parent__ stack: parliament.__parent__ = application roles = common.get_context_roles(parliament) # "bungeni.Clerk", "bungeni.Speaker", "bungeni.MP" for role_id in roles: if role_id in ("bungeni.Clerk", "bungeni.Speaker", "bungeni.MP"): log.debug("adding parliament workspace %s (for role %s)" % (parliament, role_id)) LD.workspaces.append(parliament) # "bungeni.Minister" # need to check for ministry groups to which the principal belongs, and # for each such ministry assign a ministry workspace LD.user_group_ids = get_group_ids_for_user_in_parliament( LD.user_id, parliament.group_id) LD.government_id = get_current_parliament_governments( parliament)[0].group_id # IndexError LD.ministries = get_ministries_for_user_in_government( LD.user_id, LD.government_id) log.debug( """ [prepare_user_workspaces] user_id:%s roles:%s parliament:(%s, %s) government_id:%s ministries:%s""" % (LD.user_id, roles, parliament.full_name, parliament.group_id, LD.government_id, [(m.full_name, m.group_id) for m in LD.ministries])) for ministry in LD.ministries: log.debug("adding ministry workspace %s" % ministry) LD.workspaces.append(ministry) except (Exception, ): debug.log_exc_info(sys.exc_info(), log_handler=log.info) # ensure unique workspaces, preserving order, retaining same list obj ref LD.workspaces[:] = [ workspace for i, workspace in enumerate(LD.workspaces) if LD.workspaces.index(workspace) == i ] # mark each workspace container with IWorkspaceContainer for workspace in LD.workspaces: interface.alsoProvides(workspace, interfaces.IWorkspaceContainer) log.debug(debug.interfaces(workspace)) log.debug(" [prepare_user_workspaces] %s" % debug.interfaces(request)) log.info(""" [prepare_user_workspaces] DONE: for: [request=%s][path=%s][path_info=%s] request.layer_data: %s""" % (id(request), destination_url_path, request.get("PATH_INFO"), IAnnotations(request).get("layer_data", None)))
def is_signatory(self, user_id=None): user_id = user_id or model_utils.get_db_user_id() if user_id: return user_id in [ sgn.user_id for sgn in self.signatories ] return False
def workspace_search(self): """ Search in workspace section, based on views from bungeni.ui.viewlets.workspace """ application = common.get_application() parliament = get_current_parliament(None) parliament.__parent__ = application principal = get_principal() roles = common.get_context_roles(parliament, principal) # minister role, filtering by states and object_type and ministry_id if not roles: user_id = get_db_user_id() government_id = get_current_parliament_governments(parliament)[0].group_id ministries = get_ministries_for_user_in_government(user_id, government_id) if ministries: states = workspace.MinistryArchiveViewlet.states + \ workspace.OralMinistryQuestionsViewlet.states + \ workspace.WrittenMinistryQuestionsViewlet.states + \ workspace.InProgressMinistryItemsViewlet.states states = set(states) ministry_ids = [m.group_id for m in ministries] # filter by object_type (questions only) type_query = self.searcher.query_field('object_type', "Question") query = self.searcher.query_composite(self.searcher.OP_AND, \ (self.query, type_query,)) subqueries = [] for state in states: subqueries.append(self.searcher.query_field('status', state)) state_query = self.searcher.query_composite(self.searcher.OP_OR, subqueries) query = self.searcher.query_composite(self.searcher.OP_AND, \ (query, state_query,)) #filter for ministries ministries_queries = [] for mid in ministry_ids: ministries_queries.append(self.searcher.query_field('ministry_id', str(mid))) m_query = self.searcher.query_composite(self.searcher.OP_OR, ministries_queries) query = self.searcher.query_composite(self.searcher.OP_AND, \ (query, m_query,)) try: results = self.searcher.search(query, 0, self.searcher.get_doccount()) except: results = [] return list(results) # filtering by states and owner if 'bungeni.MP' in roles: states = workspace.MPItemActionRequiredViewlet.states + \ workspace.MPItemDraftViewlet.states + \ workspace.MPItemInProgressViewlet.states + \ workspace.ItemArchiveViewlet.states states = set(states) # filter by owner of PI owner_query = self.searcher.query_field('owner', str(get_db_user_id())) query = self.searcher.query_composite(self.searcher.OP_AND, \ (self.query, owner_query,)) subqueries = [] for state in states: subqueries.append(self.searcher.query_field('status', state)) state_query = self.searcher.query_composite(self.searcher.OP_OR, subqueries) query = self.searcher.query_composite(self.searcher.OP_AND, \ (query, state_query,)) try: results = self.searcher.search(query, 0, self.searcher.get_doccount()) except: results = [] return list(results) # filtering by states if 'bungeni.Clerk' in roles: states = workspace.ClerkItemActionRequiredViewlet.states + \ workspace.ClerkItemsWorkingDraftViewlet.states + \ workspace.ClerkReviewedItemViewlet.states + \ workspace.ItemsApprovedViewlet.states + \ workspace.ItemsPendingScheduleViewlet.states + \ workspace.ItemsScheduledViewlet.states + \ workspace.AllItemArchiveViewlet.states states = set(states) subqueries = [] for state in states: subqueries.append(self.searcher.query_field('status', state)) state_query = self.searcher.query_composite(self.searcher.OP_OR, subqueries) query = self.searcher.query_composite(self.searcher.OP_AND, \ (self.query, state_query,)) try: results = self.searcher.search(query, 0, self.searcher.get_doccount()) except: results = [] return list(results) # no results return False