Beispiel #1
0
    def getUnknownParentPaths(self, unknownPaths):
        """Get a C{dict} mapping unknown paths to their closest L{Namespace}.

        This function finds the closest L{Namespace} parent for the specified
        unknown paths.  It walks back down each path until it finds a parent or
        determines that one doesn't exist.

        @param unknownPaths: A C{set} of unknown L{Tag.path}s and
            L{Namespace.path}s.
        @return: A C{dict} that maps unknown paths to their closest
            L{Namepace.path} parent.
        """
        if not unknownPaths:
            return {}

        hierarchy = getPathHierarchy(unknownPaths)
        existingPaths = getNamespaces(paths=hierarchy).values(Namespace.path)
        existingPaths = set(existingPaths)
        closestParents = {}
        for path in unknownPaths:
            parentPath = getParentPath(path)
            while parentPath is not None:
                if parentPath in existingPaths:
                    closestParents[path] = parentPath
                    break
                parentPath = getParentPath(parentPath)

        return closestParents
Beispiel #2
0
    def getUnknownParentPaths(self, unknownPaths):
        """Get a C{dict} mapping unknown paths to their closest L{Namespace}.

        This function finds the closest L{Namespace} parent for the specified
        unknown paths.  It walks back down each path until it finds a parent or
        determines that one doesn't exist.

        @param unknownPaths: A C{set} of unknown L{Tag.path}s and
            L{Namespace.path}s.
        @return: A C{dict} that maps unknown paths to their closest
            L{Namepace.path} parent.
        """
        if not unknownPaths:
            return {}

        hierarchy = getPathHierarchy(unknownPaths)
        existingPaths = getNamespaces(paths=hierarchy).values(Namespace.path)
        existingPaths = set(existingPaths)
        closestParents = {}
        for path in unknownPaths:
            parentPath = getParentPath(path)
            while parentPath is not None:
                if parentPath in existingPaths:
                    closestParents[path] = parentPath
                    break
                parentPath = getParentPath(parentPath)

        return closestParents
Beispiel #3
0
    def check(self, namespaces):
        """ Check given L{Namespace}s for integrity errors.

        @param namespaces: A sequence of L{Namespace}s to be checked.
        """

        aboutValues = self._getValues(namespaces, u'fluiddb/about')
        pathValues = self._getValues(namespaces, u'fluiddb/namespaces/path')
        descriptionValues = self._getValues(namespaces,
                                            u'fluiddb/namespaces/description')

        paths = [namespace.path for namespace in namespaces]
        namespacePermissions = dict(getNamespacePermissions(paths))

        parentPaths = [
            getParentPath(namespace.path) for namespace in namespaces
            if namespace.parentID is not None
        ]
        parentNamespaces = getNamespaces(paths=parentPaths)
        parentNamespaces = dict(
            (namespace.path, namespace) for namespace in parentNamespaces)

        users = getUsers()
        users = dict((user.id, user) for user in users)

        for namespace in namespaces:
            expectedAbout = u'Object for the namespace %s' % namespace.path
            self.checkAboutValue(namespace, aboutValues, expectedAbout)
            self.checkPathValue(namespace, pathValues)
            self.checkDescriptionValue(namespace, descriptionValues)
            self.checkPermissions(namespace, namespacePermissions, users,
                                  Operation.NAMESPACE_OPERATIONS)
            self.checkParent(namespace, parentNamespaces)
            self.checkValidPath(namespace)
Beispiel #4
0
    def _createTags(self, values, parentNamespaces):
        """Create new tags.

        @param values: A sequence of C{(Tag.path, description)} 2-tuples.
        @param parentNamespaces: A C{dict} mapping L{Namespace.path}s to
            L{Namespace} instances, the parents of the new L{Tag}s.
        @return: A C{list} of C{(objectID, Tag.path)} 2-tuples.
        """
        admin = getUser(u'fluiddb')
        objects = self._factory.objects(admin)
        systemValues = {}
        result = []
        tags = []
        for path, description in values:
            parentPath = getParentPath(path)
            name = getPathName(path)
            parentNamespace = parentNamespaces.get(parentPath)
            tag = createTag(self._user, parentNamespace, name)
            tag.objectID = objects.create(
                u'Object for the attribute %s' % path)
            result.append((tag.objectID, path))
            systemValues[tag.objectID] = {
                u'fluiddb/tags/description': description,
                u'fluiddb/tags/path': path
            }
            tags.append(tag)
        self._createPermissions(tags)

        if systemValues:
            self._factory.tagValues(admin).set(systemValues)

        return result
