def update(self, trans):
        """
        Updates the item.
        
        @param trans: A valid transaction handle
        @return: None
        """
        old_item = _db.get_item(self._id, trans)
        parent = _db.get_item(self._parentid, trans)
        
        user = currentThread().context.user
        user_role = permsresolver.get_access(old_item, user)
        
        if user_role > permsresolver.READER:
            # set security
            if user_role == permsresolver.COORDINATOR:
                # user is COORDINATOR
                if (self.inheritRoles != old_item.inheritRoles) or \
                        (not self.inheritRoles and \
                         self.security != old_item.security):
                    self._applySecurity(parent, trans)
            else:
                # restore previous ACL
                self.security = old_item.security
                self.inheritRoles = old_item.inheritRoles

            _db.handle_update(self, old_item, trans)
            self.modifiedBy = user.displayName.value
            self.modified = time.time()
            parent.modified = self.modified
            _db.put_item(self, trans)
            _db.put_item(parent, trans)
        else:
            raise exceptions.PermissionDenied, \
                    'The user does not have update permissions.'
    def delete(self, trans):
        """
        Deletes the item permanently.
        
        @param trans: A valid transaction handle
        @return: None
        """
        user = currentThread().context.user
        self = _db.get_item(self._id, trans)

        user_role = permsresolver.get_access(self, user)
        can_delete = (user_role > permsresolver.AUTHOR) or \
            (user_role == permsresolver.AUTHOR and self._owner == user._id)
        
        if (not(self._isSystem) and can_delete):
            # delete item physically
            self._delete(trans)
            # update container
            parent = _db.get_item(self._parentid, trans)
            parent.modified = time.time()
            _db.put_item(parent, trans)
        else:
            raise exceptions.PermissionDenied, \
                'The object was not deleted.\n' + \
                'The user has insufficient permissions.'
 def on_update(item, new_attr, old_attr, trans):
     from porcupine.systemObjects import Composite
     # load objects
     dctObjects = {}
     for i, obj in enumerate(new_attr.value):
         if isinstance(obj, Composite):
             obj._containerid = item._id
         elif isinstance(obj, str):
             obj = _db.get_item(obj, trans)
             new_attr.value[i] = obj
         else:
             raise exceptions.ContainmentError, \
                 'Invalid object type "%s" in composition.' % \
                 obj.__class__.__name__
         dctObjects[obj._id] = obj
     
     # check containment
     composite_type = misc.get_rto_by_name(new_attr.compositeClass)
     
     if [obj for obj in dctObjects.values()
             if not isinstance(obj, composite_type)]:
         raise exceptions.ContainmentError, \
             'Invalid content class "%s" in composition.' % \
             obj.get_contentclass()
     
     # get previous value
     if old_attr != None:
         old_ids = set(old_attr.value)
     else:
         old_ids = set()
     
     new_ids = set([obj._id for obj in new_attr.value])
     
     # calculate added composites
     lstAdded = list(new_ids - old_ids)
     for obj_id in lstAdded:
         _db.handle_update(dctObjects[obj_id], None, trans)
         _db.put_item(dctObjects[obj_id], trans)
     
     # calculate constant composites
     lstConstant = list(new_ids & old_ids)
     for obj_id in lstConstant:
         _db.handle_update(dctObjects[obj_id],
                           _db.get_item(obj_id, trans),
                           trans)
         _db.put_item(dctObjects[obj_id], trans)
     
     # calculate removed composites
     lstRemoved = list(old_ids - new_ids)
     [CompositionEventHandler._removeComposite(_db.get_item(id, trans),
                                               trans)
      for id in lstRemoved]
             
     new_attr.value = list(new_ids)
 def on_delete(item, attr, trans, bPermanent):
     if bPermanent:
         [CompositionEventHandler._removeComposite(_db.get_item(id, trans),
                                                   trans)
          for id in attr.value]
     else:
         for sID in attr.value:
             composite = _db.get_item(sID, trans)
             _db.handle_delete(composite, trans, False)
             composite._isDeleted = 1
             _db.put_item(composite, trans)
 def _remove_reference(attr, oid, trans):
     from porcupine.datatypes import Relator1, RelatorN
     ref_item = _db.get_item(attr.value, trans)
     ref_attr = getattr(ref_item, attr.relAttr)
     if isinstance(ref_attr, RelatorN):
         try:
             ref_attr.value.remove(oid)
         except ValueError:
             pass
     elif isinstance(ref_attr, Relator1):
         ref_attr.value = None
     ref_attr.validate()
     _db.put_item(ref_item, trans)
 def _applySecurity(self, oParent, trans):
     if self.inheritRoles:
         self.security = oParent.security
     if self.isCollection:
         cursor = None
         try:
             cursor = _db.query_index('_parentid', self._id, trans)
             cursor.fetch_all = True
             for child in cursor:
                 child._applySecurity(self, trans)
                 _db.put_item(child, trans)
         finally:
             if cursor != None:
                 cursor.close()
 def _add_reference(attr, oid, trans):
     from porcupine.datatypes import Relator1, RelatorN
     ref_item = _db.get_item(attr.value, trans)
     if ref_item != None and isinstance(ref_item,
                                        tuple([misc.get_rto_by_name(cc)
                                               for cc in attr.relCc])):
         ref_attr = getattr(ref_item, attr.relAttr)
         if isinstance(ref_attr, RelatorN):
             ref_attr.value.append(oid)
         elif isinstance(ref_attr, Relator1):
             ref_attr.value = oid
         ref_attr.validate()
         _db.put_item(ref_item, trans)
     else:
         attr.value = None
 def _remove_references(attr, ids, oid, trans):
     # remove references
     from porcupine.datatypes import Relator1, RelatorN
     for id in ids:
         ref_item = _db.get_item(id, trans)
         ref_attr = getattr(ref_item, attr.relAttr)
         if isinstance(ref_attr, RelatorN):
             try:
                 ref_attr.value.remove(oid)
             except ValueError:
                 pass
         elif isinstance(ref_attr, Relator1):
             ref_attr.value = ''
         ref_attr.validate()
         _db.put_item(ref_item, trans)
 def recycle(self, rb_id, trans):
     """
     Moves the item to the specified recycle bin.
     The item then becomes inaccessible.
     
     @param rb_id: The id of the destination container, which must be
                   a L{RecycleBin} instance
     @type rb_id: str
     @param trans: A valid transaction handle
     @return: None
     """
     user = currentThread().context.user
     self = _db.get_item(self._id, trans)
     
     user_role = permsresolver.get_access(self, user)
     can_delete = (user_role > permsresolver.AUTHOR) or \
                  (user_role == permsresolver.AUTHOR and
                   self._owner == user._id)
     
     if (not(self._isSystem) and can_delete):
         deleted = DeletedItem(self, trans)
         deleted._owner = user._id
         deleted._created = time.time()
         deleted.modifiedBy = user.displayName.value
         deleted.modified = time.time()
         deleted._parentid = rb_id
         
         # check recycle bin's containment
         recycle_bin = _db.get_item(rb_id, trans)
         if not(deleted.get_contentclass() in recycle_bin.containment):
             raise exceptions.ContainmentError, \
                 'The target container does not accept ' + \
                 'objects of type\n"%s".' % deleted.get_contentclass()
         
         _db.handle_update(deleted, None, trans)
         _db.put_item(deleted, trans)
         
         # delete item logically
         self._recycle(trans)
         
         # update container
         parent = _db.get_item(self._parentid, trans)
         parent.modified = time.time()
         _db.put_item(parent, trans)
     else:
         raise exceptions.PermissionDenied, \
             'The object was not deleted.\n' + \
             'The user has insufficient permissions.'
    def append_to(self, parent, trans):
        """
        Adds the item to the specified container.

        @param parent: The id of the destination container or the container
                       itself
        @type parent: str OR L{Container}
        @param trans: A valid transaction handle
        @return: None
        """
        if type(parent) == str:
            parent = _db.get_item(parent, trans)
        
        if isinstance(self, Shortcut):
            contentclass = self.get_target_contentclass(trans)
        else:
            contentclass = self.get_contentclass()
        
        user = currentThread().context.user
        user_role = permsresolver.get_access(parent, user)
        if user_role == permsresolver.READER:
            raise exceptions.PermissionDenied, \
                'The user does not have write permissions ' + \
                'on the parent folder.'
        if not(contentclass in parent.containment):
            raise exceptions.ContainmentError, \
                'The target container does not accept ' + \
                'objects of type\n"%s".' % contentclass

        # set security to new item
        if user_role == permsresolver.COORDINATOR:
            # user is COORDINATOR
            self._applySecurity(parent, trans)
        else:
            # user is not COORDINATOR
            self.inheritRoles = True
            self.security = parent.security
        
        self._owner = user._id
        self._created = time.time()
        self.modifiedBy = user.displayName.value
        self.modified = time.time()
        self._parentid = parent._id
        _db.handle_update(self, None, trans)
        parent.modified = self.modified
        _db.put_item(self, trans)
        _db.put_item(parent, trans)
    def _copy(self, target, trans, clear_inherited=False):
        clone = self.clone()
        if clear_inherited:
            clone.inheritRoles = False
        
        user = currentThread().context.user
        clone._owner = user._id
        clone._created = time.time()
        clone.modifiedBy = user.displayName.value
        clone.modified = time.time()
        clone._parentid = target._id
        
        _db.handle_update(clone, None, trans)
        _db.put_item(clone, trans)

        if self.isCollection:
            [child._copy(clone, trans) for child in self.get_children(trans)]
    def copy_to(self, target_id, trans):
        """
        Copies the item to the designated target.

        @param target_id: The ID of the destination container
        @type target_id: str
        @param trans: A valid transaction handle
        @return: None
        @raise L{porcupine.exceptions.ObjectNotFound}:
            If the target container does not exist.
        """
        target = _db.get_item(target_id, trans)
        if target == None or target._isDeleted:
            raise exceptions.ObjectNotFound, (
                'The target container "%s" does not exist.' %
                target_id , False)
        
        if isinstance(self, Shortcut):
            contentclass = self.get_target_contentclass(trans)
        else:
            contentclass = self.get_contentclass()
        
        if self.isCollection and target.is_contained_in(self._id, trans):
            raise exceptions.ContainmentError, \
                'Cannot copy item to destination.\n' + \
                'The destination is contained in the source.'
        
        # check permissions on target folder
        user = currentThread().context.user
        user_role = permsresolver.get_access(target, user)
        if not(self._isSystem) and user_role > permsresolver.READER:
            if not(contentclass in target.containment):
                raise exceptions.ContainmentError, \
                    'The target container does not accept ' + \
                    'objects of type\n"%s".' % contentclass
            
            self._copy(target, trans, clear_inherited=True)
            # update parent
            target.modified = time.time()
            _db.put_item(target, trans)
        else:
            raise exceptions.PermissionDenied, \
                'The object was not copied.\n' + \
                'The user has insufficient permissions.'
 def restore_to(self, parent_id, trans):
     """
     Restores the deleted object to the specified container.
     
     @param parent_id: The ID of the container in which
                       the item will be restored
     @type parent_id: str    
     @param trans: A valid transaction handle
     @return: None
     @raise L{porcupine.exceptions.ObjectNotFound}:
         If the original location or the original item no longer exists.
     """
     deleted = _db.get_item(self._deletedId, trans)
     if deleted == None:
         raise exceptions.ObjectNotFound, (
             'Cannot locate original item.\n' +
             'It seems that this item resided in a container\n' +
             'that has been permanently deleted or it is shortcut\n' +
             'having its target permanently deleted.', False)
     parent = _db.get_item(parent_id or deleted._parentid, trans)
     if parent == None or parent._isDeleted:
         raise exceptions.ObjectNotFound, (
             'Cannot locate target container.\n' +
             'It seems that this container is deleted.', False)
     
     if isinstance(deleted, Shortcut):
         contentclass = deleted.get_target_contentclass(trans)
     else:
         contentclass = deleted.get_contentclass()
     
     if contentclass and not(contentclass in parent.containment):
         raise exceptions.ContainmentError, \
             'The target container does not accept ' + \
             'objects of type\n"%s".' % contentclass
     
     # try to restore original item
     self._restore(deleted, parent, trans)
     # update parent
     parent.modified = time.time()
     _db.put_item(parent, trans)
     # delete self
     self.delete(trans, _removeDeleted=False)
    def move_to(self, target_id, trans):
        """
        Moves the item to the designated target.
        
        @param target_id: The ID of the destination container
        @type target_id: str
        @param trans: A valid transaction handle
        @return: None
        @raise L{porcupine.exceptions.ObjectNotFound}:
            If the target container does not exist.
        """
        user = currentThread().context.user
        user_role = permsresolver.get_access(self, user)
        can_move = (user_role > permsresolver.AUTHOR)
        ## or (user_role == permsresolver.AUTHOR and oItem.owner == user.id)

        parent_id = self._parentid
        target = _db.get_item(target_id, trans)
        if target == None or target._isDeleted:
            raise exceptions.ObjectNotFound, (
                'The target container "%s" does not exist.' %
                target_id , False)
        
        if isinstance(self, Shortcut):
            contentclass = self.get_target_contentclass(trans)
        else:
            contentclass = self.get_contentclass()
        
        user_role2 = permsresolver.get_access(target, user)
        
        if self.isCollection and target.is_contained_in(self._id, trans):
            raise exceptions.ContainmentError, \
                'Cannot move item to destination.\n' + \
                'The destination is contained in the source.'
        
        if (not(self._isSystem) and can_move and
                user_role2 > permsresolver.READER):
            if not(contentclass in target.containment):
                raise exceptions.ContainmentError, \
                    'The target container does not accept ' + \
                    'objects of type\n"%s".' % contentclass
            
            self._parentid = target._id
            self.inheritRoles = False
            self.modified = time.time()
            _db.check_unique(self, None, trans)
            _db.put_item(self, trans)

            # update target
            target.modified = time.time()
            _db.put_item(target, trans)

            # update parent
            parent = _db.get_item(parent_id, trans)
            parent.modified = time.time()
            _db.put_item(parent, trans)
        else:
            raise exceptions.PermissionDenied, \
                'The object was not moved.\n' + \
                'The user has insufficient permissions.'
 def _undelete(self, trans):
     """
     Undeletes a logically deleted item.
     Bypasses security checks.
     
     @return: None
     """
     if int(self._isDeleted) == 1:
         _db.handle_undelete(self, trans)
     
     self._isDeleted = int(self._isDeleted) - 1
     
     if self.isCollection:
         cursor = None
         try:
             cursor = _db.query_index('_parentid', self._id, trans)
             cursor.fetch_all = True
             [child._undelete(trans) for child in cursor]
         finally:
             if cursor != None:
                 cursor.close()
     
     _db.put_item(self, trans)
 def _recycle(self, trans):
     """
     Deletes an item logically.
     Bypasses security checks.
     
     @return: None
     """
     if not self._isDeleted:
         _db.handle_delete(self, trans, False)
     
     self._isDeleted = int(self._isDeleted) + 1
     
     if self.isCollection:
         cursor = None
         try:
             cursor = _db.query_index('_parentid', self._id, trans)
             cursor.fetch_all = True
             [child._recycle(trans) for child in cursor]
         finally:
             if cursor != None:
                 cursor.close()
     
     _db.put_item(self, trans)