def login(context, request): """ Login Route Login route to authenticate a user against Plone. """ # extract the data __ac_name = request.get("__ac_name", None) __ac_password = request.get("__ac_password", None) logger.info("*** LOGIN %s ***" % __ac_name) if __ac_name is None: api.fail(400, "__ac_name is missing") if __ac_password is None: api.fail(400, "__ac_password is missing") acl_users = api.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 api.is_anonymous(): api.fail(401, "Invalid Credentials") # return the JSON in the same format like the user route return get(context, request, username=__ac_name)
def get_search_results(portal_type=None, uid=None, **kw): """Search the catalog and return the results :returns: Catalog search results :rtype: iterable """ # If we have an UID, return the object immediately if uid is not None: logger.info("UID '%s' found, returning the object immediately" % uid) return u.to_list(get_object_by_uid(uid)) # allow to search search for the Plone Site with portal_type include_portal = False if u.to_string(portal_type) == "Plone Site": include_portal = True # The request may contain a list of portal_types, e.g. # `?portal_type=Document&portal_type=Plone Site` if "Plone Site" in u.to_list(req.get("portal_type")): include_portal = True # Build and execute a catalog query results = search(portal_type=portal_type, uid=uid, **kw) if include_portal: results = list(results) + u.to_list(get_portal()) return results
def logout(context, request): """ Logout Route """ logger.info("*** LOGOUT ***") acl_users = api.get_tool("acl_users") acl_users.logout(request) return {"url": api.url_for("senaite.jsonapi.v1.users"), "success": True}
def search(self, query): """search the catalog """ logger.info("Catalog query={}".format(query)) # Support to set the catalog as a request parameter catalogs = _.to_list(req.get("catalog", None)) if catalogs: return senaiteapi.search(query, catalog=catalogs) # Delegate to the search API of Bika LIMS return senaiteapi.search(query)
def auth(context, request): """ Basic Authentication """ if ploneapi.user.is_anonymous(): request.response.setStatus(401) request.response.setHeader('WWW-Authenticate', 'basic realm="JSONAPI AUTH"', 1) logger.info("*** BASIC AUTHENTICATE ***") return {}
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)
def create_object(container, portal_type, **data): """Creates an object slug :returns: The new created content object :rtype: object """ if "id" in data: # always omit the id as senaite LIMS generates a proper one id = data.pop("id") logger.warn("Passed in ID '{}' omitted! Senaite LIMS " "generates a proper ID for you".format(id)) try: # Is there any adapter registered to handle the creation of this type? adapter = queryAdapter(container, ICreate, name=portal_type) if adapter and adapter.is_creation_delegated(): logger.info("Delegating 'create' operation of '{}' in '{}'".format( portal_type, api.get_path(container))) return adapter.create_object(**data) # Special case for ARs # => return immediately w/o update if portal_type == "AnalysisRequest": obj = create_analysisrequest(container, **data) # Omit values which are already set through the helper data = u.omit(data, "SampleType", "Analyses") # Set the container as the client, as the AR lives in it data["Client"] = container return obj # Standard content creation else: # we want just a minimun viable object and set the data later obj = api.create(container, portal_type) # obj = api.create(container, portal_type, **data) except Unauthorized: fail(401, "You are not allowed to create this content") # Update the object with the given data, but omit the id try: update_object_with_data(obj, data) except APIError: # Failure in creation process, delete the invalid object # NOTE: We bypass the permission checks container._delObject(obj.id) # reraise the error raise return obj
def make_query(self, **kw): """create a query suitable for the catalog """ query = kw.pop("query", {}) query.update(self.get_request_query()) query.update(self.get_custom_query()) query.update(self.get_keyword_query(**kw)) sort_on, sort_order = self.get_sort_spec() if sort_on and "sort_on" not in query: query.update({"sort_on": sort_on}) if sort_order and "sort_order" not in query: query.update({"sort_order": sort_order}) logger.info("make_query:: query={} | catalog={}".format( query, self.catalog)) return query
# -*- coding: utf-8 -*- import pkgutil from senaite.jsonapi import logger from senaite.jsonapi.v1 import routes from senaite.jsonapi import add_route as add_senaite_route __version__ = 1 __date__ = "2017-10-01" BASE_URL = "/senaite/v1" def add_route(route, endpoint=None, **kw): """Add a new JSON API route """ # ensure correct amout of slashes def apiurl(route): return '/'.join(s.strip('/') for s in ["", BASE_URL, route]) return add_senaite_route(apiurl(route), endpoint, **kw) prefix = routes.__name__ + "." for importer, modname, ispkg in pkgutil.iter_modules(routes.__path__, prefix): module = __import__(modname, fromlist="dummy") logger.info("INITIALIZED SENAITE JSONAPI V1 ROUTE ---> %s" % module.__name__)