Пример #1
0
    def get_keyword_query(self, **kw):
        """Generates a query from the given keywords.
        Only known indexes make it into the generated query.

        :returns: Catalog query
        :rtype: dict
        """
        query = dict()

        # Only known indexes get observed
        indexes = self.catalog.get_indexes()

        # Handle additional keyword parameters
        for k, v in kw.iteritems():
            # handle uid in keywords
            if k.lower() == "uid":
                k = "UID"
            # handle portal_type in keywords
            if k.lower() == "portal_type":
                if v:
                    v = _.to_list(v)
            if k not in indexes:
                logger.warn("Skipping unknown keyword parameter '%s=%s'" %
                            (k, v))
                continue
            if v is None:
                logger.warn("Skip None value in kw parameter '%s=%s'" % (k, v))
                continue
            logger.debug("Adding '%s=%s' to query" % (k, v))
            query[k] = v

        return query
Пример #2
0
    def _set(self, instance, value, **kw):
        """Set the value of the field
        """
        logger.debug("DexterityFieldManager::set: value=%r" % value)

        # Check if the field is read only
        if self.field.readonly:
            raise Unauthorized("Field is read only")

        fieldname = self.get_field_name()
        # id fields take only strings
        if fieldname == "id":
            value = str(value)

        try:
            # Validate
            self.field.validate(value)

            # TODO: Check security on the field level
            return self.field.set(instance, value)
        except WrongType:
            logger.warn("WrongType: Field={} Value={}".format(
                self.field, value))
        except:  # noqa
            logger.warn("Unknown Exception: Field={} Value={}".format(
                self.field, value))
Пример #3
0
    def _set(self, instance, value, **kw):
        """Set the value of the field
        """
        logger.debug("ATFieldManager::set: value=%r" % value)

        # check field permission
        if not self.field.checkPermission("write", instance):
            raise Unauthorized(
                "You are not allowed to write the field {}".format(self.name))

        # check if field is writable
        if not self.field.writeable(instance):
            raise Unauthorized("Field {} is read only.".format(self.name))

        # id fields take only strings
        if self.name == "id":
            value = str(value)

        # get the field mutator
        mutator = self.field.getMutator(instance)

        # Inspect function and apply *args and **kwargs if possible.
        mapply(mutator, value, **kw)

        return True
Пример #4
0
    def extract_fields(self):
        """Extract the given fieldnames from the object

        :returns: Schema name/value mapping
        :rtype: dict
        """

        # get the proper data manager for the object
        dm = IDataManager(self.context)

        # filter out ignored fields
        fieldnames = filter(lambda name: name not in self.ignore, self.keys)

        # schema mapping
        out = dict()

        for fieldname in fieldnames:
            try:
                # get the field value with the data manager
                fieldvalue = dm.json_data(fieldname)
            # https://github.com/collective/plone.jsonapi.routes/issues/52
            # -> skip restricted fields
            except Unauthorized:
                logger.debug("Skipping restricted field '%s'" % fieldname)
                continue
            except ValueError:
                logger.debug("Skipping invalid field '%s'" % fieldname)
                continue

            out[fieldname] = api.to_json_value(self.context, fieldname,
                                               fieldvalue)

        return out
Пример #5
0
    def _get(self, instance, **kw):
        """Get the value of the field
        """
        logger.debug("DexterityFieldManager::get: instance={} field={}".format(
            instance, self.field))

        # TODO: Check security on the field level
        return self.field.get(instance)
Пример #6
0
    def get_index(self, name):
        """get an index by name

        TODO: Combine indexes of relevant catalogs depending on the portal_type
        which is searched for.
        """
        catalog = self.get_catalog()
        index = catalog._catalog.getIndex(name)
        logger.debug("get_index={} of catalog '{}' --> {}".format(
            name, catalog.__name__, index))
        return index
Пример #7
0
    def set(self, instance, value, **kw):
        """Decodes base64 value and set the file object
        """
        value = str(value).decode("base64")

        # handle the filename
        if "filename" not in kw:
            logger.debug("FielFieldManager::set: No Filename detected "
                         "-> using title or id")
            kw["filename"] = kw.get("id") or kw.get("title")

        self._set(instance, value, **kw)
Пример #8
0
    def _get(self, instance, **kw):
        """Get the value of the field
        """
        logger.debug("ATFieldManager::get: instance={} field={}".format(
            instance, self.field))

        # check the field permission
        if not self.field.checkPermission("read", instance):
            raise Unauthorized(
                "You are not allowed to read the field {}".format(self.name))

        # return the field value
        return self.field.get(instance)
