Example #1
0
class GroupSittingsViewlet(browser.BungeniItemsViewlet):
    """Display the sittings of a group. 
    
    Note 1: to be able to customize the URL for each sitting, this custom 
    viewlet replaces the previous model-introspected container listing:
        class GroupSittingsViewlet(SubformViewlet):
            sub_attr_name = "sittings"
    so replacing a url of the form: 
            .../committees/obj-59/sittings/obj-17/
    with:   /business/sittings/obj-17
    
    Note 2: this viewlet should probably be merged or better share the 
    implementation at: ui.workspace.DraftSittingsViewlet
    
    !+CustomListingURL(mr, oct-2010) an alternative way to do this is to 
    essentially stuff all the logic below into a custom column_listing to be 
    used when listing the column -- for an example of this see how the 
    listing of the column "owner_id" (moved by) is configured in:
    descriptor.ParliamentaryItemDescriptor
    
    !+ManagedContainer(mr, oct-2010) this would have been a lot simpler if
    the Group.sittings attribute was simply returning the list of sitting
    objects.
    """

    # evoque
    render = z3evoque.ViewTemplateFile("workspace_viewlets.html#group_sittings")

    view_title = "Sittings"
    view_id = "sittings"

    def _get_items(self):
        def _format_from_to(item):
            start = item.start_date
            if start:
                start = dt_formatter.format(start)
            end = item.end_date
            if end:
                end = t_formatter.format(end)
            return u"%s - %s" % (start, end)
        dt_formatter = self.get_date_formatter("dateTime", "medium")
        t_formatter = self.get_date_formatter("time", "medium")
        def _format_venue(item):
            return item.venue and _(item.venue.short_name) or ""
        #
        trusted_context = removeSecurityProxy(self.context)
        sittings = Session().query(domain.GroupSitting
            ).filter(domain.GroupSitting.group == trusted_context
            ).order_by(domain.GroupSitting.start_date.desc())
        return [{"url": "/business/sittings/obj-%s" % (item.group_sitting_id),
                 "date_from_to": _format_from_to(item),
                 "venue": _format_venue(item)
                } for item in sittings ]

    def update(self):
        self.items = self._get_items()
Example #2
0
class MyInterestsViewlet(browser.BungeniItemsViewlet):
    """ Renders subscribed items
    """
    render = z3evoque.ViewTemplateFile("workspace_myinterests.html#interests")

    view_id = "my-interests"
    view_title = _("My interests")

    def __init__(self, context, request, view, manager):
        super(MyInterestsViewlet, self).__init__(context, request, view,
                                                 manager)
        self.site_url = absoluteURL(getSite(), self.request)

    def format_date(self, date):
        return self.get_date_formatter().format(date)

    def get_description(self, item):
        return item.description

    def get_title(self, item):
        return "%s %s %s" % (translate_obj(
            item.origin,
            self.request.locale.id.language).short_name, _(u"changes from"),
                             self.format_date(item.date_audit))

    def get_url(self, item):
        site = getSite()
        base_url = absoluteURL(site, self.request)
        return base_url + "/business/%ss/obj-%s" % (
            item.origin.type, item.origin.parliamentary_item_id)

    def update(self):
        """ Getting necessary items
        """
        session = Session()
        user = session.query(domain.User).filter(
            domain.User.login == self.request.principal.id).first()
        if user is None:
            self.items = []
        else:
            # Taking latest change from each item
            subscriptions = []
            map(
                lambda x: subscriptions.extend(
                    sorted(filter(
                        lambda change: change.action not in
                        [u'modified', u'added'], x.changes),
                           key=lambda x: x.date_audit,
                           reverse=True)[:1]), user.subscriptions)
            # Soring all items by date
            subscriptions.sort(key=lambda x: x.date_audit, reverse=True)
            self.items = [{
                'title': self.get_title(item),
                'url': self.get_url(item),
                'description': self.get_description(item)
            } for item in subscriptions]
Example #3
0
class WorkspaceViewletManager(WeightOrderedViewletManager):

    # evoque
    template = z3evoque.ViewTemplateFile("workspace.html#viewlet_manager")

    # zpt
    #template = ViewPageTemplateFile("templates/workspace.pt")

    def update(self):
        super(WorkspaceViewletManager, self).update()
Example #4
0
class OfficesHeldViewlet(browser.BungeniItemsViewlet):

    # evoque
    render = z3evoque.ViewTemplateFile("workspace_viewlets.html#offices_held")

    # zpt
    #render = ViewPageTemplateFile("templates/offices_held_viewlet.pt")

    view_title = "Offices held"
    view_id = "offices-held"

    def _get_items(self):
        formatter = self.get_date_formatter("date", "long")
        trusted = removeSecurityProxy(self.context)
        user_id = trusted.user_id
        office_list = []
        if interfaces.IMemberOfParliament.providedBy(self.context):
            parliament_id = trusted.group_id
        else:
            parliament = get_parliament_for_group_id(trusted.group_id)
            if parliament:
                parliament_id = parliament.parliament_id
            else:
                return office_list
        for oh in get_offices_held_for_user_in_parliament(
            user_id, parliament_id
        ):
            title = {}
            # !+FULL_NAME(mr, oct-2010) this should probably make use of 
            # the GroupDescriptor (combined) listing Field full_name
            title["group"] = "%s - %s" % (_(oh[0]), oh[1] and _(oh[1]) or "")
            title["group_type"] = _(oh[2])
            if oh[3]:
                title["member_title"] = _(oh[3])
            else:
                title["member_title"] = _(u"Member")
            title["start_date"] = None
            if oh[4]:
                title["start_date"] = formatter.format(oh[4])
            elif oh[6]:
                title["start_date"] = formatter.format(oh[6])
            title["end_date"] = None
            if oh[5]:
                title["end_date"] = formatter.format(oh[5])
            elif oh[7]:
                title["end_date"] = formatter.format(oh[7])
            office_list.append(title)
        return office_list

    def update(self):
        self.items = self._get_items()
Example #5
0
class ViewletBase(viewlet.ViewletBase):
    # evoque
    render = z3evoque.ViewTemplateFile("workspace_viewlets.html#items")

    # zpt
    #render = ViewPageTemplateFile("templates/workspace_item_viewlet.pt")

    def __init__(self, context, request, view, manager):
        super(ViewletBase, self).__init__(context, request, view, manager)
        self._data = None

    def getData(self):
        """return the data of the query."""
        return self._data
