Esempio n. 1
0
    def add(self, task):
        """Adds a task to the queue. It pushes the task directly to the queue
        server via POST and stores the task in the local pool as well
        :param task: the QueueTask to add
        :return: the added QueueTask object
        :rtype: queue.QueueTask
        """
        # Only QueueTask type is supported
        if not is_task(task):
            raise ValueError("{} is not supported".format(repr(task)))

        # Don't add to the queue if the task is already in there
        if task in self._tasks:
            logger.warn("Task {} ({}) in the queue already".format(
                task.name, task.task_short_uid))
            return None

        # Do not add the task if unique and task for same context and name
        if task.get("unique", False):
            if self.get_tasks_for(task.context_uid, name=task.name):
                logger.debug("Task {} for {} in the queue already".format(
                    task.name, task.context_path))
                return None

        # Add the task to the queue server
        err = None
        try:
            self._post("add", payload=task)
        except (ConnectionError, Timeout, TooManyRedirects) as e:
            err = "{}: {}".format(type(e).__name__, str(e))

        except HTTPError as e:
            status = e.response.status_code or 500
            if status < 500 or status >= 600:
                raise e
            message = e.response.json() or {}
            err = "{}: {}".format(status, message.get("message", str(e)))

        except APIError as e:
            if e.status < 500 or e.status >= 600:
                raise e
            err = "{}: {}".format(e.status, e.message)

        if err:
            # Not able to add the task to the queue server. Keep it locally
            # so it can be synchronized as soon as we have connectivity again
            logger.warn(err)
            capi.get_request().response.setStatus(200)
            task.update({"offline": "add"})

        # Add the task to our local pool
        task.update({"status": "queued"})
        if task not in self._tasks:
            self._tasks.append(task)

            # Sort by priority + created
            self._tasks.sort(key=lambda t: (t.created + (300 * t.priority)))

        return task
Esempio n. 2
0
 def _sync_push(self):
     """Pushes the tasks modified locally to the queue server
     """
     for task in filter(lambda t: t.get("offline"), self._tasks):
         action = task.get("offline")
         action_func = getattr(self, action)
         try:
             task.pop("offline")
             action_func(task)
         except Exception as e:
             # push is not critical to operate, dismiss
             err = "{}: {}".format(type(e).__name__, str(e))
             logger.error(err)
             capi.get_request().response.setStatus(200)
Esempio n. 3
0
def bika_url_fetcher(url):
    """Basically the same as the default_url_fetcher from WeasyPrint,
    but injects the __ac cookie to make an authenticated request to the 
    resource.
    """
    from weasyprint import VERSION_STRING
    from weasyprint.compat import Request
    from weasyprint.compat import urlopen_contenttype

    request = api.get_request()
    __ac = request.cookies.get("__ac", "")

    if request.get_header("HOST") in url:
        result, mime_type, charset = urlopen_contenttype(
            Request(url,
                    headers={
                        'Cookie': "__ac={}".format(__ac),
                        'User-Agent': VERSION_STRING,
                        'Authorization': request._auth,
                    }))
        return dict(file_obj=result,
                    redirected_url=result.geturl(),
                    mime_type=mime_type,
                    encoding=charset)

    return default_url_fetcher(url)
Esempio n. 4
0
def bika_url_fetcher(url):
    """Basically the same as the default_url_fetcher from WeasyPrint,
    but injects the __ac cookie to make an authenticated request to the resource.
    """
    from weasyprint import VERSION_STRING
    from weasyprint.compat import Request
    from weasyprint.compat import urlopen_contenttype

    request = api.get_request()
    __ac = request.cookies.get("__ac", "")

    if request.get_header("HOST") in url:
        result, mime_type, charset = urlopen_contenttype(
            Request(url,
                    headers={
                        'Cookie': "__ac={}".format(__ac),
                        'User-Agent': VERSION_STRING,
                        'Authorization': request._auth,
                    }))
        return dict(file_obj=result,
                    redirected_url=result.geturl(),
                    mime_type=mime_type,
                    encoding=charset)

    return default_url_fetcher(url)