Beispiel #5
0
    def check(self, tags):
        """Check given L{Tag}s for integrity errors.

        @param tags: A sequence of L{Tag}s to be checked.
        """
        aboutValues = self._getValues(tags, u'fluiddb/about')
        pathValues = self._getValues(tags, u'fluiddb/tags/path')
        descriptionValues = self._getValues(tags, u'fluiddb/tags/description')

        tagPermissions = dict(getTagPermissions([tag.path for tag in tags]))

        parentPaths = [getParentPath(tag.path) for tag in tags]
        parentNamespaces = getNamespaces(parentPaths)
        parentNamespaces = dict(
            (namespace.path, namespace) for namespace in parentNamespaces)

        users = getUsers()
        users = dict((user.id, user) for user in users)

        for tag in tags:
            expectedAbout = u'Object for the attribute %s' % tag.path
            self.checkAboutValue(tag, aboutValues, expectedAbout)
            self.checkPathValue(tag, pathValues)
            self.checkDescriptionValue(tag, descriptionValues)
            self.checkPermissions(tag, tagPermissions, users,
                                  Operation.TAG_OPERATIONS)
            self.checkParent(tag, parentNamespaces)
            self.checkValidPath(tag)
Beispiel #6
0
    def create(self, values):
        """Create new L{Namespace}s.

        Missing parent L{Namespace}s are created automatically.  For example,
        if C{foo/bar/baz} is requested, and C{foo/bar} doesn't already exist,
        it will be created before C{foo/bar/baz} is created.  Associated
        L{NamespacePermission}s are created automatically with the system-wide
        default permissions.

        @param values: A sequence of C{(path, description)} 2-tuples.
        @raises DuplicatePathError: Raised if the path for a new L{Namespace}
            collides with an existing one.
        @raise MalformedPathError: Raised if one of the given paths is empty
            or has unacceptable characters.
        @return: A C{list} of C{(objectID, path)} 2-tuples for the new
            L{Namespace}s.
        """
        from fluiddb.model.user import getUser

        if not values:
            return []

        paths = [path for path, description in values]
        descriptions = dict(values)

        self._checkForDuplicates(paths)

        admin = getUser(u'fluiddb')
        objects = self._factory.objects(admin)
        systemValues = {}

        paths = getPathHierarchy(paths)
        existingNamespaces = dict((namespace.path, namespace)
                                  for namespace in getNamespaces(paths=paths))
        newNamespaces = []

        for path in sorted(paths):
            if path in existingNamespaces:
                continue

            parentPath = getParentPath(path)
            parentID = (existingNamespaces[parentPath].id
                        if parentPath is not None
                        else None)
            namespace = createNamespace(self._user, path, parentID)
            aboutValue = u'Object for the namespace %s' % path
            description = descriptions.get(path, aboutValue)
            namespace.objectID = objects.create(aboutValue)
            systemValues[namespace.objectID] = {
                u'fluiddb/namespaces/description': description,
                u'fluiddb/namespaces/path': path,
                u'fluiddb/about': aboutValue}
            existingNamespaces[path] = namespace
            newNamespaces.append(namespace)

        self._createPermissions(newNamespaces)
        self._factory.tagValues(admin).set(systemValues)
        values = [(namespace.objectID, namespace.path)
                  for namespace in newNamespaces]
        return values
Beispiel #7
0
    def check(self, tags):
        """Check given L{Tag}s for integrity errors.

        @param tags: A sequence of L{Tag}s to be checked.
        """
        aboutValues = self._getValues(tags, u'fluiddb/about')
        pathValues = self._getValues(tags, u'fluiddb/tags/path')
        descriptionValues = self._getValues(tags, u'fluiddb/tags/description')

        tagPermissions = dict(getTagPermissions([tag.path for tag in tags]))

        parentPaths = [getParentPath(tag.path) for tag in tags]
        parentNamespaces = getNamespaces(parentPaths)
        parentNamespaces = dict((namespace.path, namespace)
                                for namespace in parentNamespaces)

        users = getUsers()
        users = dict((user.id, user) for user in users)

        for tag in tags:
            expectedAbout = u'Object for the attribute %s' % tag.path
            self.checkAboutValue(tag, aboutValues, expectedAbout)
            self.checkPathValue(tag, pathValues)
            self.checkDescriptionValue(tag, descriptionValues)
            self.checkPermissions(tag, tagPermissions, users,
                                  Operation.TAG_OPERATIONS)
            self.checkParent(tag, parentNamespaces)
            self.checkValidPath(tag)
