Beispiel #1
0
class WorkflowView(browser.BungeniBrowserView):

    # evoque
    template = z3evoque.PageViewTemplateFile("workflow.html#main")

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

    _page_title = "Workflow"

    def update(self, transition=None):
        # set up viewlets; the view is rendered from viewlets for
        # historic reasons; this may be refactored anytime.
        self.history_viewlet = WorkflowHistoryViewlet(self.context,
                                                      self.request, self, None)
        self.action_viewlet = WorkflowActionViewlet(self.context, self.request,
                                                    self, None)
        # update viewlets
        self.history_viewlet.update()
        self.action_viewlet.update(transition=transition)

    def __call__(self):
        self.update()
        # NOTE: the success_handler for the parent form is at:
        #   bungeni.ui.forms.workflow.TransitionHandler
        # To get the form data:
        #   av = self.action_viewlet
        #   data = {}
        #   form.getWidgetsData(av.widgets, av.prefix, data)
        template = self.template()
        return template
Beispiel #2
0
class AjaxContainerListing(container.ContainerListing,
                           browser.BungeniBrowserView):
    """Container listing as an HTML Page.
    """
    formatter_factory = yuiwidget.ContainerDataTableFormatter

    # evoque
    template = z3evoque.PageViewTemplateFile("container.html#generic")

    def __call__(self):
        self.update()
        return self.template()

    @property
    def form_name(self):
        dm = self.context.domain_model
        return getattr(model.queryModelDescriptor(dm), "container_name",
                       dm.__name__)

    @property
    def prefix(self):
        return "container_contents"

    @property
    def formatter(self):
        context = proxy.removeSecurityProxy(self.context)
        formatter = self.formatter_factory(context,
                                           self.request, (),
                                           prefix=self.prefix,
                                           columns=self.columns)
        formatter.cssClasses["table"] = "listing"
        formatter.table_id = "datacontents"
        return formatter
Beispiel #3
0
class WorkflowView(browser.BungeniBrowserView):
    """This view is linked to by the "workflow" context action and dislays the 
    workflow history and the action viewlet with all possible transitions
    """
    # evoque
    template = z3evoque.PageViewTemplateFile("workflow.html#main")
    
    # zpt
    #template = ViewPageTemplateFile("templates/workflow.pt")
    
    _page_title = "Workflow"
    
    def update(self, transition=None):
        # !+RENAME(mr, apr-2011) should be transition_id
        #
        # set up viewlets; the view is rendered from viewlets for
        # historic reasons; this may be refactored anytime.
        if IAuditable.providedBy(self.context):
            self.history_viewlet = WorkflowHistoryViewlet(
                self.context, self.request, self, None)
            self.history_viewlet.update()
        self.action_viewlet = WorkflowActionViewlet(
            self.context, self.request, self, None)
        self.action_viewlet.update(transition=transition)
    
    def __call__(self):
        self.update()
        template = self.template()
        return template
Beispiel #4
0
class WorkflowChangeStateView(WorkflowView):
    """This gets called on selection of a transition from the menu i.e. NOT:
    a) when clicking on one of the transition buttons in the workflow form.
    b) when clicking Add of an object (automatic transitions).
    """

    # evoque
    ajax_template = z3evoque.PageViewTemplateFile("workflow.html#ajax")

    # zpt
    #ajax_template = ViewPageTemplateFile("templates/workflow_ajax.pt")

    def __call__(self, transition_id=None, headless=False):
        # parameters coming in via URL querystring or post vars !
        method = self.request["REQUEST_METHOD"]
        # !+ALWAYS_POST(mr, sep-2011) requests coming from link clicks (GETs)
        # from the bungeni Web UI seem to always be intercepted and switched
        # into POSTs.
        workflow = interfaces.IWorkflow(self.context)

        require_confirmation = True
        if transition_id is not None:
            self.update(transition_id)
            require_confirmation = workflow.get_transition(
                transition_id).require_confirmation
        else:
            self.update()

        if get_mask(
                self.context) == 'manual' and not self.context.registry_number:
            require_confirmation = True

        if (not require_confirmation and method == "POST"):
            actions = bindTransitions(self.action_viewlet, (transition_id, ),
                                      workflow)
            assert len(actions) == 1
            # execute action
            # !+ should pass self.request.form as data? e.g. value is:
            # {u"next_url": u"...", u"transition": u"submit_response"}
            result = actions[0].success({})
            # !+UNUSED(mr, jun-2011) this result is never used!

        if headless:
            actions = get_actions("context_workflow", self.context,
                                  self.request)
            state_title = workflow.get_state(self.context.status).title
            result = self.ajax_template(actions=actions,
                                        state_title=state_title)
            if require_confirmation:
                self.request.response.setStatus(403)
            else:
                self.request.response.setStatus(200)
                self.request.response.setResult(result)
                self.request.response.setHeader("Content-Type", "text/xml")
            return result

        template = self.template()
        return template