Example #6
0
class GlobalSectionsViewlet(browser.BungeniViewlet):

    # evoque
    render = z3evoque.ViewTemplateFile("navigation.html#sections")

    # zpt
    #render = ViewPageTemplateFile('templates/sections.pt')

    selected_portal_tab = None

    def update(self):
        context, request = self.context, self.request
        base_url = url.absoluteURL(getSite(), request)
        item_url = request.getURL()

        assert item_url.startswith(base_url)
        path = item_url[len(base_url):]

        self.portal_tabs = []
        seen = set()
        menu = component.getUtility(IBrowserMenu, "site_actions")

        def _action_is_on_path(action):
            return path.startswith("/".join(action.split("/")[0:-1]))

        """A menu item looks like this:
        {
            'extra': {'hideChildren': True, 'id': u''}, 
            'submenu': None, 
            'description': u'', 
            'title': u'Workspace', 
            'url': u'http://localhost:8081/', 
            'selected': u'selected', 
            'action': u'/', 
            'icon': None
        }
        """
        for item in menu.getMenuItems(context, request):
            if item['action'] in seen:
                continue
            seen.add(item['action'])
            item['url'] = item.setdefault('url', base_url + item['action'])
            item['id'] = item['action'].strip('/')
            item['name'] = item['title']
            self.portal_tabs.append(item)
            # take the last url-path matching action as selected_portal_tab
            if _action_is_on_path(item['action']):
                self.selected_portal_tab = item['id']
Example #7
0
class MemberItemsViewlet(browser.BungeniItemsViewlet):
    """A tab with bills, motions etc for an MP 
    (the "parliamentary activities" tab of of the "member" view)
    """
    states = \
        get_states("agendaitem", tagged=["public"]) + \
        get_states("bill", not_tagged=["private"]) + \
        get_states("motion", tagged=["public"]) + \
        get_states("question", tagged=["public"]) + \
        get_states("tableddocument", tagged=["public"])

    view_title = "Parliamentary activities"
    view_id = "mp-items"

    # evoque
    render = z3evoque.ViewTemplateFile("workspace_viewlets.html#mp_items")

    # zpt
    #render = ViewPageTemplateFile("templates/mp_item_viewlet.pt")

    def __init__(self, context, request, view, manager):
        super(MemberItemsViewlet, self).__init__(context, request, view,
                                                 manager)
        user_id = self.context.user_id
        parliament_id = self.context.group_id
        self.query = Session().query(domain.ParliamentaryItem).filter(
            sql.and_(
                domain.ParliamentaryItem.owner_id == user_id,
                domain.ParliamentaryItem.parliament_id == parliament_id,
                domain.ParliamentaryItem.status.in_(self.states),
            )).order_by(domain.ParliamentaryItem.parliamentary_item_id.desc())
        #self.for_display = (self.query.count() > 0)
        self.formatter = self.get_date_formatter("date", "medium")

    @property
    def items(self):
        for item in self.query.all():
            _url = "/business/%ss/obj-%i" % (item.type,
                                             item.parliamentary_item_id)
            yield {
                "type": item.type,
                "short_name": item.short_name,
                "status": misc.get_wf_state(item),
                "submission_date": item.submission_date,
                "url": _url
            }
Example #8
0
class WorkspaceContextNavigation(StructureAwareViewlet):
    
    # evoque
    render = z3evoque.ViewTemplateFile("workspace.html#context_navigation")
    
    # zpt
    #render = ViewPageTemplateFile('templates/workspace_context_navigation.pt')
    
    def update(self):
        # should only ever be called for contexts with these interfaces
        assert (IWorkspaceContainer.providedBy(self.context) or 
                IWorkspaceSectionContext.providedBy(self.context))
        self.sections = getMenu("workspace_context_navigation", 
                                                self.context, self.request)
        # get a translated copy of original workspace object
        workspace = translate_obj(
                misc.get_parent_with_interface(self, IWorkspaceContainer))
        self.workspace_title = workspace.full_name
Example #9
0
class GroupMembersViewlet(browser.BungeniItemsViewlet):

    # evoque
    render = z3evoque.ViewTemplateFile("workspace_viewlets.html#group_members")

    view_title = _("Members")
    view_id = "group-members"

    def _get_members(self):
        """Get the list of members of the context group.
        """
        raise NotImplementedError("Must be implemented by subclass.")

    @property
    def members_container_url(self):
        # !+traversal(murithi, mar-2010) ideally no urls should be
        # hardcoded here. absoluteURL should work for memberships or
        # members of groups [ to improve on getting urls of children ]
        if IAdminSectionLayer.providedBy(self.request):
            trusted = removeSecurityProxy(self.context)
            m_container = trusted.__parent__.__parent__.parliamentmembers
            return url.absoluteURL(m_container, self.request)
        return "/members/current"

    def update(self):
        session = Session()
        group_members = self._get_members()
        mpkls = domain.MemberOfParliament
        formatter = self.get_date_formatter("date", "long")
        self.items = [{
                "fullname": m.user.fullname,
                "url":
                    "%s/obj-%d/" % (self.members_container_url, 
                        session.query(mpkls).filter(
                                mpkls.user_id == m.user_id).one(
                            ).membership_id
                            ),
                "start_date":
                    m.start_date and formatter.format(m.start_date) or None,
                "end_date":
                    m.end_date and formatter.format(m.end_date) or None
            }
            for m in group_members
        ]
Example #10
0
class WorkspaceContextNavigation(StructureAwareViewlet):

    # evoque
    render = z3evoque.ViewTemplateFile("workspace.html#context_navigation",)

    # zpt
    #render = ViewPageTemplateFile("templates/workspace_context_navigation.pt")

    def update(self):
        # should only ever be called for contexts with these interfaces
        assert (IWorkspaceContainer.providedBy(self.context) or
                IWorkspaceSectionContext.providedBy(self.context))
        self.sections = getMenu("workspace_context_navigation",
                                                self.context, self.request)
        # Append a trailing slash to each workspace viewlet navigation entry so 
        # that the right context is always maintained when using this navigation.
        for section in self.sections:
            section["url"] = url.set_url_context(section["url"])

        # get a translated copy of original workspace object
        workspace = translate_obj(
                misc.get_parent_with_interface(self, IWorkspaceContainer))
        self.workspace_title = workspace.full_name
