Beispiel #1
0
 def _object_changed(self, action, ob, 
         date_active=None,
         note=None,
         procedure="a",
     ):
     """() -> domain.Change
     
     date_active:
         the UI for some changes allow the user to manually set the 
         date_active -- this is what should be used as the *effective* date 
         i.e. the date to be used for all intents and purposes other than 
         for data auditing. When not user-modified, the value should be equal 
         to date_audit.
     """
     domain.assert_valid_change_action(action)
     user = utils.get_login_user()
     assert user is not None, "Audit error. No user logged in."
     # carry over a snapshot of head values
     def get_field_names_to_audit(kls):
         names_to_audit = []
         table = self.audit_table
         for column in table.columns:
             # skip all fields starting with "audit_"
             if column.name.startswith("audit_"):
                 continue
             # ok, column must therefore be a proper attribute from ob's class
             assert column.name in kls.__dict__, \
                 "Not in class: %s" % column.name
             # skip all primary keys (audit_head_id managed separately)
             if column.primary_key: 
                 continue
             names_to_audit.append(column.name)
         for vp_name, vp_type in kls.extended_properties:
             names_to_audit.append(vp_name)
         return names_to_audit
     
     def copy_field_values(head_cls, source, dest):
         for name in get_field_names_to_audit(head_cls):
             setattr(dest, name, getattr(source, name))
     
     # ensure real head object, in case we are dealing with reversioning 
     # off an Audit instance
     head_ob = ob
     if action == "version" and issubclass(ob.__class__, domain.Audit):
         # ob is an Audit instance, so need its head_ob
         head_ob = ob.audit_head
     
     # audit snapshot - done first, to ensure a valid audit_id...
     au = self.audit_class()
     au.audit_head = head_ob # attach audit log item to parent object
     copy_field_values(head_ob.__class__, ob, au)
     session = Session()
     session.add(au)
     
     # change/audit record
     # !+version Version instances are created as Change instances!
     ch = domain.Change()
     ch.seq = 0 # !+ reset below, to avoid sqlalchemy violates not-null constraint
     ch.audit = au # ensures ch.audit_id, ch.note.object_id
     ch.user_id = user.user_id
     ch.action = action
     ch.seq = self._get_seq(ch)
     # !+translate_seq(mr, feb-2013) this should be divided by language?
     # !+translate_action(mr, feb-2013) shoudl there be an action per 
     # language e.g. translate-fr for translations to french (resolves the 
     # noted translate_seq issue)
     ch.procedure = procedure
     ch.date_audit = datetime.now()
     if date_active:
         ch.date_active = date_active
     else:
         ch.date_active = ch.date_audit
     if note:
         ch.note = note
     
     # !+SUBITEM_CHANGES_PERMISSIONS(mr, jan-2012) permission on change 
     # records for something like item[@draft]->file[@attached]->fileversion 
     # need to remember also the root item's state, else when item later 
     # becomes visible to clerk and others, the file itself will also become 
     # visible to the clerk (CORRECT) but so will ALL changes on the file 
     # while that file itself was @attached (WRONG!). May best be addressed
     # when change persistence is reworked along with single document table.
     
     session.flush()
     log.debug("AUDIT [%s] %s" % (au, au.__dict__))
     log.debug("CHANGE [%s] %s" % (action, ch.__dict__))
     return ch