Esempio n. 5
0
def create_sample(**kwargs):
    """Creates a new sample
    """
    values = kwargs and kwargs or {}
    request = _api.get_request()
    date_sampled = DateTime().strftime("%Y-%m-%d")
    values.update({
        "DateSampled": values.get("DateSampled") or date_sampled,
    })
    to_update = ["Client", "Contact", "SampleType"]
    for portal_type in to_update:
        field_value = values.get(portal_type)
        if not field_value:
            field_value = _api.get_uid(get_object(portal_type))
            values[portal_type] = field_value

    services = None
    if "services" in values:
        services = values.pop("services")

    if not services:
        services = map(_api.get_uid, get_objects("AnalysisService"))

    client = _api.get_object_by_uid(values.get("Client"))
    sample = create_analysisrequest(client, request, values, services)
    return sample
Esempio n. 6
0
    def guard(self, action):
        """Returns False if the sample is queued or contains queued analyses
        """
        # Check if this current request life-cycle is handled by a consumer
        request = capi.get_request()
        queue_task_uid = request.get("queue_tuid", "")
        if capi.is_uid(queue_task_uid):
            ctx_id = capi.get_id(self.context)
            logger.info("Skip guard for {}: {}".format(ctx_id, action))
            return True

        # Don't do anything if senaite.queue is not enabled
        if not api.is_queue_enabled():
            return True

        # Check if the sample is queued
        if api.is_queued(self.context, status=["queued"]):
            return False

        # Check whether the sample contains queued analyses
        for brain in self.context.getAnalyses():
            if api.is_queued(brain, status=["queued"]):
                return False

        return True
Esempio n. 7
0
    def _post(self, endpoint, resource=None, payload=None, timeout=10):
        """Sends a POST request to SENAITE's Queue Server
        Raises an exception if the response status is not HTTP 2xx or timeout
        :param endpoint: the endpoint to POST against
        :param resource: (Optional) resource from the endpoint to POST against
        :param payload: (Optional) hashable payload for the POST
        """
        server_url = api.get_server_url()
        parts = "/".join(filter(None, [endpoint, resource]))
        url = "{}/@@API/senaite/v1/queue_server/{}".format(server_url, parts)
        logger.info("** POST: {}".format(url))

        # HTTP Queue Authentication to be added in the request
        auth = QueueAuth(capi.get_current_user().id)

        # Additional information to the payload
        request = capi.get_request()
        if payload is None:
            payload = {}
        payload.update({"__zeo": request.get("SERVER_URL")})

        # This might rise exceptions (e.g. TimeoutException)
        response = self._req.post(url,
                                  json=payload,
                                  auth=auth,
                                  timeout=timeout)

        # Check the request is successful. Raise exception otherwise
        response.raise_for_status()

        # Return the result
        return response.json()
Esempio n. 8
0
def new_task(name, context, **kw):
    """Creates a QueueTask
    :param name: the name of the task
    :param context: the context the task is bound or relates to
    :param min_seconds: (optional) int, minimum seconds to book for the task
    :param max_seconds: (optional) int, maximum seconds to wait for the task
    :param retries: (optional) int, maximum number of retries on failure
    :param username: (optional) str, the name of the user assigned to the task
    :param priority: (optional) int, the priority value for this task
    :param unique: (optional) bool, if True, the task will only be added if
            there is no other task with same name and for same context
    :param chunk_size: (optional) the number of items to process asynchronously
            at once from this task (if it contains multiple elements)
    :return: :class:`QueueTask <QueueTask>`
    :rtype: senaite.queue.queue.QueueTask
    """
    # Skip attrs that are assigned when the QueueTask is instantiated
    exclude = ["task_uid", "name", "request", "context_uid", "context_path"]
    out_keys = filter(lambda k: k not in exclude, kw.keys())
    kwargs = dict(map(lambda k: (k, kw[k]), out_keys))

    # Create the Queue Task
    task = QueueTask(name, api.get_request(), context, **kwargs)

    # Set the username (if provided in kw)
    task.username = kw.get("username", task.username)
    return task
