Example #1
0
 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 = get_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)))
Example #2
0
    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)))
Example #3
0
 def __init__(self, context, request, view, manager):
     self.for_display = False  # bool(self.file_data_items)
     log.warn(
         "!+IAttachedFileVersion should NOT be trying to list attachments !!!"
     )
     from bungeni.ui.utils import debug
     print self.__class__.__name__, debug.interfaces(context)
Example #4
0
def _get(discriminator):
    """Get the TypeInfo instance for discriminator, that may be any of:
            type_key: str (the lowercase underscore-separated of domain cls name)
            workflow: an instance of Workflow, provides IWorkflow
            interface: provides IInterface
            domain model: provides IBungeniContent
            domain model instance: type provides IBungeniContent
            descriptor: provides IModelDescriptor
    
    Raise KeyError if no entry matched.
    
    Usage: capi.get_type_info(discriminator)
    """
    if discriminator is None:
        m = "type_info._get discriminator is None"
        log.error(m)
        raise ValueError(m)
    discri = removeSecurityProxy(discriminator)
    getter = None

    # !+IALCHEMISTCONTENT normalize trickier discriminator cases to type_key
    if IIModelInterface.providedBy(discri):
        discri = naming.type_key("table_schema_interface_name",
                                 discri.__name__)
    elif IInterface.providedBy(discri):
        discri = naming.type_key("model_interface_name", discri.__name__)
    elif type(discri) is type and issubclass(discri, domain.Entity):
        discri = naming.polymorphic_identity(discri)
    elif isinstance(discri, domain.Entity):
        discri = naming.polymorphic_identity(type(discri))

    if isinstance(discri, basestring):
        getter = _get_by_type_key
    #elif IInterface.providedBy(discri):
    #    getter = _get_by_interface
    #!+elif interfaces.IBungeniContent.implementedBy(discri):
    #elif issubclass(discri, domain.Entity):
    #    getter = _get_by_model
    #!+elif interfaces.IBungeniContent.providedBy(discri):
    #elif isinstance(discri, domain.Entity):
    #    getter = _get_by_instance
    elif IWorkflow.providedBy(discri):
        getter = _get_by_workflow
    elif IModelDescriptor.implementedBy(discri):
        getter = _get_by_descriptor_model

    if getter is not None:
        ti = getter(discri)
        if ti is not None:
            return ti
        else:
            m = "No type registered for discriminator: %r" % (discriminator)
    else:
        m = "Invalid type info lookup discriminator: %r" % (discriminator)
    from bungeni.ui.utils import debug
    log.debug(debug.interfaces(discriminator))
    log.debug(m)
    raise KeyError(m)
Example #5
0
def _get(discriminator):
    """Get the TypeInfo instance for discriminator, that may be any of:
            type_key: str (the lowercase underscore-separated of domain cls name)
            workflow: an instance of Workflow, provides IWorkflow
            interface: provides IInterface
            domain model: provides IBungeniContent
            domain model instance: type provides IBungeniContent
            descriptor: provides IModelDescriptor
    
    Raise KeyError if no entry matched.
    
    Usage: capi.get_type_info(discriminator)
    """
    if discriminator is None:
        m = "type_info._get discriminator is None"
        log.error(m)
        raise ValueError(m)
    discri = removeSecurityProxy(discriminator)
    getter = None
    
    # !+IALCHEMISTCONTENT normalize trickier discriminator cases to type_key
    if IIModelInterface.providedBy(discri):
        discri = naming.type_key("table_schema_interface_name", discri.__name__)
    elif IInterface.providedBy(discri):
        discri = naming.type_key("model_interface_name", discri.__name__)
    elif type(discri) is type and issubclass(discri, domain.Entity):
        discri = naming.polymorphic_identity(discri)
    elif isinstance(discri, domain.Entity):
        discri = naming.polymorphic_identity(type(discri))
    
    if isinstance(discri, basestring):
        getter = _get_by_type_key
    #elif IInterface.providedBy(discri):
    #    getter = _get_by_interface
    #!+elif interfaces.IBungeniContent.implementedBy(discri):
    #elif issubclass(discri, domain.Entity):
    #    getter = _get_by_model
    #!+elif interfaces.IBungeniContent.providedBy(discri):
    #elif isinstance(discri, domain.Entity):
    #    getter = _get_by_instance
    elif IWorkflow.providedBy(discri):
        getter = _get_by_workflow
    elif IModelDescriptor.implementedBy(discri):
        getter = _get_by_descriptor_model
    
    if getter is not None:
        ti = getter(discri)
        if ti is not None:
            return ti
        else:
            m = "No type registered for discriminator: %r" % (discriminator)
    else: 
        m = "Invalid type info lookup discriminator: %r" % (discriminator)
    from bungeni.ui.utils import debug
    log.debug(debug.interfaces(discriminator))
    log.debug(m)
    raise KeyError(m)