Example #11
0
class SchedulablesViewlet(browser.BungeniItemsViewlet):
    """Renders a portlet which calls upon the scheduling viewlet
    manager to render a list of schedulable items."""
    
    view_title = _(u"Scheduling")

    # the instance of the ViewProvideViewletManager
    provide = z3evoque.ViewProvideViewletManager()

    # evoque
    render = z3evoque.ViewTemplateFile("scheduling.html#main")
    # zpt
    #render = ViewPageTemplateFile("templates/scheduling.pt")

    for_display = True
    
    def __init__(self, context, request, view, manager):
        while not ISchedulingContext.providedBy(context):
            context = ISchedulingContext(context, context.__parent__)
            if context is None:
                raise RuntimeError("Unable to locate a scheduling context.")
        super(SchedulablesViewlet, self).__init__(
            context, request, view, manager)
Example #12
0
class SubformViewlet(table.AjaxContainerListing):
    """A container listing of the items indicated by "sub_attr_name". 
    """
    # evoque
    template = z3evoque.ViewTemplateFile("container.html#generic_sub")

    # zpt
    #template = ViewPageTemplateFile("templates/generic-sub-container.pt")
    def render(self):
        need("yui-datatable")
        return self.template()

    def __init__(self, context, request, view, manager):
        # The parent for SubformViewlets is the context (not the view)
        self.__parent__ = context
        self._context = context
        # !+_context(mr, oct-2010) using self.__parent__ to get to context
        # gives recursion error:
        # zope/publisher/browser.py", line 849, in __getParent
        # return getattr(self, '_parent', self.context)
        self.request = request
        self.manager = manager

    sub_attr_name = None

    @property
    def context(self):
        return getattr(self._context, self.sub_attr_name)

    @property
    def view_name(self):
        return self.sub_attr_name  # self.context.__name__

    @property
    def for_display(self):
        return len(self.context) > 0
Example #13
0
class DiffView(object):

    # evoque
    template = z3evoque.ViewTemplateFile("diff.html")
    context = None
    
    def __init__(self, source, target, request):
        self.source = source
        self.target = target
        self.request = request
    
    def __call__(self, *interfaces):
        results = diff(self.source, self.target, *interfaces)
        tables = []
        content_changed = False
        for (field, changed, hresult) in results:
            tables.append({
                "name": field.__name__,
                "title": field.title,
                "changed": changed,
                "html": hresult})
            if changed:
                content_changed = True
        return self.template(tables=tables, content_changed=content_changed)
Example #14
0
class WorkflowActionViewlet(browser.BungeniBrowserView, 
        BaseForm, viewlet.ViewletBase):
    """Display workflow status and actions."""
    
    # evoque
    render = z3evoque.ViewTemplateFile("form.html#form")
    
    # zpt
    #render = ViewPageTemplateFile("templates/viewlet.pt")
    
    class IWorkflowForm(zope.interface.Interface):
        note = zope.schema.Text(
            title=_("Comment on workflow change"), required=False)
        date_active = zope.schema.Datetime(
            title=_("Active Date"), required=True)
    form_name = "Workflow"
    form_fields = form.Fields(IWorkflowForm)
    note_widget = TextAreaWidget
    note_widget.height = 1
    form_fields["note"].custom_widget = note_widget
    form_fields["date_active"].custom_widget = TextDateTimeWidget
    actions = ()
    
    def get_min_date_active(self):
        """Determine the min_date_active to validate against.
        """
        def is_workflowed_and_draft(instance):
            """is item workflowed, and is so is it in a logical draft state?
            """
            if IWorkflowed.providedBy(instance):
                tagged_key = instance.__class__.__name__.lower()
                draft_states = get_states(tagged_key, tagged=["draft"])
                return instance.status in draft_states
            return False
        min_date_active = None
        if IAuditable.providedBy(self.context):
            instance = removeSecurityProxy(self.context)
            # !+PASTDATAENTRY(mr, jun-2011) offers a way to enter past data 
            # for workflowed items via the UI -- note, ideally we should be 
            # able to also control the item's creation active_date.
            #
            # If a workflowed item is in draft state, we do NOT take the 
            # date_active of its last change as the min_date_active, but
            # let that min fallback to parliament's creation date...
            if not is_workflowed_and_draft(instance):
                changes = [ change for change in instance.changes 
                    if change.action == "workflow" ]
                if changes:
     	            # then use the "date_active" of the most recent entry
                    min_date_active = changes[-1].date_active
        if not min_date_active:
            # fallback to current parliament's start_date (cast to a datetime)
            min_date_active = datetime.datetime.combine(
                globalsettings.get_current_parliament().start_date,
                datetime.time())
        # As the precision of the UI-submitted datetime is only to the minute, 
        # we adjust min_date_time by a margin of 59 secs earlier to avoid 
        # issues of doing 2 transitions in quick succession (within same minute) 
        # the 2nd of which could be taken to be too old...
        return min_date_active - datetime.timedelta(seconds=59)
    
    def validate(self, action, data):
        # submitted data is actually updated in following call to super.validate
        # !+PASTDATAENTRY(mr, jun-2011) enhancement? see Issue 612 Comment 6:
        # unrequire, allow active_date=None, 
        # get_effective_active_date -> last workflow non-None active_date
        errors = super(WorkflowActionViewlet, self).validate(action, data)
        if "date_active" in data.keys():
            min_date_active = self.get_min_date_active()
            if data.get("date_active") < min_date_active:
                errors.append(zope.interface.Invalid(
                    _("Active Date is too old.")))
            elif data.get("date_active") > datetime.datetime.now():
                errors.append(zope.interface.Invalid(
                    _("Active Date is in the future.")))
        return errors
    
    def setUpWidgets(self, ignore_request=False):
        class WorkflowForm:
            note = None
            date_active = None
        self.adapters = {
            self.IWorkflowForm: WorkflowForm,
        }
        self.widgets = form.setUpDataWidgets(
            self.form_fields, self.prefix, self.context, self.request,
            ignore_request=ignore_request)
    
    def update(self, transition=None):
        # !+RENAME(mr, apr-2011) should be transition_id
        workflow = interfaces.IWorkflow(self.context)
        if transition is not None:
            state_transition = workflow.get_transition(transition)
            state_title = translate(_bc(state_transition.title),
                                context=self.request)
            self.status = translate(_(
                u"Confirmation required for workflow transition: '${title}'",
                mapping={"title": state_title}), context = self.request)
        self.setupActions(transition)
        if not self.actions: 
            self.form_fields = self.form_fields.omit("note", "date_active")
        elif not IAuditable.providedBy(self.context):
            self.form_fields = self.form_fields.omit("note", "date_active")
        super(WorkflowActionViewlet, self).update()
    
    def setupActions(self, transition):
        # !+RENAME(mr, apr-2011) should be transition_id
        wfc = interfaces.IWorkflowController(self.context)
        if transition is None:
            transitions = wfc.getManualTransitionIds()
        else:
            transitions = (transition,)
        self.actions = bindTransitions(self, transitions, None, wfc.workflow)
        if IWorkspaceContainer.providedBy(self.context.__parent__):
            self._next_url = absoluteURL(self.context.__parent__, self.request)