Beispiel #8
0
    def check(self, namespaces):
        """ Check given L{Namespace}s for integrity errors.

        @param namespaces: A sequence of L{Namespace}s to be checked.
        """

        aboutValues = self._getValues(namespaces, u'fluiddb/about')
        pathValues = self._getValues(namespaces, u'fluiddb/namespaces/path')
        descriptionValues = self._getValues(namespaces,
                                            u'fluiddb/namespaces/description')

        paths = [namespace.path for namespace in namespaces]
        namespacePermissions = dict(getNamespacePermissions(paths))

        parentPaths = [getParentPath(namespace.path)
                       for namespace in namespaces
                       if namespace.parentID is not None]
        parentNamespaces = getNamespaces(paths=parentPaths)
        parentNamespaces = dict((namespace.path, namespace)
                                for namespace in parentNamespaces)

        users = getUsers()
        users = dict((user.id, user) for user in users)

        for namespace in namespaces:
            expectedAbout = u'Object for the namespace %s' % namespace.path
            self.checkAboutValue(namespace, aboutValues, expectedAbout)
            self.checkPathValue(namespace, pathValues)
            self.checkDescriptionValue(namespace, descriptionValues)
            self.checkPermissions(namespace, namespacePermissions, users,
                                  Operation.NAMESPACE_OPERATIONS)
            self.checkParent(namespace, parentNamespaces)
            self.checkValidPath(namespace)
Beispiel #9
0
    def summarizeObject(self, about):
        """Get summary information for an object.

        @param about: The about value of the object to summarize.
        @return: A C{dict} matching the following format::

              {'commentCount':   <count>,
               'followers':      [<username>, ...],
               'relatedObjects': {'<about>': <count>, ...}}
        """
        # List followers.
        result = self._objects.get([about])
        objectID = result.get(about)

        if objectID is None:
            return {'commentCount': 0, 'followers': [], 'relatedObjects': {}}

        paths = self._objects.getTagsForObjects([objectID])
        followers = []
        for path in paths:
            parent = getParentPath(path)
            if parent and not u'/' in parent and path.endswith('/follows'):
                followers.append(parent)

        # Count comments.
        store = getMainStore()
        result = store.find(CommentObjectLink.commentID,
                            CommentObjectLink.objectID == objectID)
        commentCount = result.count()

        # Count related objects. I'm using raw SQL here because don't know how
        # to translate this query to Storm.
        result = store.execute("""
            SELECT about_tag_values."value", summary.count
            FROM (
                  SELECT comment_object_link.object_id AS object_id,
                         COUNT(comment_object_link.comment_id) AS count
                  FROM comment_object_link
                  WHERE comment_object_link.comment_id IN (
                      SELECT comment_object_link.comment_id
                      FROM comment_object_link
                      WHERE comment_object_link.object_id = '{objectID}')
                    AND comment_object_link.object_id != '{objectID}'
                  GROUP BY comment_object_link.object_id
                ) AS summary JOIN about_tag_values
                 ON summary.object_id = about_tag_values.object_id;
        """.format(objectID=objectID))

        relatedObjects = dict(result)

        return {
            'commentCount': commentCount,
            'followers': followers,
            'relatedObjects': relatedObjects
        }
Beispiel #10
0
 def _createTags(self):
     """Create tags."""
     superuser = self.users[u'fluiddb']
     for tag in self._data['tags']:
         path = tag['path']
         parentPath = getParentPath(path)
         name = getPathName(path)
         parentNamespace = self.namespaces[parentPath]
         tagObject = createTag(superuser, parentNamespace, name)
         self._createTagPermissions(tagObject)
         self.tags[path] = tagObject
Beispiel #11
0
    def create(self, values):
        """See L{TagAPI.create}.

        @raises PermissionDeniedError: Raised if the user is not authorized to
            create L{Tag}s.
        """
        pathsAndOperations = [(getParentPath(path), Operation.CREATE_NAMESPACE)
                              for path, description in values]
        deniedOperations = checkPermissions(self._user, pathsAndOperations)
        if deniedOperations:
            raise PermissionDeniedError(self._user.username, deniedOperations)
        return self._api.create(values)
Beispiel #12
0
    def checkParent(self, tag, parentNamespaces):
        """Check that a given L{Tag} has a correct parent.

        @param object: A L{Tag} to check.
        @param parentNamespaces: A C{dict} mapping paths to namespaces
            representing parents.
        """
        parentPath = getParentPath(tag.path)
        parent = parentNamespaces.get(parentPath)
        if tag.namespaceID is None:
            self._log(tag, 'Parent ID is not specified.')
        elif not parent or parent.id != tag.namespaceID:
            self._log(tag, 'Assigned parent is incorrect.')