Example #6
0
 def __init__(self, context, request):
     log.debug("CalendarView.__init__: %s" % (context))
     super(CalendarView, self).__init__(ISchedulingContext(context),
                                        request)
     self.context.__name__ = self.__name__
     self.context.title = self.short_name
     interface.alsoProvides(self.context, ILocation)
     interface.alsoProvides(self.context, IDCDescriptiveProperties)
     self.__parent__ = context
     log.debug(debug.interfaces(self))
     log.debug(debug.location_stack(self))
Example #7
0
 def __call__(self, timestamp=None):
     log.debug("CalendarView.__call__: %s" % (self.context))
     trusted = removeSecurityProxy(self.context)
     trusted.__name__ = self.__name__
     interface.alsoProvides(trusted, ILocation)
     if IBusinessSectionLayer.providedBy(self.request) and isinstance(trusted, SittingContainerSchedulingContext):
         self.url = url.absoluteURL(trusted.__parent__.__parent__, self.request)
     else:
         self.url = url.absoluteURL(trusted.__parent__, self.request)
     self.title = ISchedulingContext(self.context).label
     log.debug(debug.interfaces(self))
     log.debug(debug.location_stack(self))
     return self.render()
Example #8
0
def getWorkSpacePISection(workspace):
    """ /workspace/obj-id/pi -> non-ARCHIVED parliamentary items
    """
    s = Section(title=_(u"Parliamentary items"),
                description=_(u"Current parliamentary activity"),
                default_name="workspace-pi")
    interface.alsoProvides(s, interfaces.IWorkspacePIContext)
    s.__parent__ = workspace
    s.__name__ = "pi"
    s["questions"] = QueryContent(
        container_getter(workspace,
                         'questions',
                         query_modifier=sql.not_(
                             domain.Question.status.in_(ARCHIVED))),
        #title=_(u"Questions"),
        description=_(u"Questions"))
    s["motions"] = QueryContent(
        container_getter(workspace,
                         'motions',
                         query_modifier=sql.not_(
                             domain.Motion.status.in_(ARCHIVED))),
        #title=_(u"Motions"),
        description=_(u"Motions"))
    s["tableddocuments"] = QueryContent(
        container_getter(workspace,
                         'tableddocuments',
                         query_modifier=sql.not_(
                             domain.TabledDocument.status.in_(ARCHIVED))),
        #title=_(u"Tabled documents"),
        description=_(u"Tabled documents"))
    s["bills"] = QueryContent(
        container_getter(workspace,
                         'bills',
                         query_modifier=sql.not_(
                             domain.Bill.status.in_(ARCHIVED))),
        #title=_(u"Bills"),
        description=_(u"Bills"))
    s["agendaitems"] = QueryContent(
        container_getter(workspace,
                         'agendaitems',
                         query_modifier=sql.not_(
                             domain.AgendaItem.status.in_(ARCHIVED))),
        #title=_(u"Agenda items"),
        description=_(u" items"))
    s["committees"] = QueryContent(
        container_getter(workspace, 'committees'),
        #title=_(u"Committees"),
        description=_(u"Committees"))
    log.debug("WorkspacePISection %s" % debug.interfaces(s))
    return s
