Ejemplo n.º 1
0
def copy_items(portal_type=None, request=None, uid=None, endpoint=None):
    """ copy items
    """

    # try to find the requested objects
    objects = find_objects(uid=uid)

    # No objects could be found, bail out
    if not objects:
        raise APIError(404, "No Objects could be found")

    # We support only to copy a single object
    if len(objects) > 1:
        raise APIError(400, "Can only copy one object at a time")

    # We don't want to copy the portal object
    if filter(lambda o: is_root(o), objects):
        raise APIError(400, "Can not copy the portal object")

    # cut the object
    obj = objects[0]
    obj.aq_parent.manage_copyObjects(obj.getId(), REQUEST=request)
    request.response.setHeader("Content-Type", "application/json")
    info = IInfo(obj)()

    return [info]
Ejemplo n.º 2
0
def update_object_with_data(content, record):
    """ update the content with the values from records
    """
    dm = IDataManager(content, None)
    if dm is None:
        raise APIError(400, "Update on this object is not allowed")
    for k, v in record.items():
        try:
            success = dm.set(k, v)
        except Unauthorized:
            raise APIError(401,
                           "You are not allowed to set the field '%s'" % k)

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

        logger.info("update_object_with_data::field %r updated with value=%r",
                    k, v)

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

    # reindex the object
    content.reindexObject()
    return content
Ejemplo n.º 3
0
def delete_items(portal_type=None, request=None, uid=None, endpoint=None):
    """ delete items

    1. If the uid is given, we can ignore the request body and delete the
       object with the given uid (if the uid was valid).
    2. If no uid is given, the user wants to delete more than one item.
       => go through each item and extract the uid. Delete it afterwards.
       // we should do this kind of transaction base. So if we can not get an
       // object for an uid, no item will be deleted.
    3. we could check if the portal_type matches, just to be sure the user
       wants to delete the right content.
    """

    # try to find the requested objects
    objects = find_objects(uid=uid)

    # We don't want to delete the portal object
    if filter(lambda o: is_root(o), objects):
        raise APIError(400, "Can not delete the portal object")

    results = []
    for obj in objects:
        info = IInfo(obj)()
        info["deleted"] = delete_object(obj)
        results.append(info)

    if not results:
        raise APIError(404, "No Objects could be found")

    return results
Ejemplo n.º 4
0
def find_target_container(record):
    """Locates a target container for the given record

    :param record: The dictionary representation of a content object
    :type record: dict
    :returns: folder which contains the object
    :rtype: object
    """
    parent_uid = record.get("parent_uid")
    parent_path = record.get("parent_path")

    target = None

    # Try to find the target object
    if parent_uid:
        target = get_object_by_uid(parent_uid)
    elif parent_path:
        target = get_object_by_path(parent_path)
        # Issue 18
        if target is None:
            target = mkdir(parent_path)
    else:
        raise APIError(404, "No target UID/PATH information found")

    if not target:
        raise APIError(404, "No target container found")

    return target
Ejemplo n.º 5
0
def paste_items(portal_type=None, request=None, uid=None, endpoint=None):
    """ paste items
    """

    # try to find the requested objects
    objects = find_objects(uid=uid)

    # No objects could be found, bail out
    if not objects:
        raise APIError(404, "No Objects could be found")

    # check if the cookie is there
    cookie = req.get_cookie("__cp")
    if cookie is None:
        raise APIError(400, "No data found to paste")

    # We support only to copy a single object
    if len(objects) > 1:
        raise APIError(400, "Can only paste to one location")

    # cut the object
    obj = objects[0]

    # paste the object
    results = obj.manage_pasteObjects(cookie)

    out = []
    for result in results:
        new_id = result.get("new_id")
        pasted = obj.get(new_id)
        if pasted:
            out.append(IInfo(pasted)())

    return out
Ejemplo n.º 6
0
def login(context, request):
    """ Login Route

    Login route to authenticate a user against Plone.
    """
    # extract the data
    __ac_name = request.form.get("__ac_name", None)
    __ac_password = request.form.get("__ac_password", None)

    logger.info("*** LOGIN %s ***" % __ac_name)

    if __ac_name is None:
        raise APIError(400, "Username is missing")
    if __ac_password is None:
        raise APIError(400, "Password is missing")

    acl_users = ploneapi.portal.get_tool("acl_users")

    # XXX hard coded
    acl_users.credentials_cookie_auth.login()

    # XXX amin user won't be logged in if I use this approach
    # acl_users.login()
    # response = request.response
    # acl_users.updateCredentials(request, response, __ac_name, __ac_password)

    if ploneapi.user.is_anonymous():
        raise APIError(401, "Invalid Credentials")

    # return the JSON in the same format like the user route
    return get_user(context, request, username=__ac_name)