Esempio n. 9
0
def get_request_data(request=None):
    """Get request header/form data

    A typical request behind NGINX looks like this:

    {
        'CONNECTION_TYPE': 'close',
        'CONTENT_LENGTH': '52',
        'CONTENT_TYPE': 'application/x-www-form-urlencoded; charset=UTF-8',
        'GATEWAY_INTERFACE': 'CGI/1.1',
        'HTTP_ACCEPT': 'application/json, text/javascript, */*; q=0.01',
        'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br',
        'HTTP_ACCEPT_LANGUAGE': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7',
        'HTTP_COOKIE': '_ga=GA1.2.1058345096.1522506452; ...',
        'HTTP_HOST': 'senaite.ridingbytes.com',
        'HTTP_ORIGIN': 'https://senaite.ridingbytes.com',
        'HTTP_REFERER': 'https://senaite.ridingbytes.com/clients/client-1/H2O-0054',
        'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
        'HTTP_X_FORWARDED_FOR': '93.238.47.95',
        'HTTP_X_REAL_IP': '93.238.47.95',
        'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest',
        'PATH_INFO': '/VirtualHostBase/https/senaite.ridingbytes.com/senaite/VirtualHostRoot//@@API/update',
        'PATH_TRANSLATED': '/VirtualHostBase/https/senaite.ridingbytes.com/senaite/VirtualHostRoot/@@API/update',
        'QUERY_STRING': '',
        'REMOTE_ADDR': '127.0.0.1',
        'REQUEST_METHOD': 'POST',
        'SCRIPT_NAME': '',
        'SERVER_NAME': 'localhost',
        'SERVER_PORT': '8081',
        'SERVER_PROTOCOL': 'HTTP/1.0',
        'SERVER_SOFTWARE': 'Zope/(2.13.28, python 2.7.12, linux2) ZServer/1.1',
        'channel.creation_time': 1556086048
    }

    :param request: Request object
    :returns: Dictionary of extracted request header/form data
    """ # noqa

    if request is None:
        # get the request
        request = api.get_request()

    # Happens in the test runner
    if not request:
        return {}

    # Try to obtain the real IP address of the client
    forwarded_for = request.get_header("X_FORWARDED_FOR")
    real_ip = request.get_header("X_REAL_IP")
    remote_address = request.get_header("REMOTE_ADDR")

    return {
        "comments": request.form.get("comments", ""),
        "remote_address": forwarded_for or real_ip or remote_address,
        "user_agent": request.get_header("HTTP_USER_AGENT"),
        "referer": request.get_header("HTTP_REFERER"),
    }
Esempio n. 10
0
    def done(self, task):
        """Notifies the queue that the task has been processed successfully.
        Sends a POST to the queue server and removes the task from local pool
        :param task: task's unique id (task_uid) or QueueTask object
        """
        # Tell the queue server the task is done
        task_uid = get_task_uid(task)
        payload = {"task_uid": task_uid}
        err = None
        try:
            self._post("done", payload=payload)
        except (ConnectionError, Timeout, TooManyRedirects) as e:
            err = "{}: {}".format(type(e).__name__, str(e))

        except HTTPError as e:
            status = e.response.status_code or 500
            if status < 500 or status >= 600:
                raise e
            message = e.response.json() or {}
            err = "{}: {}".format(status, message.get("message", str(e)))

        except APIError as e:
            if e.status < 500 or e.status >= 600:
                raise e
            err = "{}: {}".format(e.status, e.message)

        if err:
            # Not able to tell the queue server. Keep it locally so it can be
            # synchronized as soon as we have connectivity again
            logger.warn(err)
            capi.get_request().response.setStatus(200)
            task_uid = get_task_uid(task_uid)
            tasks = filter(lambda t: t.task_uid == task_uid, self._tasks)
            if tasks:
                task = tasks[0]
            else:
                self._tasks.append(task)
            task.update({"offline": "done"})
            return

        # Remove from local pool
        self._tasks = filter(lambda t: t.task_uid != task_uid, self._tasks)
Esempio n. 11
0
def handle_action(context, items_or_uids, action):
    """Simulates the handling of an action when multiple items from a list are
    selected and the action button is pressed
    """
    if not isinstance(items_or_uids, (list, tuple)):
        items_or_uids = [items_or_uids]
    items_or_uids = map(_api.get_uid, items_or_uids)
    request = _api.get_request()
    request.set("workflow_action", action)
    request.set("uids", items_or_uids)
    WorkflowActionHandler(context, request)()