Example #9
0
 def __call__(self, timestamp=None):
     log.debug("CalendarView.__call__: %s" % (self.context))
     trusted = removeSecurityProxy(self.context)
     trusted.__name__ = self.__name__
     interface.alsoProvides(trusted, ILocation)
     if (IBusinessSectionLayer.providedBy(self.request) and 
         isinstance(trusted, SittingContainerSchedulingContext)):
         self.url = url.absoluteURL(trusted.__parent__.__parent__, self.request)
     else:
         self.url = url.absoluteURL(trusted.__parent__, self.request)
     self.title = ISchedulingContext(self.context).label
     log.debug(debug.interfaces(self))
     log.debug(debug.location_stack(self))
     return self.render()
Example #10
0
 def __init__(self, context, request):
     log.debug("CalendarView.__init__: %s" % (context))
     super(CalendarView, self).__init__(ISchedulingContext(context),
                                        request)
     trusted = removeSecurityProxy(self.context)
     trusted.__name__ = self.__name__
     trusted.title = self.short_name
     interface.alsoProvides(trusted, ILocation)
     interface.alsoProvides(trusted, IDCDescriptiveProperties)
     if (IBusinessSectionLayer.providedBy(request)
             and isinstance(trusted, SittingContainerSchedulingContext)):
         self.url = url.absoluteURL(trusted.__parent__.__parent__, request)
     else:
         self.url = url.absoluteURL(trusted.__parent__, request)
     self.__parent__ = context
     log.debug(debug.interfaces(self))
     log.debug(debug.location_stack(self))
Example #11
0
 def __init__(self, context, request):
     log.debug("CalendarView.__init__: %s" % (context))
     super(CalendarView, self).__init__(
         ISchedulingContext(context), request)
     trusted = removeSecurityProxy(self.context)
     trusted.__name__ = self.__name__
     trusted.title = self.short_name
     interface.alsoProvides(trusted, ILocation)
     interface.alsoProvides(trusted, IDCDescriptiveProperties)
     if (IBusinessSectionLayer.providedBy(request) and 
         isinstance(trusted, SittingContainerSchedulingContext)):
         self.url = url.absoluteURL(trusted.__parent__.__parent__, request)
     else:
         self.url = url.absoluteURL(trusted.__parent__, request)
     self.__parent__ = context
     log.debug(debug.interfaces(self))
     log.debug(debug.location_stack(self))
Example #12
0
def getWorkSpaceArchiveSection(workspace):
    """ /workspace/obj-id/my-archive/ -> ARCHIVED parliamentary items 
    """
    s = Section(title=_(u"My archive"),
                description=_(u"My archive personal items"),
                default_name="workspace-archive")
    interface.alsoProvides(s, interfaces.IWorkspaceArchiveContext)
    s.__parent__ = workspace
    s.__name__ = "archive"
    s["questions"] = QueryContent(
        container_getter(workspace,
                         'questions',
                         query_modifier=domain.Question.status.in_(ARCHIVED)),
        #title=_(u"Questions"),
        description=_(u"Questions"))
    s["motions"] = QueryContent(
        container_getter(workspace,
                         'motions',
                         query_modifier=domain.Motion.status.in_(ARCHIVED)),
        #title=_(u"Motions"),
        description=_(u"Motions"))
    s["tableddocuments"] = QueryContent(
        container_getter(
            workspace,
            'tableddocuments',
            query_modifier=domain.TabledDocument.status.in_(ARCHIVED)),
        #title=_(u"Tabled documents"),
        description=_(u"Tabled documents"))
    s["bills"] = QueryContent(
        container_getter(workspace,
                         'bills',
                         query_modifier=domain.Bill.status.in_(ARCHIVED)),
        #title=_(u"Bills"),
        description=_(u"Bills"))
    s["agendaitems"] = QueryContent(
        container_getter(
            workspace,
            'agendaitems',
            query_modifier=domain.AgendaItem.status.in_(ARCHIVED)),
        #title=_(u"Agenda items"),
        description=_(u" items"))
    log.debug("getWorkSpaceArchiveSection %s" % debug.interfaces(s))
    return s