Example #15
0
class WorkflowActionViewlet(browser.BungeniBrowserView, BaseForm,
                            viewlet.ViewletBase):
    """Display workflow status and actions."""

    # evoque
    render = z3evoque.ViewTemplateFile("form.html#form")

    # zpt
    #render = ViewPageTemplateFile("templates/viewlet.pt")

    class IWorkflowForm(zope.interface.Interface):
        note = zope.schema.Text(title=_("Comment on workflow change"),
                                required=False)
        date_active = zope.schema.Datetime(title=_("Active Date"),
                                           required=True)

    form_name = "Workflow"
    form_fields = form.Fields(IWorkflowForm)
    note_widget = TextAreaWidget
    note_widget.height = 1
    form_fields["note"].custom_widget = note_widget
    form_fields["date_active"].custom_widget = TextDateTimeWidget
    actions = ()

    def get_min_date_active(self):
        """Determine the min_date_active to validate against.
        """
        min_date_active = None
        if IAuditable.providedBy(self.context):
            instance = removeSecurityProxy(self.context)
            changes = [
                change for change in instance.changes
                if change.action == "workflow"
            ]
            if changes:
                # then use the "date_active" of the most recent entry
                min_date_active = changes[-1].date_active
        if not min_date_active:
            # then fallback to the current parliament's atart_date
            min_date_active = globalsettings.get_current_parliament(
            ).start_date
        # As the precision of the UI-submitted datetime is only to the minute,
        # we adjust min_date_time by a margin of 59 secs earlier to avoid
        # issues of doing 2 transitions in quick succession (within same minute)
        # the 2nd of which could be taken to be too old...
        return min_date_active - timedelta(seconds=59)

    def validate(self, action, data):
        # submitted data is actually updated in following call to super.validate
        errors = super(WorkflowActionViewlet, self).validate(action, data)
        if "date_active" in data.keys():
            min_date_active = self.get_min_date_active()
            if data.get("date_active") < min_date_active:
                errors.append(
                    zope.interface.Invalid(_("Active Date is too old.")))
            elif data.get("date_active") > datetime.now():
                errors.append(
                    zope.interface.Invalid(_("Active Date is in the future.")))
        return errors

    def setUpWidgets(self, ignore_request=False):
        class WorkflowForm:
            note = None
            date_active = None

        self.adapters = {
            self.IWorkflowForm: WorkflowForm,
        }
        self.widgets = form.setUpDataWidgets(self.form_fields,
                                             self.prefix,
                                             self.context,
                                             self.request,
                                             ignore_request=ignore_request)

    def update(self, transition=None):
        wf = interfaces.IWorkflow(self.context)
        if transition is not None:
            state_transition = wf.getTransitionById(transition)
            # !- workflow state title translations are in bungeni.core
            # use the right factory here to get translation
            state_title = translate(_bc(state_transition.title),
                                    context=self.request)
            self.status = translate(_(
                u"Confirmation required for workflow transition: '${title}'",
                mapping={"title": state_title}),
                                    context=self.request)
        self.setupActions(transition)
        if not self.actions:
            self.form_fields = self.form_fields.omit("note", "date_active")
        elif not IAuditable.providedBy(self.context):
            self.form_fields = self.form_fields.omit("note", "date_active")
        super(WorkflowActionViewlet, self).update()

    def setupActions(self, transition):
        self.wf = interfaces.IWorkflowInfo(self.context)
        if transition is None:
            transitions = self.wf.getManualTransitionIds()
        else:
            transitions = (transition, )
        self.actions = bindTransitions(self, transitions, None,
                                       interfaces.IWorkflow(self.context))
Example #16
0
class SchedulableItemsViewlet(browser.BungeniItemsViewlet):
    """Renders a list of schedulable items for a particular ``model``,
    filtered by workflow ``states``.

    Must subclass.
    """
    model = states = container = view_title = None
    
    # evoque
    render = z3evoque.ViewTemplateFile("scheduling.html#items")
    # zpt
    #render = ViewPageTemplateFile("templates/schedulable_items.pt")
    
    @property
    def app(self):
        parent = self.context.__parent__
        while parent is not None:
            if IBungeniApplication.providedBy(parent):
                return parent
            parent = parent.__parent__
        raise ValueError("Unable to locate application.")

    def group(self):
        parent = self.context.__parent__
        while parent is not None:
            if IBungeniGroup.providedBy(parent):
                return parent
            parent = parent.__parent__
        return None
        raise ValueError("Unable to locate application.")

    @property
    def visible(self):
        return not(ICommittee.providedBy(self.group()))
    
    def _query_items(self):
        return tuple(Session().query(self.model).filter(
                self.model.status.in_(self.states)))
    
    def _item_date(self, item):
        return item.status_date
    
    def _item_url(self, item):
        return url.set_url_context("%s/business/%ss/obj-%s" % (
                url.absoluteURL(getSite(), self.request), 
                item.type, 
                item.parliamentary_item_id))
    
    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": date_formatter.format(self._item_date(item)),
                "state": IWorkflow(item).get_state(item.status).title,
                "id": item.parliamentary_item_id,
                "class": (
                    (item.parliamentary_item_id 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 ]
        ]