Esempio n. 12
0
def translate_i18n(i18n_msg):
    """Safely translate and convert to UTF8, any zope i18n msgid returned from
    senaite health's message factory
    """
    text = to_unicode(i18n_msg)
    try:
        request = api.get_request()
        domain = getattr(i18n_msg, "domain", "senaite.health")
        text = translate(text, domain=domain, context=request)
    except UnicodeDecodeError:
        logger.warn("{} couldn't be translated".format(text))
    return to_utf8(text)
Esempio n. 13
0
def on_object_edited(instance, event):
    """Event handler when a sample was edited
    """
    # XXX "save" from Sample's header view does not call widget's process_form
    request = api.get_request()
    field_name = "DateOfBirth"
    if field_name in request.form:
        dob_field = instance.getField(field_name)
        dob = dob_field.widget.process_form(instance, dob_field, request.form)
        if dob is not None:
            dob_field.set(instance, dob[0])

    update_patient(instance)
Esempio n. 14
0
def t(i18n_msg):
    """Safely translate and convert to UTF8, any zope i18n msgid returned from
    a bikaMessageFactory _
    """
    text = to_unicode(i18n_msg)
    try:
        request = api.get_request()
        domain = getattr(i18n_msg, "domain", "senaite.core")
        text = translate(text, domain=domain, context=request)
    except UnicodeDecodeError:
        # TODO: This is only a quick fix
        logger.warn("{} couldn't be translated".format(text))
    return to_utf8(text)
Esempio n. 15
0
def process(context, request, task_uid=None):  # noqa
    """Processes the task passed-in
    """
    # disable CSRF
    req.disable_csrf_protection()

    # Maybe the task uid has been sent via POST
    task_uid = task_uid or req.get_json().get("task_uid")

    # Get the task
    task = get_task(task_uid)
    if task.username != capi.get_current_user().id:
        # 403 Authenticated, but user does not have access to the resource
        _fail(403)

    # Process
    t0 = time.time()
    task_context = task.get_context()
    if not task_context:
        _fail(500, "Task's context is not available")

    # Get the adapter able to process this specific type of task
    adapter = queryAdapter(task_context, IQueuedTaskAdapter, name=task.name)
    if not adapter:
        _fail(501, "No adapter found for {}".format(task.name))

    logger.info("Processing task {}: '{}' for '{}' ({}) ...".format(
        task.task_short_uid, task.name, capi.get_id(task_context),
        task.context_uid))

    # Inject the queue_consumer marker to the request so guards skip checks
    # against the queue
    request = capi.get_request()
    request.set("queue_tuid", task_uid)

    # If the task refers to a worksheet, inject (ws_id) in params to make
    # sure guards (assign, un-assign) return True
    if IWorksheet.providedBy(task_context):
        request.set("ws_uid", capi.get_uid(task_context))

    # Process the task
    adapter.process(task)

    # Sleep a bit for minimum effect against userland threads
    # Better to have a transaction conflict here than in userland
    min_seconds = task.get("min_seconds", 3)
    while time.time() - t0 < min_seconds:
        time.sleep(0.5)

    msg = "Processed: {}".format(task.task_short_uid)
    return get_message_summary(msg, "consumer.process")
Esempio n. 16
0
def get_rejection_pdf(sample):
    """Generates a pdf with sample rejection reasons
    """
    # Avoid circular dependencies
    from bika.lims.browser.analysisrequest.reject import \
        AnalysisRequestRejectPdfView

    # Render the html's rejection document
    tpl = AnalysisRequestRejectPdfView(sample, api.get_request())
    html = tpl.template()
    html = safe_unicode(html).encode("utf-8")

    # Generate the pdf
    return createPdf(htmlreport=html)
Esempio n. 17
0
 def __call__(self, context):
     # XXX Workaround for missing context in nested choice widget vocabulary
     if context is None:
         # fetch context from the request
         request = api.get_request()
         if request and request["PARENTS"]:
             context = request["PARENTS"][0]
     items = []
     adapted = IDataBoxBehavior(context, None)
     if adapted is None:
         return SimpleVocabulary.fromValues([])
     for field in adapted.get_fields():
         items.append(SimpleTerm(field, token=field, title=field))
     return SimpleVocabulary(items)
