Example #1
0
    def __getattr__(self, name):
        """Try to pick any attribute (not found on this change record--this 
        method only gets called when a non-existent attribute is accessed) off 
        the related audit snapshot record (as every change record is related 
        to a type-dedicated audit record).

        !+ should this be on Change i.e. for all change actions?
        """
        audit = self.audit
        try:
            return getattr(audit, name)
        except AttributeError:
            # !+DocVersion.filevers
            try:
                from bungeni.alchemist import utils
                return utils.FILES_VERSION_CONTAINER_ATTRIBUTE_ERROR_HACK(
                    self, name)
            except:
                import sys
                from bungeni.utils import probing
                probing.log_exc(sys.exc_info(), log_handler=log.error)

            raise AttributeError(
                "%r [audit_id=%r, audit_type=%r] object has no attribute %r" %
                (self, self.audit_id, self.audit_type, name))
Example #2
0
def get_head_object_state_rpm(sub_context):
    """IRolePermissionMap(context) adapter factory.
    
    Lighweight and high-performance wrapper on get_object_state(context), 
    to *lookup* (note: no creation of any instance) the workflow State 
    singleton instance for the sub context's head's status.
    
    Note that sub context is NOT workflowed.
    
    On lookup error, returns NONE_STATE_RPM, instead of what would be a 
    zope.component.ComponentLookupError.
    """
    try:
        head = sub_context.head
        return interfaces.IWorkflow(head).get_state(sub_context.status)
    except interfaces.InvalidStateError:
        from bungeni.models.interfaces import IChange
        if sub_context.status is None and IChange.providedBy(sub_context):
            # if status is None,then must have an "add" change action... ignore.
            assert sub_context.action == "add"
        else:
            log.error("get_head_object_state_rpm:%s:%s",
                      type(sub_context).__name__, sub_context.pk)
            probing.log_exc(sys.exc_info(), log_handler=log.error)
        return NONE_STATE_RPM
Example #3
0
 def createAndAdd(self, data):
     domain_model = self.domain_model
     # create the object, inspect data for constructor args      
     try:  
         ob = createInstance(domain_model, data)
     except TypeError:
         log.error("Failure: createInstance(%s, %s)", domain_model, data)
         probing.log_exc(sys.exc_info(), log_handler=log.error)
         ob = domain_model()
     # apply any context values
     self.finishConstruction(ob)
     # apply extra form values
     formlib.form.applyChanges(ob, self.form_fields, data, self.adapters)
     # set the object in container context, causing autosetting of 
     # constrained values e.g. one2many attributes, by triggering call to 
     # _ManagedContainer.constraints.setConstrainedValues()
     self.context[""] = ob
     # flush so we have database id
     Session().flush()
     # !+DataError reload form and display this error?
     # fire an object created event
     notify(ObjectCreatedEvent(ob)) # !+ would set doc_id (if session not flushed) !!
     # signal to add form machinery to go to next url
     self._finished_add = True
     # retrieve the object with location and security information
     oid = self.get_oid(ob)
     return self.context[oid]
Example #4
0
def get_object_state_rpm(context):
    """IRolePermissionMap(context) adapter factory. 
    
    Looks up the workflow State singleton instance that is the current
    IRolePermissionMap responsible for the context.
    
    Lighweight and high-performance wrapper on get_object_state(context), 
    to *lookup* (note: no creation of any instance) the workflow State 
    singleton instance.

    On lookup error, returns NONE_STATE_RPM, instead of what would be a 
    zope.component.ComponentLookupError.
    """
    try:
        state = get_object_state(context)
    except interfaces.InvalidStateError:
        log.error("get_object_state_rpm:%s:%s",
                  type(context).__name__, context.pk)
        probing.log_exc(sys.exc_info(), log_handler=log.error)
        return NONE_STATE_RPM
    if state.parent_permissions:
        # this state delegates permissions to parent,
        # so just recurse passing parent item instead
        head = context.head
        return get_object_state_rpm(head)
    return state