Example #17
0
class BungeniAttributeDisplay(DynamicFields, form.SubPageDisplayForm,
                              browser.BungeniViewlet):
    """bungeni.subform.manager
    """

    # evoque
    render = z3evoque.ViewTemplateFile("form.html#display")
    # zpt
    #render = ViewPageTemplateFile("templates/display_form.pt")

    # the instance of the ViewProvideViewletManager
    provide = z3evoque.ViewProvideViewletManager(
        default_provider_name="bungeni.subform.manager")

    mode = "view"
    form_name = _(u"General")
    view_id = "display-item"
    has_data = True
    adapters = None

    def get_note(self):
        """Return Notes if supplied by context.
        """
        context = removeSecurityProxy(self.context)
        if getattr(context, "note", False):
            return context.note

    def setupActions(self):
        return  # !+ ??
        wfc = interfaces.IWorkflowController(self.context, None)
        if wfc is not None:
            transitions = wfc.getManualTransitionIds()
            self.actions = tuple(
                bindTransitions(self, transitions, wfc.workflow))

    def setUpWidgets(self, ignore_request=False):
        languages = get_all_languages()
        self.form_fields = filterFields(self.context, self.form_fields)

        #do not display empty form fields
        omit_names = []
        for f in self.form_fields:
            val = getattr(self.context, f.__name__)
            if val is None:
                omit_names.append(f.__name__)
        self.form_fields = self.form_fields.omit(*omit_names)
        context = self.context
        if ITranslatable.providedBy(self.context):
            lang = self.request.locale.getLocaleID()
            try:
                translation = get_translation_for(self.context, lang)
            except:
                translation = []
            if (not translation and getattr(self.context, "language", None)
                    and getattr(self.context, "language", None) != lang):
                supported_lang = languages.get(lang)
                if supported_lang:
                    langname = supported_lang.get("native", None)
                    if langname == None:
                        langname = supported_lang.get("name")
                    self.status = translate(
                        _(u"This content is not yet translated into" +\
                            " $language",
                            mapping={"language": langname}),
                        domain="bungeni",
                        context=self.request
                    )
            context = copy(removeSecurityProxy(self.context))
            for field_translation in translation:
                setattr(context, field_translation.field_name,
                        field_translation.field_text)
        self.widgets = form.setUpEditWidgets(self.form_fields,
                                             self.prefix,
                                             context,
                                             self.request,
                                             adapters=self.adapters,
                                             for_display=True,
                                             ignore_request=ignore_request)

    def update(self):
        self.setupActions()
        #super(BungeniAttributeDisplay, self).update()
        DynamicFields.update(self)
        self.setupActions()  # after we transition we have different actions
        try:
            self.wf_status = interfaces.IStateController(
                removeSecurityProxy(self.context)).get_status()
        except:
            pass

    @property
    def form_name(self):
        parent = self.context.__parent__
        #DESCRIPTOR(miano, June 2011) This originally first checked the parent's
        #descriptor then the item's descriptor. Why???
        #This was causing an error in the display pages of items in the
        #workspace since the workspace containers have no descriptor
        #defined for them.
        if IAlchemistContent.providedBy(self.context):
            descriptor = queryModelDescriptor(self.context.__class__)
        elif IAlchemistContainer.providedBy(parent):
            descriptor = queryModelDescriptor(parent.domain_model)
        else:
            raise RuntimeError("Unsupported object: %s." % repr(self.context))

        if descriptor:
            name = getattr(descriptor, "display_name", None)

        if name is None:
            name = self.context.__class__.__name__

        return name

    # !+RENAME get_object_class_name
    def getObjectClass(self):
        """Get the context object's class name. Called from the view template.
        """
        return self.context.__class__.__name__

    # !+ from ui.forms.common.BaseForm -- merge these 2 base classes?
    @property
    def invariantErrors(self):
        """ () -> [error:zope.interface.Invalid]
        """
        errors = []
        for error in self.errors:
            if isinstance(error, interface.Invalid):
                errors.append(error)
        return errors

    @property
    def invariantMessages(self):
        """ () -> [message:str]
        Called from the form.html#display template.
        """
        return filter(None, [error.message for error in self.invariantErrors])
Example #18
0
class TimeLineViewlet(browser.BungeniItemsViewlet):
    """
    tracker/timeline view:
    
    Chronological changes are aggregated from : bill workflow, bill
    audit, bill scheduling and bill event records. 
    """
    # evoque
    render = z3evoque.ViewTemplateFile("viewlets.html#timeline")

    # zpt
    #render = ViewPageTemplateFile("templates/timeline_viewlet.pt")

    # sqlalchemy give me a rough time sorting a union,
    # with hand coded sql it is much easier.
    # !+ get rid of the hard-coded sql
    sql_timeline = ""
    add_action = form.Actions(
        form.Action(_(u"add event"), success="handle_event_add_action"), )
    view_title = _("Timeline")
    view_id = "unknown-timeline"

    changes_getter = {
        "atype": lambda item: item.action,
        "adate": lambda item: item.date_active,
        "description": format_change_description,
        "notes": lambda item: "",
    }
    events_getter = {
        "atype": lambda item: "event",
        "adate": lambda item: item.event_date,
        "description": lambda item: "<a href='%s'>%s</a>" \
            %(url.absoluteURL(item, common.get_request()), item.short_name),
        "notes": lambda item: "",
    }

    def __init__(self, context, request, view, manager):
        super(TimeLineViewlet, self).__init__(context, request, view, manager)
        self.formatter = self.get_date_formatter("dateTime", "medium")

    def handle_event_add_action(self, action, data):
        self.request.response.redirect(self.addurl)

    def update(self):
        self.items = itertools.chain(*[
            load_formatted_container_items(self.context.changes,
                                           self.changes_getter),
            load_formatted_container_items(self.context.event,
                                           self.events_getter)
        ])
        self.items = sorted(self.items,
                            key=lambda item: item["adate"],
                            reverse=True)

    def update_sql(self):
        """Refresh the query.
        """

        #!+_TIMELINE(mb, aug-2011) to deprecate this function and use
        # sub-container listings as shown above to acess timeline items

        # evaluate serialization of a dict, failure returns an empty dict
        def _eval_as_dict(s):
            try:
                d = eval(s)
                assert isinstance(d, dict)
                return d
            except (SyntaxError, TypeError, AssertionError):
                #debug.log_exc(sys.exc_info(), log_handler=log.info)
                return {}

        # !+CHANGE_EXTRAS(mr, dec-2010)
        # only *Change records have an extras dict (as "notes" str attr) and the
        # content of this depends on the value of "atype" (see core/audit.py)
        item_id = self.context.parliamentary_item_id
        self.items = [
            dict(atype=action,
                 item_id=piid,
                 description=desc,
                 adate=date,
                 notes=_eval_as_dict(notes)) for action, piid, desc, date,
            notes in queries.execute_sql(self.sql_timeline, item_id=item_id)
        ]

        # Filter out workflow draft items for anonymous users
        if get_principal_id() in ("zope.anybody", ):
            _draft_states = ("draft", "working_draft")

            def show_timeline_item(item):
                if item["atype"] == "workflow":
                    if item["notes"].get("destination") in _draft_states:
                        return False
                return True

            self.items = [
                item for item in self.items if show_timeline_item(item)
            ]

        #change_cls = getattr(domain, "%sChange" % (self.context.__class__.__name__))
        for r in self.items:
            # workflow
            if r["atype"] == "workflow":
                # description
                # the workflow transition change log stores the (unlocalized)
                # human title for the transition's destination workflow state
                # -- here we just localize what is supplied:
                r["description"] = _(r["description"])
                # NOTE: we could elaborate an entirely custom description
                # from scratch e.g via interpolation of a template string:
                '''
                if r["notes"].get("destination", ""):
                    description = "%s %s" % (
                                _("some text"),
                                _(misc.get_wf_state(
                                    self.context, r["notes"]["destination"])))
                '''
            # event
            elif r["atype"] == "event":
                # description
                r["description"] = """<a href="event/obj-%s">%s</a>""" % (
                    r["item_id"], _(r["description"]))
            # version
            elif r["atype"] == "version":
                # description
                try:
                    r["description"] = """<a href="versions/obj-%s">%s</a>""" % (
                        r["notes"]["version_id"], _(r["description"]))
                except (KeyError, ):
                    # no recorded version_id, just localize what is supplied
                    r["description"] = _(r["description"])
        #
        path = url.absoluteURL(self.context, self.request)
        self.addurl = "%s/event/add" % (path)