Esempio n. 18
0
 def to_localized_time(self, date, **kw):
     """Converts the given date to a localized time string
     """
     if date is None:
         return ""
     # default options
     options = {
         "long_format": True,
         "time_only": False,
         "context": api.get_portal(),
         "request": api.get_request(),
         "domain": "senaite.core",
     }
     options.update(kw)
     return ulocalized_time(date, **options)
Esempio n. 19
0
def create_sample(services, client, contact, sample_type, receive=True):
    """Creates a new sample with the specified services
    """
    request = _api.get_request()
    values = {
        'Client': client.UID(),
        'Contact': contact.UID(),
        'DateSampled': DateTime().strftime("%Y-%m-%d"),
        'SampleType': sample_type.UID()
    }
    service_uids = map(_api.get_uid, services)
    sample = create_analysisrequest(client, request, values, service_uids)
    if receive:
        do_action_for(sample, "receive")
    transaction.commit()
    return sample
Esempio n. 20
0
def is_worksheet_context():
    """Returns whether the current context from the request is a Worksheet
    """
    request = api.get_request()
    parents = request.get("PARENTS", [])
    portal_types_names = map(lambda p: getattr(p, "portal_type", None), parents)
    if "Worksheet" in portal_types_names:
        return True

    # Check if the worksheet is declared in request explicitly
    ws_uid = request.get("ws_uid", "")
    obj = api.get_object_by_uid(ws_uid, None)
    if IWorksheet.providedBy(obj):
        return True

    return False
Esempio n. 21
0
def process(browser, task_uid):
    """Simulates the processing of the task
    """
    request = _api.get_request()
    site_url = _api.get_url(_api.get_portal())
    url = "{}/@@API/senaite/v1/queue_consumer/process".format(site_url)
    payload = {"task_uid": task_uid}
    browser.post(url, parse.urlencode(payload, doseq=True))

    # We loose the globalrequest each time we do a post with browser
    globalrequest.setRequest(request)

    # Mark the task as done
    api.get_queue().done(task_uid)

    transaction.commit()
    return browser.contents
Esempio n. 22
0
 def __call__(self, context):
     # XXX Workaround for missing context in nested choice widget vocabulary
     if context is None:
         # fetch context from the request
         request = api.get_request()
         if request and request["PARENTS"]:
             context = request["PARENTS"][0]
     items = []
     adapted = IDataBoxBehavior(context, None)
     if adapted is None:
         return SimpleVocabulary.fromValues([])
     catalog = adapted.get_catalog_tool()
     indexes = catalog.getIndexObjects()
     for index in indexes:
         name = index.getId()
         items.append(SimpleTerm(name, token=name, title=name))
     return SimpleVocabulary(items)
Esempio n. 23
0
def clear_department_cookies(event):
    """
    Logout event handler.
    When user explicitly logs out from the Logout menu, clean department
    filtering related cookies.
    """
    if not is_bika_installed():
        logger.warn(
            "Package 'bika.lims' is not installed, skipping event handler "
            "for IUserLoggedOutEvent.")
        return
    request = api.get_request()
    response = request.RESPONSE

    # Voiding our special cookie on logout
    response.setCookie(
        'filter_by_department_info', None,  path='/', max_age=0)
    response.setCookie(
        'dep_filter_disabled', None,  path='/', max_age=0)
Esempio n. 24
0
def to_task(task_dict):
    """Converts a dict representation of a task to a QueueTask object
    :param task_dict: dict that represents a task
    :return: the QueueTask object the passed-in task_dict represents
    :rtype: QueueTask
    """
    name = task_dict.get("name")
    context_uid = task_dict.get("context_uid")
    context_path = task_dict.get("context_path")
    if not all([name, context_uid, context_path]):
        return None

    # Skip attrs that are assigned when the QueueTask is instantiated
    exclude = ["name", "request"]
    out_keys = filter(lambda k: k not in exclude, task_dict.keys())
    kwargs = dict(map(lambda k: (k, task_dict[k]), out_keys))

    # Create the Queue Task
    return QueueTask(name, api.get_request(), context_uid, **kwargs)