Beispiel #13
0
 def _createNamespaces(self):
     """Create L{Namespace}s."""
     superuser = self.users[u'fluiddb']
     for namespaceData in self._data['namespaces']:
         path = namespaceData['path']
         parentPath = getParentPath(path)
         parentNamespace = self.namespaces.get(parentPath, None)
         parentID = parentNamespace.id if parentNamespace else None
         namespace = createNamespace(superuser, path, parentID)
         self._createNamespacePermissions(namespace)
         self.namespaces[path] = namespace
         if path in self.users:
             self.users[path].namespaceID = namespace.id
Beispiel #14
0
    def _createPermissions(self, tags):
        """Create L{TagPermission}s for new L{Tag}s.

        L{Tag}s inherit permissions from their parent tag, if one
        is available.

        @param tags: A sequence of new L{Tag}s to create
            L{TagPermission}s for.
        """
        # Preload parent Namespace and NamespacePermission's into Storm's
        # cache.  Simply creating the objects will be enough to get them into
        # the cache.  If there are many objects we need to be careful about
        # overloading the cache, but that isn't an issue here.
        parentPaths = [getParentPath(tag.path) for tag in tags]
        list(getNamespacePermissions(parentPaths))
        for tag in tags:
            createTagPermission(tag)
Beispiel #15
0
    def check(self, values):
        """Check permissions for a L{User} with the L{Role.USER} role.

        @param values: A sequence of C{(path, Operation)} 2-tuples
            representing actions that should be checked.
        @raise UnknownUserError: Raised if a user don't exist for user
            operations.
        @return: A C{list} of C{(path, Operation)} 2-tuples representing
            actions that are denied.
        """
        deniedOperations = []
        storedOperations = set()
        for path, operation in values:
            # Create object is always allowed for normal users.
            if operation == Operation.CREATE_OBJECT:
                continue
            # Create root namespaces is always denied for normal users.
            elif path is None and operation == Operation.CREATE_NAMESPACE:
                deniedOperations.append((path, operation))
                continue
            # Delete root namespaces is always denied for normal users.
            elif (path is not None and getParentPath(path) is None
                  and operation == Operation.DELETE_NAMESPACE):
                deniedOperations.append((path, operation))
                continue
            # User managers are always allowed to perform user operations.
            elif (self._user.role == Role.USER_MANAGER
                  and operation in Operation.USER_OPERATIONS):
                continue
            # Updating user data is only allowed for the own user.
            elif (operation == Operation.UPDATE_USER
                  and self._user.username == path):
                continue
            # All other user operations are always denied for normal users.
            elif operation in Operation.USER_OPERATIONS:
                deniedOperations.append((path, operation))
                continue
            else:
                # Operations that have to be checked in the database.
                storedOperations.add((path, operation))

        if not storedOperations:
            return deniedOperations

        return deniedOperations + self._getDeniedOperations(storedOperations)
Beispiel #16
0
    def create(self, values):
        """See L{NamespaceAPI.create}.

        @raise PermissionDeniedError: Raised if the user is not authorized to
            create L{Namespace}s.
        """
        paths = []
        pathsAndOperations = []
        for path, description in values:
            parentPath = getParentPath(path)
            pathsAndOperations.append((parentPath, Operation.CREATE_NAMESPACE))
            paths.append(path)

        deniedOperations = checkPermissions(self._user, pathsAndOperations)
        if deniedOperations:
            raise PermissionDeniedError(self._user.username, deniedOperations)

        return self._api.create(values)
Beispiel #17
0
    def _createPermissions(self, namespaces):
        """Create L{NamespacePermission}s for new L{Namespace}s.

        L{Namespace}s inherit permissions from their parent namespace, if one
        is available.

        @param namespaces: A sequence of new L{Namespace}s to create
            L{NamespacePermission}s for.
        """
        paths = [namespace.path for namespace in namespaces]
        parentPaths = getParentPaths(paths)
        index = {}
        for parent, permission in getNamespacePermissions(parentPaths):
            index[parent.path] = permission
        for namespace in sorted(namespaces,
                                key=lambda namespace: namespace.path):
            parentPath = getParentPath(namespace.path)
            parentPermission = index.get(parentPath)
            permission = createNamespacePermission(
                namespace, permissionTemplate=parentPermission)
            index[namespace.path] = permission
Beispiel #18
0
 def testGetParentPath(self):
     """
     L{getParentPath} returns the parent path for non-root-level paths.
     """
     self.assertEqual(u'foo', getParentPath(u'foo/bar'))
     self.assertEqual(u'foo/bar', getParentPath(u'foo/bar/baz'))
Beispiel #19
0
 def testGetParentPathWithRootPath(self):
     """
     L{getParentPath} returns C{None} if the path is a root-level path.
     """
     self.assertIdentical(None, getParentPath(u'foo'))