Example #19
0
class SecondaryNavigationViewlet(browser.BungeniViewlet):

    # evoque
    render = z3evoque.ViewTemplateFile("navigation.html#secondary",
                                       i18n_domain="bungeni.core")

    # zpt
    #render = ViewPageTemplateFile("templates/secondary-navigation.pt")

    def update(self):
        request = self.request
        context = self.context
        chain = _get_context_chain(context)
        length = len(chain)
        self.items = []
        if length < 2:
            # there must be at least: [top-level section, application]
            return  # container is None
        else:
            # the penultimate context is the top-level container
            container = chain[-2]
            assert container.__name__ is not None
            if not IReadContainer.providedBy(container):
                return  # container has no readable content
        assert container is not None

        # add container items
        if length > 2:
            context = chain[-3]
        else:
            context = None
        self.add_container_menu_items(context, container)
        # add any menu items from zcml
        self.add_zcml_menu_items(container)

    def add_zcml_menu_items(self, container):
        """Add the list of ZCML menu items (if any) for this top-level 
        container. Top-level section given by container may define a menu 
        in ZCML with naming convention: <container_name>_navigation. 
        """
        # !+ turn this into a utility
        zcml_menu_name_template = "%s_navigation"
        try:
            menu_name = zcml_menu_name_template % container.__name__
            menu = component.getUtility(IBrowserMenu, name=menu_name)
            items = menu.getMenuItems(container, self.request)
        except (Exception, ):
            debug.log_exc(sys.exc_info(), log_handler=log.debug)
            return []
        # OK, do any necessary post-processing of each menu item
        local_url = url.absoluteURL(container, self.request)
        site_url = url.absoluteURL(getSite(), self.request)
        request_url = self.request.getURL()
        default_view_name = queryDefaultViewName(container, self.request)
        selection = None
        for item in sorted(items,
                           key=lambda item: item['action'],
                           reverse=True):
            action = item['action']
            if default_view_name == action.lstrip('@@'):
                _url = local_url
                if selection is None:
                    selected = sameProxiedObjects(container, self.context)
            else:
                _url = make_absolute(action, local_url, site_url)
                if selection is None:
                    selected = pos_action_in_url(action, request_url)
            item['url'] = _url
            item['selected'] = selected and u'selected' or u''
            if selected:
                # self is marker
                selection = self
                selected = False
            self.items.append(item)

    def add_container_menu_items(self, context, container):
        request = self.request
        # add a menu item for each user workspace, if we are in an
        # IWorkspaceSectionLayer
        # !+ if user is logged in or if request.layer_data

        if (interfaces.IWorkspaceSectionLayer.providedBy(request)
                or interfaces.IWorkspaceSchedulingSectionLayer.providedBy(
                    request)):
            try:
                workspaces = IAnnotations(request)["layer_data"].get(
                    "workspaces")
            except:
                workspaces = []
            log.info("%s got user workspaces: %s" % (self, workspaces))
            base_url_path = "/workspace"
            for workspace in workspaces:
                log.info("appending menu item for user workspace: %s" %
                         str(workspace))
                self.items.append(
                    url.get_menu_item_descriptor(
                        workspace.full_name,
                        pos_action_in_url(
                            "/workspace/obj-%s" % workspace.group_id,
                            request.getURL()), base_url_path,
                        "obj-%s" % workspace.group_id))

        _url = url.absoluteURL(container, request)

        if IReadContainer.providedBy(container):
            #XXX should be the same in all containers ?
            container = proxy.removeSecurityProxy(container)
            for name, item in container.items():
                if context is None:
                    selected = False
                else:
                    selected = url.same_path_names(context.__name__, name)
                item = proxy.removeSecurityProxy(item)
                if IDCDescriptiveProperties.providedBy(item):
                    title = item.title
                else:
                    props = IDCDescriptiveProperties(item)
                    title = props.title
                # only items with valid title
                if title is not None:
                    self.items.append(
                        url.get_menu_item_descriptor(title, selected, _url,
                                                     name))
        default_view_name = queryDefaultViewName(container, self.request)
        default_view = component.queryMultiAdapter((container, self.request),
                                                   name=default_view_name)
        if hasattr(default_view, "title") and default_view.title is not None:
            self.items.insert(
                0,
                url.get_menu_item_descriptor(
                    default_view.title,
                    sameProxiedObjects(container, self.context), _url))