Beispiel #5
0
class DisplayForm(catalyst.DisplayForm, browser.BungeniBrowserView):

    template = z3evoque.PageViewTemplateFile("content.html#view")
    #template = ViewPageTemplateFile("templates/content-view.pt")

    form_name = _("View")

    def __call__(self):
        return self.template()
Beispiel #6
0
class WorkflowChangeStateView(WorkflowView):
    """This gets called on selection of a transition from the menu i.e. NOT:
    a) when clicking on one of the trasition buttons in the workflow form.
    b) when clicking Add of an object (automatic transitions).
    """

    # evoque
    ajax_template = z3evoque.PageViewTemplateFile("workflow.html#ajax")

    # zpt
    #ajax_template = ViewPageTemplateFile("templates/workflow_ajax.pt")

    def __call__(self, headless=False, transition=None):
        # !+RENAME(mr, apr-2011) should be transition_id
        method = self.request["REQUEST_METHOD"]
        workflow = interfaces.IWorkflow(self.context)

        # !+REWITE(mr, jun-2011) the following needs to be rewritten!
        if transition:
            state_transition = workflow.get_transition(transition)
            require_confirmation = getattr(state_transition,
                                           "require_confirmation", False)
            self.update(transition)
        else:
            self.update()

        if transition and require_confirmation is False and method == "POST":
            actions = bindTransitions(self.action_viewlet, (transition, ),
                                      None, workflow)
            assert len(actions) == 1
            # execute action
            # !+ should pass self.request.form as data? e.g. value is:
            # {u"next_url": u"...", u"transition": u"submit_response"}
            result = actions[0].success({})
            # !+REWITE(mr, jun-2011) this result is never used!

        if headless is True:
            actions = get_actions("context_workflow", self.context,
                                  self.request)
            state_title = workflow.get_state(self.context.status).title
            result = self.ajax_template(actions=actions,
                                        state_title=state_title)

            # !+REWITE(mr, jun-2011) require_confirmation only defined when
            # transition is True!
            if require_confirmation is True:
                self.request.response.setStatus(403)
            else:
                self.request.response.setStatus(200)
                self.request.response.setResult(result)
                self.request.response.setHeader("Content-Type", "text/xml")

            return result

        template = self.template()
        return template
Beispiel #7
0
class WorkspaceSectionView(browser.BungeniBrowserView):

    # evoque
    __call__ = z3evoque.PageViewTemplateFile("workspace.html#section_page")

    # zpt
    #__call__ = ViewPageTemplateFile("templates/workspace-section.pt")

    # set on request.layer_data
    user_id = None
    user_group_ids = None
    government_id = None
    ministries = None

    role_interface_mapping = {
        u'bungeni.Admin': interfaces.IAdministratorWorkspace,
        u'bungeni.Minister': interfaces.IMinisterWorkspace,
        u'bungeni.MP': interfaces.IMPWorkspace,
        u'bungeni.Speaker': interfaces.ISpeakerWorkspace,
        u'bungeni.Clerk': interfaces.IClerkWorkspace
    }

    def __init__(self, context, request):
        """self:zope.app.pagetemplate.simpleviewclass.SimpleViewClass -> 
                    templates/workspace-index.pt
           context:bungeni.core.content.Section
        """
        LD = IAnnotations(request)["layer_data"]
        assert interfaces.IWorkspaceSectionLayer.providedBy(request)
        assert LD.get("workspaces") is not None
        super(WorkspaceSectionView, self).__init__(context, request)
        cls_name = self.__class__.__name__
        # NOTE: Zope morphs this class's name to "SimpleViewClass from ..."
        log.debug("%s.__init__ %s context=%s url=%s" %
                  (cls_name, self, self.context, request.getURL()))

        # transfer layer data items, for the view/template
        self.user_id = LD.user_id
        self.user_group_ids = LD.user_group_ids
        self.government_id = LD.government_id  # may be None
        self.ministries = LD.ministries  # may be None
        if self.ministries:
            # then, ONLY if an ancestor container is actually a Ministry,
            # this must be a MinisterWorkspace
            if misc.get_parent_with_interface(self,
                                              model_interfaces.IMinistry):
                interface.alsoProvides(self, interfaces.IMinisterWorkspace)

        # roles are function of the context, so always recalculate
        roles = common.get_context_roles(self.context)
        for role_id in roles:
            iface = self.role_interface_mapping.get(role_id)
            if iface is not None:
                interface.alsoProvides(self, iface)
        log.debug("%s.__init__ %s" % (cls_name, debug.interfaces(self)))