Ejemplo n.º 7
0
def delete_object(obj):
    """ delete the object """
    # we do not want to delete the site root!
    if is_root(obj):
        raise APIError(401, "Removing the Portal is not allowed")
    try:
        success = ploneapi.content.delete(obj) == None and True or False
    except Unauthorized:
        raise APIError(
            401, "You are not allowed to delete the object '%s'" % obj.getId())
Ejemplo n.º 8
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
    """

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

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

    if dm is None:
        raise APIError(400, "Update on this object is not allowed")

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

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

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

    # 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_action_for(content, t)

    # do a sharing update
    if record.get("sharing", None):
        s = record.get("sharing")
        logger.debug(">>> Update sharing to %r for Object %s", s,
                     content.getId())
        update_sharing_for(content, s)

    # reindex the object
    content.reindexObject()
    return content
Ejemplo n.º 9
0
def delete_object(brain_or_object):
    """Delete the given object

    :param brain_or_object: A single catalog brain or content object
    :type brain_or_object: ATContentType/DexterityContentType/CatalogBrain
    :returns: Nothing
    :rtype: None
    """
    obj = get_object(brain_or_object)
    # we do not want to delete the site root!
    if is_root(obj):
        raise APIError(401, "Removing the Portal is not allowed")
    try:
        return ploneapi.content.delete(obj) is None and True or False
    except Unauthorized:
        raise APIError(401, "Not allowed to delete object '%s'" % obj.getId())
Ejemplo n.º 10
0
def mkdir(path):
    """Crate a folder structure by a given path

    Behavior is similar to `mkdir -p`

    :param path: The physical path of the folder
    :type path: string
    :returns: folder located at the path
    :rtype: object
    """
    container = get_portal()
    segments = path.split("/")
    curpath = None

    for n, segment in enumerate(segments):
        # skip the first element
        if not segment:
            continue

        curpath = "/".join(segments[:n + 1])
        obj = get_object_by_path(curpath)

        if obj:
            container = obj
            continue

        if not is_folderish(container):
            raise APIError(400, "Object at %s is not a folder" % curpath)

        # create the folder on the go
        container = ploneapi.content.create(container,
                                            type="Folder",
                                            id=segment)

    return container
Ejemplo n.º 11
0
def create_items(portal_type=None, request=None, uid=None, endpoint=None):
    """ create items

    1. If the uid is given, get the object and create the content in there
       (assumed that it is folderish)
    2. If the uid is 0, the target folder is assumed the portal.
    3. If there is no uid given, the payload is checked for either a key
        - `parent_uid`  specifies the *uid* of the target folder
        - `parent_path` specifies the *physical path* of the target folder
    """

    # destination where to create the content
    dest = uid and get_object_by_uid(uid) or None

    # extract the data from the request
    records = req.get_request_data()

    results = []
    for record in records:
        if dest is None:
            # find the container for content creation
            dest = find_target_container(record)
        if portal_type is None:
            portal_type = record.get("portal_type", None)
        id = record.get("id", None)
        title = record.get("title", None)
        obj = create_object_in_container(dest, portal_type, id=id, title=title)
        # update the object
        update_object_with_data(obj, record)
        results.append(obj)

    if not results:
        raise APIError(400, "No Objects could be created")

    return make_items_for(results, endpoint=endpoint)
Ejemplo n.º 12
0
def mkdir(path):
    """ creates a folder structure by a given path
    """

    container = get_portal()
    segments = path.split("/")
    curpath = None

    for n, segment in enumerate(segments):
        # skip the first element
        if not segment:
            continue

        curpath = "/".join(segments[:n + 1])
        obj = get_object_by_path(curpath)

        if obj:
            container = obj
            continue

        if not is_folderish(container):
            raise APIError(400, "Object at %s is not a folder" % curpath)

        # create the folder on the go
        container = ploneapi.content.create(container,
                                            type="Folder",
                                            title=segment,
                                            save_id=True)

    return container
Ejemplo n.º 13
0
def get_object_by_uid(uid):
    """ Fetches an object by uid
    """

    # nothing to do here
    if uid is None:
        return None

    # define uid 0 as the portal object
    if str(uid).lower() in PORTAL_IDS:
        return get_portal()

    # we try to find the object with both catalogs
    pc = get_portal_catalog()
    rc = get_portal_reference_catalog()

    # try to find the object with the reference catalog first
    obj = rc.lookupObject(uid)
    if obj:
        return obj

    # try to find the object with the portal catalog
    res = pc(dict(UID=uid))
    if len(res) > 1:
        raise APIError(400, "More than one object found for UID %s" % uid)
    if not res:
        return None

    return get_object(res[0])
Ejemplo n.º 14
0
def create_object(**kw):
    defaults = {"save_id": True}
    defaults.update(kw)
    try:
        return ploneapi.content.create(**defaults)
    except Unauthorized:
        raise APIError(401, "You are not allowed to create this content")
Ejemplo n.º 15
0
def get(context, request, resource=None, uid=None):
    """Get Plone contents, e.g.

    <Plonesite>/@@API/plone/api/1.0/folder -> returns all folders
    <Plonesite>/@@API/plone/api/1.0/folder/4711 -> returns the folder with UID 4711
    """

    # We have a UID, return the record
    if uid and not resource:
        return api.get_record(uid)

    # we have a UID as resource, return the record
    if api.is_uid(resource):
        return api.get_record(resource)

    # BBB
    if resource == "get":
        logger.warn(
            "The /get route is obsolete and will be removed in 1.0.0. Please use /<UID> instead"
        )
        return api.get_record(uid)

    portal_type = api.resource_to_portal_type(resource)
    if portal_type is None:
        raise APIError(404, "Not Found")
    return api.get_batched(portal_type=portal_type,
                           uid=uid,
                           endpoint="plone.jsonapi.routes.get")
Ejemplo n.º 16
0
def get_object_by_path(path):
    """Find an object by a given physical path

    :param path: The physical path of the object to find
    :type path: string
    :returns: Found Object or None
    :rtype: object
    """

    # nothing to do here
    if not path:
        return None

    pc = get_portal_catalog()
    portal = get_portal()
    portal_path = get_path(portal)

    if not path.startswith(portal_path):
        raise APIError(404, "Not a physical path inside the portal")

    if path == portal_path:
        return portal

    res = pc(path=dict(query=path, depth=0))
    if not res:
        return None
    return get_object(res[0])
Ejemplo n.º 17
0
 def get_schema(self):
     """ get the schema
     """
     try:
         return self.context.Schema()
     except AttributeError:
         raise APIError(400, "Can not get Schema of %r" % self.context)
Ejemplo n.º 18
0
def get_request_data():
    """ extract and convert the json data from the request

    returns a list of dictionaries
    """
    request = get_request()
    data = request.get("BODY", "{}")
    if not is_json_deserializable(data):
        from plone.jsonapi.routes.exceptions import APIError
        raise APIError(400, "Request Data is not JSON deserializable – Check JSON Syntax!")
    return _.convert(json.loads(data), _.to_list)
Ejemplo n.º 19
0
def create_object_in_container(container, portal_type, id=None, title=None):
    """ creates an object with the given data in the container
    """
    if not is_root(container) and portal_type not in get_locally_allowed_types(
            container):
        raise APIError(
            500,
            "Creation of this portal type is not allowed in this context.")
    return create_object(container=container,
                         id=id,
                         title=title,
                         type=portal_type)
Ejemplo n.º 20
0
def create_object(**kw):
    """Creates an object

    :returns: The new created content object
    :rtype: object
    """
    defaults = {"save_id": True}
    defaults.update(kw)
    try:
        return ploneapi.content.create(**defaults)
    except Unauthorized:
        raise APIError(401, "You are not allowed to create this content")
Ejemplo n.º 21
0
def get_record(uid=None):
    """ returns a single record
    """
    obj = None
    if uid is not None:
        obj = get_object_by_uid(uid)
    else:
        form = req.get_form()
        obj = get_object_by_record(form)
    if obj is None:
        raise APIError(404, "No object found")
    items = make_items_for([obj])
    return _.first(items)
Ejemplo n.º 22
0
def find_target_container(record):
    """ find the target container for this record
    """

    parent_uid = record.get("parent_uid")
    parent_path = record.get("parent_path")

    target = None

    # Try to find the target object
    if parent_uid:
        target = get_object_by_uid(parent_uid)
    elif parent_path:
        target = get_object_by_path(parent_path)
        # Issue 18
        if target is None:
            target = mkdir(parent_path)
    else:
        raise APIError(404, "No target UID/PATH information found")

    if not target:
        raise APIError(404, "No target container found")

    return target
Ejemplo n.º 23
0
def get_record(uid=None):
    """ returns a single record
    """
    obj = None
    if uid is not None:
        obj = get_object_by_uid(uid)
    else:
        form = req.get_form()
        obj = get_object_by_record(form)
    if obj is None:
        raise APIError(404, "No object found")
    complete = req.get_complete(default=_marker)
    if complete is _marker:
        complete = True
    items = make_items_for([obj], complete=complete)
    return _.first(items)
Ejemplo n.º 24
0
def create_object_in_container(container, portal_type, id=None, title=None):
    """Creates a content object in the specified container

    :param container: A single folderish catalog brain or content object
    :type container: ATContentType/DexterityContentType/CatalogBrain
    :param portal_type: The portal type to create
    :type portal_type: string
    :returns: The new content object
    :rtype: object
    """
    container = get_object(container)
    allowed_types = get_locally_allowed_types(container)
    if not is_root(container) and portal_type not in allowed_types:
        raise APIError(
            500, "Creation of this portal type"
            "is not allowed in this context.")

    return create_object(container=container,
                         id=id,
                         title=title,
                         type=portal_type)
Ejemplo n.º 25
0
def delete_items(portal_type=None, request=None, uid=None, endpoint=None):
    """ delete items

    1. If the uid is given, we can ignore the request body and delete the
       object with the given uid (if the uid was valid).
    2. If no uid is given, the user wants to delete more than one item.
       => go through each item and extract the uid. Delete it afterwards.
       // we should do this kind of transaction base. So if we can not get an
       // object for an uid, no item will be deleted.
    3. we could check if the portal_type matches, just to be sure the user
       wants to delete the right content.
    """

    # the data to update
    records = req.get_request_data()

    # we have an uid -> try to get an object for it
    obj = get_object_by_uid(uid)
    if obj:
        info = IInfo(obj)()
        info["deleted"] = delete_object(obj)
        return [info]

    # no uid -> go through the record items
    results = []
    for record in records:
        obj = get_object_by_record(record)

        # no object found for this record
        if obj is None:
            continue

        info = IInfo(obj)()
        info["deleted"] = delete_object(obj)
        results.append(info)

    if not results:
        raise APIError(400, "No Objects could be deleted")

    return results
Ejemplo n.º 26
0
def get_object_by_path(path):
    """ fetch the object by physical path
    """

    # nothing to do here
    if not path:
        return None

    pc = get_portal_catalog()
    portal = get_portal()
    portal_path = get_path(portal)

    if not path.startswith(portal_path):
        raise APIError(404, "Not a physical path inside the portal")

    if path == portal_path:
        return portal

    res = pc(path=dict(query=path, depth=0))
    if not res:
        return None
    return get_object(res[0])
Ejemplo n.º 27
0
def update_items(portal_type=None, request=None, uid=None, endpoint=None):
    """ update items

    1. If the uid is given, the user wants to update the object with the data
       given in request body
    2. If no uid is given, the user wants to update a bunch of objects.
       -> each record contains either an UID, path or parent_path + id
    """

    # the data to update
    records = req.get_request_data()

    # we have an uid -> try to get an object for it
    obj = get_object_by_uid(uid)
    if obj:
        record = records[0]  # ignore other records if we got an uid
        obj = update_object_with_data(obj, record)
        return make_items_for([obj], endpoint=endpoint)

    # no uid -> go through the record items
    results = []
    for record in records:
        obj = get_object_by_record(record)

        # no object found for this record
        if obj is None:
            continue

        # update the object with the given record data
        obj = update_object_with_data(obj, record)
        results.append(obj)

    if not results:
        raise APIError(400, "No Objects could be updated")

    return make_items_for(results, endpoint=endpoint)
Ejemplo n.º 28
0
def fail(status, msg):
    """API Error
    """
    if msg is None:
        msg = "Reason not given."
    raise APIError(status, "{}".format(msg))