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 = u.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
def get_object_by_record(record): """Find an object by a given record Inspects request the record to locate an object :param record: A dictionary representation of an object :type record: dict :returns: Found Object or None :rtype: object """ # nothing to do here if not record: return None if record.get("uid"): return get_object_by_uid(record["uid"]) if record.get("path"): return get_object_by_path(record["path"]) if record.get("parent_path") and record.get("id"): path = "/".join([record["parent_path"], record["id"]]) return get_object_by_path(path) logger.warn("get_object_by_record::No object found! record='%r'" % record) return None
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
def resource_to_portal_type(resource): """Converts a resource to a portal type :param resource: Resource name as it is used in the content route :type name: string :returns: Portal type name :rtype: string """ if resource is None: return None resource_mapping = get_resource_mapping() portal_type = resource_mapping.get(resource.lower()) # BBB: Handle pre 0.9.1 resource routes, e.g. folders, collections... if portal_type is None and resource.endswith("s"): new_resource = resource.rstrip("s") portal_type = resource_mapping.get(new_resource) if portal_type: logger.warn("Old style resources will be removed in 1.0. " "Please use '{}' instead of '{}'".format( new_resource, resource)) if portal_type is None: logger.warn("Could not map the resource '{}' " "to any known portal type".format(resource)) return portal_type
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")
def set(self, instance, value, **kw): """Converts the value into a DateTime object before setting. """ try: value = DateTime(value) except SyntaxError: logger.warn( "Value '{}' is not a valid DateTime string".format(value)) return False self._set(instance, value, **kw)
def set(self, instance, value, **kw): """Converts the value into a DateTime object before setting. """ try: value = DateTime(value) except SyntaxError: logger.warn("Value '{}' is not a valid DateTime string" .format(value)) return False self._set(instance, value, **kw)
def json_data(self, instance, default=None): """Get a JSON compatible value """ value = self.get(instance) out = [] for rel in value: if rel.isBroken(): logger.warn("Skipping broken relation {}".format(repr(rel))) continue obj = rel.to_object out.append(api.get_url_info(obj)) return out
def get_user_info(user): """Get the user information """ user = api.get_user(user) current = api.get_current_user() if api.is_anonymous(): return { "username": current.getUserName(), "authenticated": False, "roles": current.getRoles(), "api_url": api.url_for("plone.jsonapi.routes.users", username="******"), } # nothing to do if user is None: logger.warn("No user found for {}".format(user)) return None # plone user pu = user.getUser() info = { "username": user.getUserName(), "roles": user.getRoles(), "groups": pu.getGroups(), "authenticated": current == user, "api_url": api.url_for("plone.jsonapi.routes.users", username=user.getId()), } for k, v in api.get_user_properties(user).items(): if api.is_date(v): v = api.to_iso_date(v) if not api.is_json_serializable(v): logger.warn( "User property '{}' is not JSON serializable".format(k)) continue info[k] = v return info
def url_for(endpoint, **values): """Looks up the API URL for the given endpoint :param endpoint: The name of the registered route :type endpoint: string :returns: External URL for this endpoint :rtype: string/None """ try: return router.url_for(endpoint, force_external=True, values=values) except Exception: # XXX plone.jsonapi.core should catch the BuildError of Werkzeug and # throw another error which can be handled here. logger.warn("Could not build API URL for endpoint '%s'. " "No route provider registered?" % endpoint) return None
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") # https://github.com/collective/plone.jsonapi.routes/issues/77 # filter out bogus keywords # XXX Maybe we should pass only values where we have identical field names? field_kwargs = u.omit(record, "file") # Iterate through record items for k, v in record.items(): try: success = dm.set(k, v, **field_kwargs) 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)
def get_user_info(user): """Get the user information """ user = api.get_user(user) current = api.get_current_user() if api.is_anonymous(): return { "username": current.getUserName(), "authenticated": False, "roles": current.getRoles(), "api_url": api.url_for("plone.jsonapi.routes.users", username="******"), } # nothing to do if user is None: logger.warn("No user found for {}".format(user)) return None # plone user pu = user.getUser() info = { "username": user.getUserName(), "roles": user.getRoles(), "groups": pu.getGroups(), "authenticated": current == user, "api_url": api.url_for("plone.jsonapi.routes.users", username=user.getId()), } for k, v in api.get_user_properties(user).items(): if api.is_date(v): v = api.to_iso_date(v) if not api.is_json_serializable(v): logger.warn("User property '{}' is not JSON serializable".format(k)) continue info[k] = v return info
def to_json_value(obj, fieldname, value=_marker, default=None): """JSON save value encoding :param obj: Content object :type obj: ATContentType/DexterityContentType :param fieldname: Schema name of the field :type fieldname: str/unicode :param value: The field value :type value: depends on the field type :returns: JSON encoded field value :rtype: field dependent """ # This function bridges the value of the field to a probably more complex # JSON structure to return to the client. # extract the value from the object if omitted if value is _marker: value = IDataManager(obj).json_data(fieldname) # convert objects if isinstance(value, ImplicitAcquisitionWrapper): return get_url_info(value) # convert dates if is_date(value): return to_iso_date(value) # check if the value is callable if callable(value): value = value() # check if the value is JSON serializable if not is_json_serializable(value): logger.warn("Output {} is not JSON serializable".format(repr(value))) return default return value
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: logger.warn("Unknown Exception: Field={} Value={}".format(self.field, value))
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")
def set(self, name, value, **kw): """Setter is not used for catalog brains """ logger.warn("Setting is not allowed on catalog brains")