Beispiel #2
0
    def _object_changed(
        self,
        action,
        ob,
        date_active=None,
        note=None,
        procedure="a",
    ):
        """
        date_active:
            the UI for some changes allow the user to manually set the 
            date_active -- this is what should be used as the *effective* date 
            i.e. the date to be used for all intents and purposes other than 
            for data auditing. When not user-modified, the value should be equal 
            to date_audit.
        """
        domain.assert_valid_change_action(action)
        user_id = get_db_user_id()
        assert user_id is not None, "Audit error. No user logged in."

        # carry over a snapshot of head values
        def get_field_names_to_audit(kls):
            names_to_audit = []
            table = self.audit_table
            for column in table.columns:
                # skip all fields starting with "audit_"
                if column.name.startswith("audit_"):
                    continue
                # ok, column must therefore be a proper attribute from ob's class
                assert column.name in kls.__dict__, \
                    "Not in class: %s" % column.name
                # skip all primary keys (audit_head_id managed separately)
                if column.primary_key:
                    continue
                names_to_audit.append(column.name)
            for vp_name, vp_type in kls.extended_properties:
                names_to_audit.append(vp_name)
            return names_to_audit

        def copy_field_values(head_cls, source, dest):
            for name in get_field_names_to_audit(head_cls):
                setattr(dest, name, getattr(source, name))

        # ensure real head object, in case we are dealing with reversioning
        # off an Audit instance
        head_ob = ob
        if action == "version" and issubclass(ob.__class__, domain.Audit):
            # ob is an Audit instance, so need its head_ob
            head_ob = ob.audit_head

        # audit snapshot - done first, to ensure a valid audit_id...
        au = self.audit_class()
        au.audit_head = head_ob  # attach audit log item to parent object
        copy_field_values(head_ob.__class__, ob, au)
        session = Session()
        session.add(au)

        # change/audit record
        # !+version Version instances are created as Change instances!
        ch = domain.Change()
        ch.seq = 0  # !+ reset below, to avoid sqlalchemy violates not-null constraint
        ch.audit = au  # ensures ch.audit_id, ch.note.object_id
        ch.user_id = user_id
        ch.action = action
        ch.seq = self._get_seq(ch)
        ch.procedure = procedure
        ch.date_audit = datetime.now()
        if date_active:
            ch.date_active = date_active
        else:
            ch.date_active = ch.date_audit
        if note:
            ch.note = note

        # !+SUBITEM_CHANGES_PERMISSIONS(mr, jan-2012) permission on change
        # records for something like item[@draft]->file[@attached]->fileversion
        # need to remember also the root item's state, else when item later
        # becomes visible to clerk and others, the file itself will also become
        # visible to the clerk (CORRECT) but so will ALL changes on the file
        # while that file itself was @attached (WRONG!). May best be addressed
        # when change persistence is reworked along with single document table.

        session.flush()
        log.debug("AUDIT [%s] %s" % (au, au.__dict__))
        log.debug("CHANGE [%s] %s" % (action, ch.__dict__))
        return ch
Beispiel #3
0
    def _object_changed(self, action, ob, 
            description="", extras=None, date_active=None):
        """
        description: 
            this is a non-localized string as base description of the log item,
            offers a (building block) for the description of this log item. 
            UI components may use this in any of the following ways:
            - AS IS, optionally localized
            - as a building block for an elaborated description e.g. for 
              generating descriptions that are hyperlinks to an event or 
              version objects
            - ignore it entirely, and generate a custom description via other
              means e.g. from the "notes" extras dict.
        
        extras: !+CHANGE_EXTRAS(mr, dec-2010)
            a python dict, containing "extra" information about the log item, 
            with the "key/value" entries depending on the change "action"; 

            Specific examples, for actions: 
                workflow: self.object_workflow()
                    source
                    destination
                    transition
                    comment
                version: self.object_version()
                    version_id
                modify: self.object_modify()
                    comment
            
            For now, this dict is serialized (using repr(), values are assumed 
            to be simple strings or numbers) as the value of the notes column, 
            for storing in the db--but if and when the big picture of these 
            extra keys is understood clearly then the changes table may be 
            remodeled with dedicated table columns.
        
        date_active:
            the UI for some changes allow the user to manually set the 
            date_active -- this is what should be used as the *effective* date 
            i.e. the date to be used for all intents and purposes other than 
            for data auditing. When not user-modified, the value should be equal 
            to date_audit. 
        """
        domain.assert_valid_change_action(action)
        oid, otype = self._getKey(ob)
        user_id = get_db_user_id()
        assert user_id is not None, "Audit error. No user logged in."
        session = Session()
        change = self.change_class()
        change.action = action
        change.date_audit = datetime.now()
        if date_active:
            change.date_active = date_active
        else:
            change.date_active = change.date_audit
        change.user_id = user_id
        change.description = description
        change.extras = extras
        change.content_type = otype
        change.head = ob # attach change to parent object
        change.status = ob.status # remember parent's status at time of change
        # !+SUBITEM_CHANGES_PERMISSIONS(mr, jan-2012) permission on change 
        # records for something like item[@draft]->file[@attached]->fileversion 
        # need to remember also the root item's state, else when item later 
        # becomes visible to clerk and others, the file itself will also become 
        # visible to the clerk (CORRECT) but so will ALL changes on the file 
        # while that file itself was @attached (WRONG!). May best be addressed
        # when change persistence is reworked along with single document table.
        session.add(change)
        session.flush()
        log.debug("AUDITED [%s] %s" % (action, change.__dict__))
        return change.change_id