Пример #9
0
def update_object_with_data(content, record):
    """Update the content with the record data

    :param content: A single folderish catalog brain or content object
    :type content: ATContentType/DexterityContentType/CatalogBrain
    :param record: The data to update
    :type record: dict
    :returns: The updated content object
    :rtype: object
    :raises:
        APIError,
        :class:`~plone.jsonapi.routes.exceptions.APIError`
    """

    # ensure we have a full content object
    content = get_object(content)

    # Look for an update-specific adapter for this object
    adapter = queryAdapter(content, IUpdate)
    if adapter:
        # Use the adapter to update the object
        logger.info("Delegating 'update' operation of '{}'".format(
            api.get_path(content)))
        adapter.update_object(**record)

    else:
        # Fall-back to default update machinery
        # get the proper data manager
        dm = IDataManager(content)

        if dm is None:
            fail(400, "Update for this object is not allowed")

        # Bail-out non-update-able fields
        purged_records = copy.deepcopy(record)
        map(lambda key: purged_records.pop(key, None), SKIP_UPDATE_FIELDS)

        # Iterate through record items
        for k, v in purged_records.items():
            try:
                success = dm.set(k, v, **record)
            except Unauthorized:
                fail(401, "Not allowed to set the field '%s'" % k)
            except ValueError, exc:
                fail(400, str(exc))

            if not success:
                logger.warn("update_object_with_data::skipping key=%r", k)
                continue

            logger.debug("update_object_with_data::field %r updated", k)
Пример #10
0
    def _set(self, instance, value, **kw):
        """Set the value of the field
        """
        logger.debug("DexterityFieldManager::set: value=%r" % value)

        # Check if the field is read only
        if self.field.readonly:
            raise Unauthorized("Field is read only")

        # Validate
        self.field.validate(value)

        # TODO: Check security on the field level
        return self.field.set(instance, value)
Пример #11
0
    def set(self, instance, value, **kw):
        logger.debug(
            "NamedFileFieldManager::set:File field"
            "detected ('%r'), base64 decoding value", self.field)

        data = str(value).decode("base64")
        filename = kw.get("filename") or kw.get("id") or kw.get("title")
        contentType = kw.get("mimetype") or kw.get("content_type")

        if contentType:
            # create NamedFile with content type information
            value = self.field._type(data=data,
                                     contentType=contentType,
                                     filename=filename)
        else:
            # create NamedFile w/o content type information
            # -> will be guessed by the extension of the filename
            value = self.field._type(data=data, filename=filename)

        return self.field.set(instance, value)
Пример #12
0
def update_object_with_data(content, record):
    """Update the content with the record data

    :param content: A single folderish catalog brain or content object
    :type content: ATContentType/DexterityContentType/CatalogBrain
    :param record: The data to update
    :type record: dict
    :returns: The updated content object
    :rtype: object
    :raises:
        APIError,
        :class:`~plone.jsonapi.routes.exceptions.APIError`
    """

    # ensure we have a full content object
    content = get_object(content)

    # get the proper data manager
    dm = IDataManager(content)

    if dm is None:
        fail(400, "Update for this object is not allowed")

    # Iterate through record items
    for k, v in record.items():
        try:
            success = dm.set(k, v, **record)
        except Unauthorized:
            fail(401, "Not allowed to set the field '%s'" % k)
        except ValueError, exc:
            fail(400, str(exc))

        if not success:
            logger.warn("update_object_with_data::skipping key=%r", k)
            continue

        logger.debug("update_object_with_data::field %r updated", k)
Пример #13
0
        if not success:
            logger.warn("update_object_with_data::skipping key=%r", k)
            continue

        logger.debug("update_object_with_data::field %r updated", k)

    # Validate the entire content object
    invalid = validate_object(content, record)
    if invalid:
        fail(400, u.to_json(invalid))

    # do a wf transition
    if record.get("transition", None):
        t = record.get("transition")
        logger.debug(">>> Do Transition '%s' for Object %s", t,
                     content.getId())
        do_transition_for(content, t)

    # reindex the object
    content.reindexObject()
    return content


def validate_object(brain_or_object, data):
    """Validate the entire object

    :param brain_or_object: A single catalog brain or content object
    :type brain_or_object: ATContentType/DexterityContentType/CatalogBrain
    :param data: The sharing dictionary as returned from the API
    :type data: dict
    :returns: invalidity status