Example #5
0
def get_object_state_rpm(context):
    """IRolePermissionMap(context) adapter factory. 
    
    Looks up the workflow State singleton instance that is the current
    IRolePermissionMap responsible for the context.
    
    Lighweight and high-performance wrapper on get_object_state(context), 
    to *lookup* (note: no creation of any instance) the workflow State 
    singleton instance.

    On lookup error, returns NONE_STATE_RPM, instead of what would be a 
    zope.component.ComponentLookupError.
    """
    try:
        state = get_object_state(context)
    except interfaces.InvalidStateError:
        log.error("get_object_state_rpm:%s:%s", type(context).__name__, context.pk)
        probing.log_exc(sys.exc_info(), log_handler=log.error)
        return NONE_STATE_RPM
    if state.parent_permissions:
        # this state delegates permissions to parent, 
        # so just recurse passing parent item instead
        head = context.head
        return get_object_state_rpm(head)
    return state
Example #6
0
 def page_description(self):
     """Formalize view.page_description as a view property to factor the 
     logic for determining the page description for a view out of the 
     template.
     
     Templates should always simply call: view.page_description
     """
     # if view explicitly sets a page_description, use it
     if self._page_description:
         return self._page_description
     # otherwise try to determine it from DC annotations
     context = removeSecurityProxy(self.context)
     try:
         # This is equivalent of the ZPT expression "context/dc:description"
         # i.e. to "load the value of the variable context, then find a
         # component that adapts that object to Dublin Core and read the
         # description attribute of the component."
         return IDCDescriptiveProperties(context).description
     except (Exception, ):
         probing.log_exc(sys.exc_info(), log_handler=log.debug)
     # otherwise try to determine it from the context
     if getattr(context, "description", None):
         return context.description
     else:
         return "Bungeni"
Example #7
0
 def createAndAdd(self, data):
     domain_model = self.domain_model
     # create the object, inspect data for constructor args
     try:
         ob = createInstance(domain_model, data)
     except TypeError:
         log.error("Failure: createInstance(%s, %s)", domain_model, data)
         probing.log_exc(sys.exc_info(), log_handler=log.error)
         ob = domain_model()
     # apply any context values
     self.finishConstruction(ob)
     # apply extra form values
     formlib.form.applyChanges(ob, self.form_fields, data, self.adapters)
     # set the object in container context, causing autosetting of
     # constrained values e.g. one2many attributes, by triggering call to
     # _ManagedContainer.constraints.setConstrainedValues()
     self.context[""] = ob
     # flush so we have database id
     Session().flush()
     # !+DataError reload form and display this error?
     # fire an object created event
     notify(ObjectCreatedEvent(
         ob))  # !+ would set doc_id (if session not flushed) !!
     # signal to add form machinery to go to next url
     self._finished_add = True
     # retrieve the object with location and security information
     oid = self.get_oid(ob)
     return self.context[oid]
Example #8
0
    def __getattr__(self, name):
        """Try to pick any attribute (not found on this change record--this 
        method only gets called when a non-existent attribute is accessed) off 
        the related audit snapshot record (as every change record is related 
        to a type-dedicated audit record).

        !+ should this be on Change i.e. for all change actions?
        """
        audit = self.audit
        try:
            return getattr(audit, name)
        except AttributeError:
            # !+DocVersion.filevers
            try:
                from bungeni.alchemist import utils

                return utils.FILES_VERSION_CONTAINER_ATTRIBUTE_ERROR_HACK(self, name)
            except:
                import sys
                from bungeni.utils import probing

                probing.log_exc(sys.exc_info(), log_handler=log.error)

            raise AttributeError(
                "%r [audit_id=%r, audit_type=%r] object has no attribute %r"
                % (self, self.audit_id, self.audit_type, name)
            )
Example #9
0
 def filter_group(self, query, domain_class, kw):
     try:
         group_id = int(kw.get("filter_group", 0) or 0)  # incoming value is
         # typically the "" empty string, resulting in exception noise below
     except (TypeError, ValueError):
         probing.log_exc(sys.exc_info(), log_handler=log.error)
         group_id = 0
     if group_id:
         if hasattr(domain_class, "group_id"):
             query = query.filter(domain_class.group_id == group_id)
         elif hasattr(domain_class, "chamber_id"):
             query = query.filter(domain_class.chamber_id == group_id)
     return query
Example #10
0
 def filter_group(self, query, domain_class, kw):
     try:
         group_id = int(kw.get("filter_group", 0) or 0) # incoming value is 
         # typically the "" empty string, resulting in exception noise below
     except (TypeError, ValueError):
         probing.log_exc(sys.exc_info(), log_handler=log.error)
         group_id = 0
     if group_id:
         if hasattr(domain_class, "group_id"):
             query = query.filter(domain_class.group_id==group_id)
         elif hasattr(domain_class, "chamber_id"):
             query = query.filter(domain_class.chamber_id==group_id)
     return query