Esempio n. 25
0
    def url_fetcher(self, url):
        """Fetches internal URLs by path and not via an external request.

        N.B. Multiple calls to this method might exhaust the available threads
             of the server, which causes a hanging instance.
        """
        if url.startswith("data"):
            logger.info("Data URL, delegate to default URL fetcher...")
            return default_url_fetcher(url)

        logger.info("Fetching URL '{}' for WeasyPrint".format(url))

        # get the pyhsical path from the URL
        request = api.get_request()
        host = request.get_header("HOST")
        path = "/".join(request.physicalPathFromURL(url))

        # fetch the object by sub-request
        portal = api.get_portal()
        context = portal.restrictedTraverse(path, None)

        if context is None or host not in url:
            logger.info("External URL, delegate to default URL fetcher...")
            return default_url_fetcher(url)

        logger.info("Local URL, fetching data by path '{}'".format(path))

        # get the data via an authenticated subrequest
        response = subrequest(path)

        # Prepare the return data as required by WeasyPrint
        string = response.getBody()
        filename = url.split("/")[-1]
        mime_type = mimetypes.guess_type(url)[0]
        redirected_url = url

        return {
            "string": string,
            "filename": filename,
            "mime_type": mime_type,
            "redirected_url": redirected_url,
        }
Esempio n. 26
0
    def process(self, task):
        """Process the task from the queue
        """
        # If there are too many objects to process, split them in chunks to
        # prevent the task to take too much time to complete
        chunks = get_chunks(task["uids"], 50)

        # Process the first chunk
        map(self.reindex_security, chunks[0])

        # Add remaining objects to the queue
        if chunks[1]:
            request = _api.get_request()
            context = task.get_context()
            kwargs = {
                "uids": chunks[1],
                "priority": task.priority,
            }
            new_task = QueueTask(task.name, request, context, **kwargs)
            api.get_queue().add(new_task)
Esempio n. 27
0
def set_department_cookies(event):
    """
    Login event handler.
    When user logs in, departments must be selected if filtering by department
    is enabled in Bika Setup.
        - For (Lab)Managers and Client Contacts, all the departments from the
          system must be selected.
        - For regular Lab Contacts, default Department must be selected. If
          the Contact doesn't have any default department assigned, then first
          department in alphabetical order will be selected.
    """
    if not is_bika_installed():
        logger.warn(
            "Package 'bika.lims' is not installed, skipping event handler "
            "for IUserLoggedInEvent.")
        return

    # get the bika_setup object
    portal = api.get_portal()
    bika_setup = portal.get("bika_setup")

    # just to be sure...
    # This should go into the api.py module once it is in place
    if bika_setup is None:
        raise RuntimeError(
            "bika_setup not found in this Bika LIMS installation")

    # Getting request, response and username
    request = api.get_request()
    response = request.RESPONSE
    user = api.get_current_user()
    username = user and user.getUserName() or None
    is_manager = user and (user.has_role('Manager') or
                           user.has_role('LabManager'))
    portal_catalog = api.get_tool("portal_catalog")

    # If department filtering is disabled, disable the cookies
    if not bika_setup.getAllowDepartmentFiltering():
        response.setCookie(
            'filter_by_department_info', None,  path='/', max_age=0)
        response.setCookie(
            'dep_filter_disabled', None,  path='/', max_age=0)
        return

    selected_deps = []

    # Select all Departments for Lab Managers
    if is_manager:
        selected_deps = portal_catalog(
            portal_type='Department',
            sort_on='sortable_title',
            sort_order='ascending',
            inactive_state='active')

        response.setCookie(
            'dep_filter_disabled', 'true',  path='/',
            max_age=24 * 3600)

    else:
        brain = portal_catalog(getUsername=username)
        # It is possible that current user is created by Plone ZMI.
        # Just log it as a warning and go on
        if not brain:
            logger.warn(
                "No lab Contact found... Plone user or Client "
                "Contact logged in. " + username)
            response.setCookie(
                'filter_by_department_info', None, path='/', max_age=0)
            response.setCookie(
                'dep_filter_disabled', None, path='/', max_age=0)
            return

        # If it is a Client Contact, select all departments no need to filter.
        elif brain[0].portal_type == 'Contact':
            selected_deps = portal_catalog(
                portal_type='Department',
                sort_on='sortable_title',
                sort_order='ascending',
                inactive_state='active')

            response.setCookie(
                'dep_filter_disabled', None, path='/', max_age=24 * 3600)

        # It is a LabContact, select only one department. It must be Default
        # Department of the Lab Contact if possible
        elif brain[0].portal_type == 'LabContact':
            lab_con = brain[0].getObject()
            if lab_con.getDefaultDepartment():
                selected_deps = [lab_con.getDefaultDepartment()]
            else:
                departments = lab_con.getSortedDepartments()
                selected_deps = [departments[0]] if departments else []

            response.setCookie(
                'dep_filter_disabled', None, path='/', max_age=0)

    selected_dep_uids = ','.join([api.get_uid(dep) for dep in selected_deps])
    response.setCookie(
        'filter_by_department_info',
        selected_dep_uids,
        path='/',
        max_age=24 * 3600)

    return