Example #20
0
class WorkflowActionViewlet(browser.BungeniBrowserView, BaseForm,
                            viewlet.ViewletBase):
    """Display workflow status and actions."""
    class IWorkflowComment(zope.interface.Interface):
        note = zope.schema.Text(title=_("Comment on workflow change"),
                                required=False)
        date_active = zope.schema.Datetime(title=_("Active Date"),
                                           required=True)

        @zope.interface.invariant
        def valid_date_active(comment):
            request = common.get_request()
            # recover min_date_active, and adjust it to be 59 secs earlier to
            # avoid issues of doing 2 transitions in quick succession (within
            # the same minute) the 2nd of which could be taken to be too old...
            min_date_active = (IAnnotations(request)["min_date_active"] -
                               timedelta(seconds=59))
            if not hasattr(comment, "date_active"):
                # !+ because of a BUG in the datetime widget (probably) :
                # after a server restart, resubmitting a previously loaded
                # form -- that displays valid data_active value results in a
                # form.NoDataInput("date_active") error... thus causing:
                # (comment.date_active<min_date_active) to be False !
                raise zope.interface.Invalid(_("NoDataInput for Active Date."))
            elif comment.date_active < min_date_active:
                raise zope.interface.Invalid(_("Active Date is too old."))
            elif comment.date_active > datetime.now():
                raise zope.interface.Invalid(
                    _("Active Date is in the future."))

    class WorkflowComment(object):
        note = u""
        date_active = None

    form_name = "Workflow"
    form_fields = form.Fields(IWorkflowComment)  # [form.FormField]
    actions = ()

    # evoque
    render = z3evoque.ViewTemplateFile("form.html#form")

    # zpt
    #render = ViewPageTemplateFile("templates/viewlet.pt")

    def update(self, transition=None):
        self.adapters = {
            self.IWorkflowComment: self.WorkflowComment(),
        }
        wf = interfaces.IWorkflow(self.context)

        if transition is not None:
            state_transition = wf.getTransitionById(transition)
            self.status = _(
                u"Confirmation required for workflow transition: '${title}'",
                mapping={"title": _(state_transition.title)})

        self.setupActions(transition)
        super(WorkflowActionViewlet, self).update()

        # after we transition we have different actions
        self.setupActions(transition)
        # only display the notes field to comment if there is an action
        # and a log table
        auditor = audit.getAuditor(self.context)
        if len(self.actions) == 0:
            self.form_fields = self.form_fields.omit("note", "date_active")
        elif auditor is None:
            self.form_fields = self.form_fields.omit("note", "date_active")
        else:
            # note widget
            note_widget = TextAreaWidget
            note_widget.height = 1
            self.form_fields["note"].custom_widget = note_widget
            # date_active widget
            self.form_fields["date_active"].custom_widget = TextDateTimeWidget
            # !+ for "past data entry" mode, the default "date_active" value
            # should be gotten from a "pseudo_current_date" service utility
        self.setUpWidgets()
        # update form status in case of any errors
        # !+ follow the "bungeni descriptor schema_invariants" way of doing
        # this, i.e. displaying widget-specific errors next to each widget
        if self.errors:
            if self.status is None:
                self.status = _("Errors")
            self.status = "%s: %s " % (
                self.status,
                " / ".join([
                    e.message  #or e.__class__.__name__ 
                    for e in self.errors
                ]))

    def setupActions(self, transition):
        self.wf = interfaces.IWorkflowInfo(self.context)
        if transition is None:
            transitions = self.wf.getManualTransitionIds()
        else:
            transitions = (transition, )
        self.actions = bindTransitions(self, transitions, None,
                                       interfaces.IWorkflow(self.context))

    def setUpWidgets(self, ignore_request=False):
        # setup widgets in data entry mode not bound to context
        self.widgets = form.setUpDataWidgets(self.form_fields,
                                             self.prefix,
                                             self.context,
                                             self.request,
                                             ignore_request=ignore_request)
Example #21
0
class MyGroupsViewlet(WorkspaceViewlet):
    view_id = "my_groups"
    view_title = _("My Groups")

    # evoque
    render = z3evoque.ViewTemplateFile("workspace_viewlets.html#groups")
    # ZPT
    #render = ViewPageTemplateFile("templates/workspace_group_viewlet.pt")

    def _get_items(self):
        formatter = self.get_date_formatter("date", "long")
        data_list = []
        results = self.query.all()

        # if no current parliament, no data
        try:
            parliament_id = model_utils.get_current_parliament().parliament_id
        except:
            return data_list
        #
        government_id = self.__parent__.government_id
        for result in results:
            data = {}
            data["qid"] = "g_%s" % (result.group_id)
            data["subject"] = result.short_name
            data["title"] = "%s (%s)" % (result.short_name, result.type)
            data["result_item_class"] = "workflow-state-%s" % (result.status)
            _url = "/archive/browse/parliaments/obj-%s" % (parliament_id)
            if type(result) == domain.Parliament:
                data["url"] = url.set_url_context(_url)
                continue
            elif type(result) == domain.Committee:
                #data["url"] = url + "/committees/obj-" + str(result.group_id) 
                data["url"] = url.set_url_context("/groups/%s/%s" % (
                    result.parent_group.group_principal_id,
                    result.group_principal_id))
            elif type(result) == domain.PoliticalGroup:
                data["url"] = url.set_url_context(
                    "%s/politicalgroups/obj-%s" % (_url, result.group_id))
            elif type(result) == domain.Ministry:
                data["url"] = url.set_url_context(
                    "%s/governments/obj-%s/ministries/obj-%s" % (
                        _url, government_id, result.group_id))
            else:
                data["url"] = "#"
            data["status"] = misc.get_wf_state(result)
            data["status_date"] = formatter.format(result.status_date)
            data["owner"] = ""
            data["type"] = _(result.type)
            data["to"] = ""
            data_list.append(data)
        return data_list

    def update(self):
        """refresh the query
        """
        session = Session()
        #user_id = self.__parent__.user_id
        #parliament_id = self.__parent__.context.parliament_id
        group_ids = self.__parent__.user_group_ids
        gfilter = sql.and_(domain.Group.group_id.in_(group_ids),
                            domain.Group.status == "active")
        groups = session.query(domain.Group).filter(gfilter)
        self.query = groups
        self.items = self._get_items()
Example #22
0
class BreadCrumbsViewlet(browser.BungeniViewlet):
    """Breadcrumbs.
    
    Render the breadcrumbs to show a user his current location.
    """
    # evoque
    render = z3evoque.ViewTemplateFile("navigation.html#breadcrumbs")

    # zpt
    #render = ViewPageTemplateFile( 'templates/breadcrumbs.pt' )

    def __init__(self, context, request, view, manager):
        self.context = context
        self.request = request
        self.__parent__ = view
        self.manager = manager
        self.path = []
        self.site_url = url.absoluteURL(getSite(), self.request)
        self.user_name = ''

    def _get_path(self, context):
        """Return the current path as a list
        """
        descriptor = None
        name = None
        path = []

        context = proxy.removeSecurityProxy(context)
        if context is None:
            return path
        # Proof-of-concept: support for selective inclusion in breadcrumb trail:
        # a view marked with an attribute __crumb__=False is NOT included in
        # the breadcrumb trail (see core/app.py: "workspace" Section)
        if not getattr(context, "__crumb__", True):
            return path
        if context.__parent__ is not None:
            path.extend(self._get_path(context.__parent__))

        _url = url.absoluteURL(context, self.request)

        # Append a trailing slash to each breadcrumb entry so that
        # the right context is always maintained when the breadcrumbs
        # are used for navigation.
        _url = url.set_url_context(_url)

        title = _get_title_from_context(context)

        if title is not None:
            path.append({'name': title, 'url': _url})

        return path

    def update(self):
        self.path = self._get_path(self.context)

        # if the view is a location, append this to the breadcrumbs
        if ILocation.providedBy(self.__parent__) and \
               IDCDescriptiveProperties.providedBy(self.__parent__):
            self.path.append({
                'name': self.__parent__.title,
                'url': None,
            })
        try:
            self.user_name = self.request.principal.login
        except:
            pass