Example #11
0
 def descriptor_classes():
     """A generator of descriptor classes in this module, preserving the
     order of definition.
     """
     # dir() returns names in alphabetical order
     decorated = []
     for key in dir(module):
         cls = getattr(module, key)
         try:
             assert IModelDescriptor.implementedBy(cls)
             # we decorate with the source code line number for the cls
             decorated.append((inspect.getsourcelines(cls)[1], cls))
         except (TypeError, AttributeError, AssertionError):
             probing.log_exc(sys.exc_info(), log_handler=log.debug)
     # we yield each cls in order of definition
     for cls in [ cls for (line_num, cls) in sorted(decorated) ]:
         yield cls
Example #12
0
 def descriptor_classes():
     """A generator of descriptor classes in this module, preserving the
     order of definition.
     """
     # dir() returns names in alphabetical order
     decorated = []
     for key in dir(module):
         cls = getattr(module, key)
         try:
             assert IModelDescriptor.implementedBy(cls)
             # we decorate with the source code line number for the cls
             decorated.append((inspect.getsourcelines(cls)[1], cls))
         except (TypeError, AttributeError, AssertionError):
             probing.log_exc(sys.exc_info(), log_handler=log.debug)
     # we yield each cls in order of definition
     for cls in [cls for (line_num, cls) in sorted(decorated)]:
         yield cls
Example #13
0
def absoluteURL(context, request):
    """
    For cleaner public URLs, we ensure to use an empty string instead of "index".
    
    Throughout bungeni and ploned packages, this function should ALWAYS be
    used instead of zope.traversing.browser.absoluteURL.
    
    """
    try:
        url = zope.traversing.browser.absoluteURL(context, request).split("/")
    except:
        # !+ABSOLUTE_URL: TypeError: There isn't enough context to get URL information. 
        # This is probably due to incorrect setting up of location information.
        probing.log_exc(sys.exc_info(), log_handler=log.error)
        log.error("\n    ...CONTEXT: %s\n    ...REQUEST URL: %s", context, request.getURL())
        return ""
    while url[-1] in indexNames:
        log.warn("POPPING: %s -> %s", "/".join(url), url[-1])
        url.pop()
    return "/".join(url)
Example #14
0
 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,):
         probing.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)
Example #15
0
def get_head_object_state_rpm(sub_context):
    """IRolePermissionMap(context) adapter factory.
    
    Lighweight and high-performance wrapper on get_object_state(context), 
    to *lookup* (note: no creation of any instance) the workflow State 
    singleton instance for the sub context's head's status.
    
    Note that sub context is NOT workflowed.
    
    On lookup error, returns NONE_STATE_RPM, instead of what would be a 
    zope.component.ComponentLookupError.
    """
    try:
        head = sub_context.head
        return interfaces.IWorkflow(head).get_state(sub_context.status)
    except interfaces.InvalidStateError:
        from bungeni.models.interfaces import IChange
        if sub_context.status is None and IChange.providedBy(sub_context):
            # if status is None,then must have an "add" change action... ignore.
            assert sub_context.action == "add"
        else:
            log.error("get_head_object_state_rpm:%s:%s", type(sub_context).__name__, sub_context.pk)
            probing.log_exc(sys.exc_info(), log_handler=log.error)
        return NONE_STATE_RPM