Beispiel #8
0
class WorkflowChangeStateView(WorkflowView):
    """This gets called on selection of a transition from the menu i.e. NOT
    when clicking on one of the trasition buttons in the workflow form.
    """

    # evoque
    ajax_template = z3evoque.PageViewTemplateFile("workflow.html#ajax")

    # zpt
    #ajax_template = ViewPageTemplateFile("templates/workflow_ajax.pt")

    def __call__(self, headless=False, transition=None):
        method = self.request["REQUEST_METHOD"]
        if transition:
            wf = interfaces.IWorkflow(self.context)
            state_transition = wf.getTransitionById(transition)
            require_confirmation = getattr(state_transition,
                                           "require_confirmation", False)
            self.update(transition)
        else:
            self.update()

        if transition and require_confirmation is False and method == "POST":
            actions = bindTransitions(self.action_viewlet, (transition, ),
                                      None, interfaces.IWorkflow(self.context))
            assert len(actions) == 1
            # execute action
            # !+ should pass self.request.form as data? e.g. value is:
            # {u"next_url": u"...", u"transition": u"submit_response"}
            result = actions[0].success({})

        if headless is True:
            actions = get_actions("context_workflow", self.context,
                                  self.request)
            state_title = IWorkflowInfo(
                self.context).workflow().workflow.states[
                    self.context.status].title
            result = self.ajax_template(actions=actions,
                                        state_title=state_title)

            if require_confirmation is True:
                self.request.response.setStatus(403)
            else:
                self.request.response.setStatus(200)
                self.request.response.setResult(result)
                self.request.response.setHeader("Content-Type", "text/xml")

            return result

        template = self.template()
        return template
Beispiel #9
0
class ChangeLog(ChangeBaseView, zope.publisher.browser.BrowserPage):
    """Change Log View for an object
    """

    # evoque
    __call__ = z3evoque.PageViewTemplateFile("audit.html#changes")

    # zpt
    #__call__ = ViewPageTemplateFile("templates/changes.pt")

    _page_title = "Change Log"

    def __init__(self, context, request):
        super(ChangeLog, self).__init__(context, request)
        if hasattr(self.context, "short_name"):
            self._page_title = "%s: %s" % (_(
                self._page_title), _(self.context.short_name))
Beispiel #10
0
class ReorderForm(PageForm):
    """Item reordering form.

    We use an intermediate list of ids to represent the item order.

    Note that this form must be subclassed with the ``save_ordering``
    method overriden.
    """
    class IReorderForm(interface.Interface):
        ordering = schema.List(title=u"Ordering", value_type=schema.TextLine())

    # evoque
    template = z3evoque.PageViewTemplateFile("form.html#page")
    # zpt
    #template = NamedTemplate("alchemist.form")
    form_name = _(u"Item reordering")
    form_fields = formlib.form.Fields(IReorderForm, render_context=True)

    def setUpWidgets(self, ignore_request=False):
        class context:
            ordering = list(self.context)

        self.adapters = {
            self.IReorderForm: context,
        }

        self.widgets = formlib.form.setUpWidgets(self.form_fields,
                                                 self.prefix,
                                                 self.context,
                                                 self.request,
                                                 form=self,
                                                 adapters=self.adapters,
                                                 ignore_request=ignore_request)

    def save_ordering(self, ordering):
        raise NotImplementedError("Must be defined by subclass")

    @formlib.form.action(_(u"Save"))
    def handle_save(self, action, data):
        self.save_ordering(data["ordering"])