Esempio n. 28
0
 def request(self):
     request = api.get_request()
     if not isinstance(request, HTTPRequest):
         return None
     return request
Esempio n. 29
0
 def wrapper(*args, **kw):
     # set the content type header
     request = api.get_request()
     request.response.setHeader("Content-Type", "application/json")
     return func(*args, **kw)
Esempio n. 30
0
def is_installed():
    """Returns whether the product is installed or not
    """
    request = get_request()
    return ISenaitePatientLayer.providedBy(request)
Esempio n. 31
0
def senaite_url_fetcher(url):
    """Uses plone.subrequest to fetch an internal image resource.

    If the URL points to an external resource, the URL is handed
    to weasyprint.default_url_fetcher.

    Please see these links for details:

        - https://github.com/plone/plone.subrequest
        - https://pypi.python.org/pypi/plone.subrequest
        - https://github.com/senaite/senaite.core/issues/538

    :returns: A dict with the following keys:

        * One of ``string`` (a byte string) or ``file_obj``
          (a file-like object)
        * Optionally: ``mime_type``, a MIME type extracted e.g. from a
          *Content-Type* header. If not provided, the type is guessed from the
          file extension in the URL.
        * Optionally: ``encoding``, a character encoding extracted e.g. from a
          *charset* parameter in a *Content-Type* header
        * Optionally: ``redirected_url``, the actual URL of the resource
          if there were e.g. HTTP redirects.
        * Optionally: ``filename``, the filename of the resource. Usually
          derived from the *filename* parameter in a *Content-Disposition*
          header

        If a ``file_obj`` key is given, it is the caller’s responsibility
        to call ``file_obj.close()``.
    """

    logger.info("Fetching URL '{}' for WeasyPrint".format(url))

    # get the pyhsical path from the URL
    request = api.get_request()
    host = request.get_header("HOST")
    path = "/".join(request.physicalPathFromURL(url))

    # fetch the object by sub-request
    portal = api.get_portal()
    context = portal.restrictedTraverse(path, None)

    # We double check here to avoid an edge case, where we have the same path
    # as well in our local site, e.g. we have `/senaite/img/systems/senaite.png`,
    # but the user requested http://www.ridingbytes.com/img/systems/senaite.png:
    #
    # "/".join(request.physicalPathFromURL("http://www.ridingbytes.com/img/systems/senaite.png"))
    # '/senaite/img/systems/senaite.png'
    if context is None or host not in url:
        logger.info(
            "URL is external, passing over to the default URL fetcher...")
        return default_url_fetcher(url)

    logger.info(
        "URL is local, fetching data by path '{}' via subrequest".format(path))

    # get the data via an authenticated subrequest
    response = subrequest(path)

    # Prepare the return data as required by WeasyPrint
    string = response.getBody()
    filename = url.split("/")[-1]
    mime_type = mimetypes.guess_type(url)[0]
    redirected_url = url

    return {
        "string": string,
        "filename": filename,
        "mime_type": mime_type,
        "redirected_url": redirected_url,
    }