Example #13
0
def getWorkSpacePISection(workspace):
    """ /workspace/obj-id/pi -> non-ARCHIVED parliamentary items
    """
    s = Section(title=_(u"Parliamentary items"),
            description=_(u"Current parliamentary activity"),
            default_name="workspace-pi")
    interface.alsoProvides(s, interfaces.IWorkspacePIContext)
    s.__parent__ = workspace
    s.__name__ = "pi"
    s["questions"] = QueryContent(
            container_getter(workspace, 'questions',
            query_modifier=sql.not_(domain.Question.status.in_(ARCHIVED))),
            #title=_(u"Questions"),
            description=_(u"Questions"))
    s["motions"] = QueryContent(
            container_getter(workspace, 'motions',
                query_modifier=sql.not_(domain.Motion.status.in_(ARCHIVED))),
            #title=_(u"Motions"),
            description=_(u"Motions"))
    s["tableddocuments"] = QueryContent(
            container_getter(workspace, 'tableddocuments',
                query_modifier=sql.not_(domain.TabledDocument.status.in_(ARCHIVED))),
            #title=_(u"Tabled documents"),
            description=_(u"Tabled documents"))
    s["bills"] = QueryContent(
            container_getter(workspace, 'bills',
                query_modifier=sql.not_(domain.Bill.status.in_(ARCHIVED))),
            #title=_(u"Bills"),
            description=_(u"Bills"))
    s["agendaitems"] = QueryContent(
            container_getter(workspace, 'agendaitems',
                query_modifier=sql.not_(domain.AgendaItem.status.in_(ARCHIVED))),
            #title=_(u"Agenda items"),
            description=_(u" items"))
    s["committees"] = QueryContent(
            container_getter(workspace, 'committees'),
            #title=_(u"Committees"),
            description=_(u"Committees"))
    log.debug("WorkspacePISection %s" % debug.interfaces(s))
    return s
Example #14
0
def getWorkSpaceArchiveSection(workspace):
    """ /workspace/obj-id/my-archive/ -> ARCHIVED parliamentary items 
    """
    s = Section(title=_(u"My archive"),
            description=_(u"My archive personal items"),
            default_name="workspace-archive")
    interface.alsoProvides(s, interfaces.IWorkspaceArchiveContext)
    s.__parent__ = workspace
    s.__name__ = "archive"
    s["questions"] = QueryContent(
            container_getter(workspace, 'questions',
                query_modifier=domain.Question.status.in_(ARCHIVED)),
            #title=_(u"Questions"),
            description=_(u"Questions"))
    s["motions"] = QueryContent(
            container_getter(workspace, 'motions',
                query_modifier=domain.Motion.status.in_(ARCHIVED)),
            #title=_(u"Motions"),
            description=_(u"Motions"))
    s["tableddocuments"] = QueryContent(
            container_getter(workspace, 'tableddocuments',
                query_modifier=domain.TabledDocument.status.in_(ARCHIVED)),
            #title=_(u"Tabled documents"),
            description=_(u"Tabled documents"))
    s["bills"] = QueryContent(
            container_getter(workspace, 'bills',
                query_modifier=domain.Bill.status.in_(ARCHIVED)),
            #title=_(u"Bills"),
            description=_(u"Bills"))
    s["agendaitems"] = QueryContent(
            container_getter(workspace, 'agendaitems',
                query_modifier=domain.AgendaItem.status.in_(ARCHIVED)),
            #title=_(u"Agenda items"),
            description=_(u" items"))
    log.debug("getWorkSpaceArchiveSection %s" % debug.interfaces(s))
    return s
Example #15
0
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)))
Example #16
0
 def __init__(self, context, request, view, manager):
     self.for_display = False # bool(self.file_data_items)        
     log.warn("!+IAttachedFileVersion should NOT be trying to list attachments !!!")
     from bungeni.ui.utils import debug
     print self.__class__.__name__, debug.interfaces(context)
Example #17
0
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)))