Beispiel #11
0
class DeleteForm(PageForm):
    """Delete-form for Bungeni content.

    Confirmation

        The user is presented with a confirmation form which details
        the items that are going to be deleted.

    Subobjects

        Recursively, a permission check is carried out for each item
        that is going to be deleted. If a permission check fails, an
        error message is displayed to the user.

    Will redirect back to the container on success.
    """
    # evoque
    template = z3evoque.PageViewTemplateFile("delete.html")

    # zpt
    # !+form_template(mr, jul-2010) this is unused here, but needed by
    # some adapter of this "object delete" view
    #form_template = NamedTemplate("alchemist.form")
    #template = ViewPageTemplateFile("templates/delete.pt")

    _next_url = None
    form_fields = formlib.form.Fields()

    def _can_delete_item(self, action):
        return True

    def nextURL(self):
        return self._next_url

    def update(self):
        self.subobjects = self.get_subobjects()
        super(DeleteForm, self).update()

    def get_subobjects(self):
        return ()

    def delete_subobjects(self):
        return 0

    @formlib.form.action(_(u"Delete"), condition=_can_delete_item)
    def handle_delete(self, action, data):
        count = self.delete_subobjects()
        container = self.context.__parent__
        trusted = removeSecurityProxy(self.context)
        session = Session()
        session.delete(trusted)
        count += 1

        try:
            session.flush()
        except IntegrityError, e:
            # this should not happen in production; it's a critical
            # error, because the transaction might have failed in the
            # second phase of the commit
            session.rollback()
            log.critical(e)

            self.status = _(u"Could not delete item due to "
                            "database integrity error")

            return self.render()
        # !+SESSION_CLOSE(taras.sterch, july-2011) there is no need to close the
        # session. Transaction manager will take care of this. Hope it does not
        # brake anything.
        #session.close()

        #TODO: check that it is removed from the index!
        notify(
            ObjectRemovedEvent(self.context,
                               oldParent=container,
                               oldName=self.context.__name__))
        # we have to switch our context here otherwise the deleted object will
        # be merged into the session again and reappear magically
        self.context = container
        next_url = self.nextURL()

        if next_url is None:
            next_url = url.absoluteURL(container, self.request) + \
                       "/?portal_status_message=%d items deleted" % count

        self.request.response.redirect(next_url)
Beispiel #12
0
class PageForm(BaseForm, formlib.form.PageForm, browser.BungeniBrowserView):
    #template = NamedTemplate("alchemist.form")
    template = z3evoque.PageViewTemplateFile("form.html#page")