Example #16
0
 def validate_derived_table_schema(self, action, data):
     """Look-ahead validate against database contraints.
     """
     dm = self.domain_model
     ti = capi.get_type_info(dm)
     derived_table_schema = ti.derived_table_schema
     errors = []
     for name in derived_table_schema:
         ff = self.form_fields.get(name)
         # skip if no form does not define a corresponding form field
         if not ff:
             continue
         # !+ skip if field not included in this form "mode"?
         #if name not in getattr("%s_columns" % (self.mode), ti.descriptor_model):
         #    continue
         
         field = derived_table_schema.get(name)
         assert field is ff.field, name # !+TMP sanity check
         value = data.get(name, None)
         
         ''' !+VTF disabling for now, as attempting to preset a contextualized
         vocab fails for subsequent lodaing of a *view*, as this is executed 
         when validating a *submit* -- may still work if executed right moment.
         
         # !+VTF bungeni.ui.fields.VocabularyTextField -- here a vocabulary 
         # field is not necessarily the type defined by bungeni 
         # e.g. zope.schema._field.Choice that during validation attempts to
         # retrieve the vocabulary and initialize it with a None context...
         # To preempt the error that this causes, we check for and stuff
         # an appropiately initialized vocabulary instance onto this field...
         if hasattr(field, "vocabulary"):
             # preset a vocabulary on self.context, or reset with one off current 
             # context if the one preset previously was off a different context
             if (field.vocabulary is None or (
                     # a vocab was preset previously
                     hasattr(field, "_vtf_last_context") and
                     # and it was prepared with a different context
                     getattr(field, "_vtf_last_context") is not self.context)
                 ):
                 from bungeni.alchemist.utils import get_vocabulary
                 field.vocabulary = get_vocabulary(field.vocabularyName)(self.context)
                 # remember last context used to preset vocabulary
                 field._vtf_last_context = self.context
                 log.debug("Validation of vocabulary field (%r, %r) with value=%r -- "
                     "stuffing vocabulary instance %s [context: %r] onto field %s ...", 
                     name, field.vocabularyName, value, field.vocabulary, self.context, field)
         '''
         # !+VTF a "temporary" and simpler version of above, to avoid 
         # AttributeError in try block below (and incorrectly failed validation).
         TMP_SET_VOCAB = False
         if hasattr(field, "vocabulary") and field.vocabulary is None:
             TMP_SET_VOCAB = True
             from bungeni.alchemist.utils import get_vocabulary
             field.vocabulary = get_vocabulary(field.vocabularyName)(self.context)
         # standard field validation !+ necessary, already called elsewhere? 
         try:
             widget_error = field.validate(value)
         except (RequiredMissing,) as exc:
             widget_error = exc
         # !+ other possible exceptions, should never pass here?
         except (formlib.form.NoInputData, interface.Invalid, Exception,) as exc:
             widget_error = exc
             probing.log_exc(sys.exc_info(), log_handler=log.error)
             log.debug(probing.class_inheritance(exc))
             log.error("\n"
                 "    %r.validate(%r) FAILED (field %r)\n"
                 "    [context: %r]", field, value, name, self.context)
             #raise # !+?
         # !+VTF clear any vocabulary that we preset above
         if TMP_SET_VOCAB:
             field.vocabulary = None
         if widget_error:
             errors.append(self.set_widget_error(name, widget_error))
             widget_error = None
             continue
         
         # get db column definition
         domain_attr = getattr(dm, name)
         if not isinstance(domain_attr, sa.orm.attributes.InstrumentedAttribute):
             continue
         domain_attr_property = domain_attr.property
         assert isinstance(domain_attr_property, sa.orm.properties.ColumnProperty), name # !+TMP sanity check
         # !+MULTIPLE_COLUMNS only single columns supported (so far)
         if len(domain_attr_property.columns) == 1:
             col = domain_attr_property.columns[0]
             #!+AttributeError: '_Label' object has no attribute 'nullable'
             # not: sa.sql.expression._Label, sa.sql.expression.ColumnElement
             assert isinstance(col, sa.schema.Column), col 
         else:
             log.warn("SQLAlchemy property %r NOT defined as a single column, "
                 "skipping derived_table_schema validation...", name)
             continue
         
         # validate against db column definition
         # nullable
         if value is None:
             if not col.nullable:
                 errors.append(self.set_widget_error(name, _(u"May not be null")))
             continue
         # sa.String
         if isinstance(col.type, sa.types.String):
             # length
             length = col.type.length
             if length is not None:
                 if length < len(value):
                     errors.append(self.set_widget_error(name, 
                             _(u"May not be longer than ${length}", 
                                 mapping={"length": length})))
     return errors