Example #23
0
class DraftSittingsViewlet(WorkspaceViewlet):
    """The "agendas/minutes" tab in the workspace/pi view for the Clerk.
    """

    # evoque
    render = z3evoque.ViewTemplateFile("workspace_viewlets.html#sittings")

    # zpt
    #render = ViewPageTemplateFile("templates/workspace_sitting_viewlet.pt")

    view_id = "sitting-draft"
    view_title = _("agendas/minutes")
    states = get_states("groupsitting", tagged=["workspace"])

    def _get_items(self):
        data_list = []
        results = self.query.all()
        formatter = self.get_date_formatter("date", "long")
        time_formatter = self.get_date_formatter("time", "short")
        for result in results:
            data = {}
            data["subject"] = result.short_name
            # this tab appears in the workspace pi/ view...
            data["url"] = url.set_url_context(
                "../../scheduling/sittings/obj-%i/schedule" % result.group_sitting_id)
            # Note: same UI is also displayed at: 
            # /business/sittings/obj-%i/schedule % result.group_sitting_id
            data["items"] = ""
            data["status"] = misc.get_wf_state(result)
            data["status_date"] = formatter.format(result.status_date)
            data["owner"] = ""
            data["type"] = result.group.type
            data["group"] = u"%s %s" % (
                    result.group.type.capitalize(), result.group.short_name)
            data["time_from_to"] = (
                    time_formatter.format(result.start_date),
                    time_formatter.format(result.end_date))
            data["date"] = formatter.format(result.start_date)
            if result.venue:
                data["venue"] = _(result.venue.short_name)
            #else:
            #    date["venue"] = ""
            if type(result) == domain.Question:
                data["to"] = result.ministry.short_name
            else:
                data["to"] = ""
            # past, present, future
            today = datetime.datetime.today().date()
            startday = result.start_date.date()
            if today == startday:
                data["css_class"] = "present"
            elif today > startday:
                data["css_class"] = "past"
            else:
                data["css_class"] = "future"
            data_list.append(data)
        return data_list

    def update(self):
        """Refresh the query
        """
        session = Session()
        qfilter = domain.GroupSitting.status.in_(self.states)
        sittings = session.query(domain.GroupSitting).filter(
                qfilter).order_by(domain.GroupSitting.start_date.desc()
                    ).options(
                eagerload("group")
                )
        self.query = sittings
        self.items = self._get_items()
Example #24
0
class TimeLineViewlet(viewlet.ViewletBase):
    """
    tracker/timeline view:
    
    Chronological changes are aggregated from : bill workflow, bill
    audit, bill scheduling and bill event records. 
    """
    # evoque
    render = z3evoque.ViewTemplateFile("workspace_viewlets.html#timeline")

    # zpt
    #render = ViewPageTemplateFile('templates/timeline_viewlet.pt')

    # sqlalchemy give me a rough time sorting a union,
    # with hand coded sql it is much easier.
    # !+ get rid of the hard-coded sql
    sql_timeline = ""
    add_action = form.Actions(
        form.Action(_(u'add event'), success='handle_event_add_action'), )
    for_display = True
    view_name = "Timeline"
    view_id = "unknown-timeline"

    def __init__(self, context, request, view, manager):
        self.context = context
        self.request = request
        self.__parent__ = view
        self.manager = manager
        self.query = None
        self.formatter = date.getLocaleFormatter(self.request, "dateTime",
                                                 "medium")

    def handle_event_add_action(self, action, data):
        self.request.response.redirect(self.addurl)

    def update(self):
        """Refresh the query.
        """

        # evaluate serialization of a dict, failure returns an empty dict
        def _eval_as_dict(s):
            try:
                d = eval(s)
                assert isinstance(d, dict)
                return d
            except (SyntaxError, TypeError, AssertionError):
                #debug.log_exc(sys.exc_info(), log_handler=log.info)
                return {}

        # NOTE: only *Change records have a "notes" dict attribute and the
        # content of this depends on the value of "atype" (see core/audit.py)
        item_id = self.context.parliamentary_item_id
        self.results = [
            dict(atype=action,
                 item_id=piid,
                 description=desc,
                 adate=date,
                 notes=_eval_as_dict(notes)) for action, piid, desc, date,
            notes in queries.execute_sql(self.sql_timeline, item_id=item_id)
        ]

        # Filter out workflow draft items for anonymous users
        if get_principal_id() in ("zope.anybody", ):
            _draft_states = ("draft", "working_draft")

            def show_timeline_item(result):
                if result["atype"] == "workflow":
                    if result["notes"].get("destination") in _draft_states:
                        return False
                return True

            self.results = [
                result for result in self.results if show_timeline_item(result)
            ]

        #change_cls = getattr(domain, "%sChange" % (self.context.__class__.__name__))
        for r in self.results:
            # workflow
            if r["atype"] == "workflow":
                # description
                # the workflow transition change log stores the (unlocalized)
                # human title for the transition's destination workflow state
                # -- here we just localize what is supplied:
                r["description"] = _(r["description"])
                # NOTE: we could elaborate an entirely custom description
                # from scratch e.g via interpolation of a template string:
                '''
                if r["notes"].get("destination", ""):
                    description = "%s %s" % (
                                _("some text"),
                                _(misc.get_wf_state(
                                    self.context, r["notes"]["destination"])))
                '''
            # event
            elif r["atype"] == "event":
                # description
                r["description"] = """<a href="event/obj-%s">%s</a>""" % (
                    r["item_id"], _(r["description"]))
            # version
            elif r["atype"] == "version":
                # description
                try:
                    r["description"] = """<a href="versions/obj-%s">%s</a>""" % (
                        r["notes"]["version_id"], _(r["description"]))
                except (KeyError, ):
                    # no recorded version_id, just localize what is supplied
                    r["description"] = _(r["description"])
        #
        path = url.absoluteURL(self.context, self.request)
        self.addurl = '%s/event/add' % (path)
Example #25
0
class WorkspaceViewlet(browser.BungeniItemsViewlet):

    # evoque
    render = z3evoque.ViewTemplateFile("workspace_viewlets.html#items")