Beispiel #13
0
class VersionLogView(browser.BungeniBrowserView, forms.common.BaseForm):
    class IVersionEntry(interface.Interface):
        commit_message = schema.Text(title=_(u"Change Message"))

    form_fields = formlib.form.Fields(IVersionEntry)
    formatter_factory = TableFormatter

    # evoque
    render = z3evoque.PageViewTemplateFile("version.html")
    # zpt
    #render = ViewPageTemplateFile("templates/version.pt")

    diff_view = None

    def __init__(self, context, request):
        super(VersionLogView, self).__init__(context.__parent__, request)
        # table to display the versions history
        formatter = date.getLocaleFormatter(self.request, "dateTime", "short")
        # !+ note this breaks the previous sort-dates-as-strings-hack of
        # formatting dates, for all locales, as date.strftime("%Y-%m-%d %H:%M")
        # that, when sorted as a string, gives correct results.
        self.columns = [
            column.SelectionColumn(lambda item: str(item.version_id),
                                   name="selection"),
            column.GetterColumn(title=_(u"version"),
                                getter=lambda i, f: '<a href="%s">%d</a>' %
                                ("%s/versions/obj-%d" %
                                 (f.url, i.version_id), i.version_id)),
            column.GetterColumn(title=_(u"manual"),
                                getter=lambda i, f: i.manual),
            column.GetterColumn(
                title=_(u"modified"),
                getter=lambda i, f: formatter.format(i.change.date_active)),
            column.GetterColumn(title=_(u"by"),
                                getter=lambda i, f: i.change.user_id),
            column.GetterColumn(title=_(u"message"),
                                getter=lambda i, f: i.change.description),
        ]
        self.selection_column = self.columns[0]

    def listing(self):
        # set up table
        values = list(self._versions.values())
        values.sort(key=operator.attrgetter("version_id"))
        values.reverse()
        formatter = self.formatter_factory(
            self.context,
            self.request,
            values,
            prefix="results",
            visible_column_names=[c.name for c in self.columns],
            columns=self.columns)

        # the column getter methods expect an ``url`` attribute
        formatter.url = url.absoluteURL(self.context, self.request)

        # update and render
        formatter.updateBatching()
        return formatter()

    def has_write_permission(self, context):
        """check that  the user has the rights to edit 
             the object, if not we assume he has no rights 
             to make a version
             assumption is here that if he has the rights on any of the fields
             he may create a version."""
        trusted = removeSecurityProxy(self.context)
        table = orm.class_mapper(trusted.__class__).mapped_table
        for column in table.columns:
            try:
                if canWrite(self.context, column.name):
                    return True
            except ForbiddenAttribute:
                pass
        else:
            return False

    # !+action_url(mr, jul-2010) - throughout bungeni UI, defined only here
    @property
    def action_url(self):
        # this avoids that "POST"ed forms get a "@@index" appended to action URL
        return ""

    # !+action_method(mr, jul-2010) - throughout bungeni UI, defined only here
    @property
    def action_method(self):
        # XXX - for forms that only View information, this should return "get"
        # e.g. business / questions / <q> / versions / Show Differences
        return "post"

    @formlib.form.action(label=_("New Version"),
                         condition=has_write_permission)
    def handle_new_version(self, action, data):
        self._versions.create(message=data["commit_message"], manual=True)
        self.status = _(u"New Version Created")

    @formlib.form.action(label=_("Revert To"), condition=has_write_permission)
    def handle_revert_version(self, action, data):
        selected = getSelected(self.selection_column, self.request)
        if len(selected) != 1:
            self.status = _("Select one item to revert to")
            return
        version = self._versions.get(selected[0])
        message = data["commit_message"]
        self._versions.revert(version, message)
        self.status = (_(u"Reverted to Previous Version %s") %
                       (version.version_id))

    @formlib.form.action(label=_("Show Differences"),
                         name="diff",
                         validator=lambda form, action, data: ())
    def handle_diff_version(self, action, data):
        self.status = _("Displaying differences")

        selected = getSelected(self.selection_column, self.request)

        if len(selected) not in (1, 2):
            self.status = _("Select one or two items to show differences")
            return

        context = removeSecurityProxy(self.context)
        source = self._versions.get(selected[0])

        try:
            target = self._versions.get(selected[1])
            if source.version_id > target.version_id:
                t = source
                source = target
                target = t
        except IndexError:
            target = context
        diff_view = DiffView(source, target, self.request)

        self.diff_view = diff_view(*filter(IIModelInterface.providedBy,
                                           interface.providedBy(context)))

        log.debug("handle_diff_version: source=%s target=%s \n%s" %
                  (source, target, self.diff_view))

    def setUpWidgets(self, ignore_request=False):
        # setup widgets in data entry mode not bound to context
        actions = self.actions
        self.actions = []
        for action in actions:
            if getattr(action, "condition", None):
                if action.condition(self, self.context):
                    self.actions.append(action)
            else:
                self.actions.append(action)
        if not self.has_write_permission(self.context):
            self.form_fields = self.form_fields.omit("commit_message")
        self.adapters = {}
        self.widgets = formlib.form.setUpDataWidgets(
            self.form_fields,
            self.prefix,
            self.context,
            self.request,
            ignore_request=ignore_request)

    @property
    def _versions(self):
        instance = removeSecurityProxy(self.context)
        versions = IVersioned(instance)
        return versions

    def __call__(self):
        self.update()
        return self.render()
Beispiel #14
0
class PageForm(BaseForm, formlib.form.PageForm, browser.BungeniBrowserView):
    template = z3evoque.PageViewTemplateFile("form.html#page")