Example #17
0
    def validate_derived_table_schema(self, action, data):
        """Look-ahead validate against database contraints.
        """
        dm = self.domain_model
        ti = capi.get_type_info(dm)
        derived_table_schema = ti.derived_table_schema
        errors = []
        for name in derived_table_schema:
            ff = self.form_fields.get(name)
            # skip if no form does not define a corresponding form field
            if not ff:
                continue
            # !+ skip if field not included in this form "mode"?
            #if name not in getattr("%s_columns" % (self.mode), ti.descriptor_model):
            #    continue

            field = derived_table_schema.get(name)
            assert field is ff.field, name  # !+TMP sanity check
            value = data.get(name, None)
            ''' !+VTF disabling for now, as attempting to preset a contextualized
            vocab fails for subsequent lodaing of a *view*, as this is executed 
            when validating a *submit* -- may still work if executed right moment.
            
            # !+VTF bungeni.ui.fields.VocabularyTextField -- here a vocabulary 
            # field is not necessarily the type defined by bungeni 
            # e.g. zope.schema._field.Choice that during validation attempts to
            # retrieve the vocabulary and initialize it with a None context...
            # To preempt the error that this causes, we check for and stuff
            # an appropiately initialized vocabulary instance onto this field...
            if hasattr(field, "vocabulary"):
                # preset a vocabulary on self.context, or reset with one off current 
                # context if the one preset previously was off a different context
                if (field.vocabulary is None or (
                        # a vocab was preset previously
                        hasattr(field, "_vtf_last_context") and
                        # and it was prepared with a different context
                        getattr(field, "_vtf_last_context") is not self.context)
                    ):
                    from bungeni.alchemist.utils import get_vocabulary
                    field.vocabulary = get_vocabulary(field.vocabularyName)(self.context)
                    # remember last context used to preset vocabulary
                    field._vtf_last_context = self.context
                    log.debug("Validation of vocabulary field (%r, %r) with value=%r -- "
                        "stuffing vocabulary instance %s [context: %r] onto field %s ...", 
                        name, field.vocabularyName, value, field.vocabulary, self.context, field)
            '''
            # !+VTF a "temporary" and simpler version of above, to avoid
            # AttributeError in try block below (and incorrectly failed validation).
            TMP_SET_VOCAB = False
            if hasattr(field, "vocabulary") and field.vocabulary is None:
                TMP_SET_VOCAB = True
                from bungeni.alchemist.utils import get_vocabulary
                field.vocabulary = get_vocabulary(field.vocabularyName)(
                    self.context)
            # standard field validation !+ necessary, already called elsewhere?
            try:
                widget_error = field.validate(value)
            except (RequiredMissing, ) as exc:
                widget_error = exc
            # !+ other possible exceptions, should never pass here?
            except (
                    formlib.form.NoInputData,
                    interface.Invalid,
                    Exception,
            ) as exc:
                widget_error = exc
                probing.log_exc(sys.exc_info(), log_handler=log.error)
                log.debug(probing.class_inheritance(exc))
                log.error(
                    "\n"
                    "    %r.validate(%r) FAILED (field %r)\n"
                    "    [context: %r]", field, value, name, self.context)
                #raise # !+?
            # !+VTF clear any vocabulary that we preset above
            if TMP_SET_VOCAB:
                field.vocabulary = None
            if widget_error:
                errors.append(self.set_widget_error(name, widget_error))
                widget_error = None
                continue

            # get db column definition
            domain_attr = getattr(dm, name)
            if not isinstance(domain_attr,
                              sa.orm.attributes.InstrumentedAttribute):
                continue
            domain_attr_property = domain_attr.property
            assert isinstance(
                domain_attr_property,
                sa.orm.properties.ColumnProperty), name  # !+TMP sanity check
            # !+MULTIPLE_COLUMNS only single columns supported (so far)
            if len(domain_attr_property.columns) == 1:
                col = domain_attr_property.columns[0]
                #!+AttributeError: '_Label' object has no attribute 'nullable'
                # not: sa.sql.expression._Label, sa.sql.expression.ColumnElement
                assert isinstance(col, sa.schema.Column), col
            else:
                log.warn(
                    "SQLAlchemy property %r NOT defined as a single column, "
                    "skipping derived_table_schema validation...", name)
                continue

            # validate against db column definition
            # nullable
            if value is None:
                if not col.nullable:
                    errors.append(
                        self.set_widget_error(name, _(u"May not be null")))
                continue
            # sa.String
            if isinstance(col.type, sa.types.String):
                # length
                length = col.type.length
                if length is not None:
                    if length < len(value):
                        errors.append(
                            self.set_widget_error(
                                name,
                                _(u"May not be longer than ${length}",
                                  mapping={"length": length})))
        return errors