예제 #1
0
def get_task(task_uid):
    """Resolves the task for the given task uid
    """
    if not capi.is_uid(task_uid) or task_uid == "0":
        # 400 Bad Request, wrong task uid
        _fail(412, "Task uid empty or no valid format")

    task = api.get_queue().get_task(task_uid)
    if not task:
        _fail(404, "Task {}".format(task_uid))

    if not capi.is_uid(task.context_uid):
        _fail(500, "Task's context uid is not valid")

    return task
예제 #2
0
    def _to_service(self, thing):
        """Convert to Analysis Service

        :param thing: UID/Catalog Brain/Object/Something
        :returns: Analysis Service object or None
        """

        # Convert UIDs to objects
        if api.is_uid(thing):
            thing = api.get_object_by_uid(thing, None)

        # Bail out if the thing is not a valid object
        if not api.is_object(thing):
            logger.warn("'{}' is not a valid object!".format(repr(thing)))
            return None

        # Ensure we have an object here and not a brain
        obj = api.get_object(thing)

        if IAnalysisService.providedBy(obj):
            return obj

        if IAnalysis.providedBy(obj):
            return obj.getAnalysisService()

        # An object, but neither an Analysis nor AnalysisService?
        # This should never happen.
        portal_type = api.get_portal_type(obj)
        logger.error("ARAnalysesField doesn't accept objects from {} type. "
                     "The object will be dismissed.".format(portal_type))
        return None
예제 #3
0
def _process_value(value):
    """Convert the value into a human readable diff string
    """
    if not value:
        value = _("Not set")
    # handle strings
    elif isinstance(value, basestring):
        # XXX: bad data, e.g. in AS Method field
        if value == "None":
            value = _("Not set")
        # 0 is detected as the portal UID
        elif value == "0":
            value = "0"
        # handle physical paths
        elif value.startswith("/"):
            # remove the portal path to reduce noise in virtual hostings
            portal_path = api.get_path(api.get_portal())
            value = value.replace(portal_path, "", 1)
        elif api.is_uid(value):
            value = _get_title_or_id_from_uid(value)
    # handle dictionaries
    elif isinstance(value, (dict)):
        value = json.dumps(sorted(value.items()), indent=1)
    # handle lists and tuples
    elif isinstance(value, (list, tuple)):
        value = sorted(map(_process_value, value))
        value = "; ".join(value)
    # handle unicodes
    if isinstance(value, unicode):
        value = api.safe_unicode(value).encode("utf8")
    return str(value)
예제 #4
0
    def _to_service(self, thing):
        """Convert to Analysis Service

        :param thing: UID/Catalog Brain/Object/Something
        :returns: Analysis Service object or None
        """

        # Convert UIDs to objects
        if api.is_uid(thing):
            thing = api.get_object_by_uid(thing, None)

        # Bail out if the thing is not a valid object
        if not api.is_object(thing):
            logger.warn("'{}' is not a valid object!".format(repr(thing)))
            return None

        # Ensure we have an object here and not a brain
        obj = api.get_object(thing)

        if IAnalysisService.providedBy(obj):
            return obj

        if IAnalysis.providedBy(obj):
            return obj.getAnalysisService()

        # An object, but neither an Analysis nor AnalysisService?
        # This should never happen.
        msg = "ARAnalysesField doesn't accept objects from {} type. " \
            "The object will be dismissed.".format(api.get_portal_type(obj))
        logger.warn(msg)
        return None
예제 #5
0
def is_result_range_compliant(analysis):
    """Returns whether the result range from the analysis matches with the
    result range for the service counterpart defined in the Sample
    """
    if not IRequestAnalysis.providedBy(analysis):
        return True

    if IDuplicateAnalysis.providedBy(analysis):
        # Does not make sense to apply compliance to a duplicate, cause its
        # valid range depends on the result of the original analysis
        return True

    rr = analysis.getResultsRange()
    service_uid = rr.get("uid", None)
    if not api.is_uid(service_uid):
        return True

    # Compare with Sample
    sample = analysis.getRequest()

    # If no Specification is set, assume is compliant
    specification = sample.getRawSpecification()
    if not specification:
        return True

    # Compare with the Specification that was initially set to the Sample
    sample_rr = sample.getResultsRange(search_by=service_uid)
    if not sample_rr:
        # This service is not defined in Sample's ResultsRange, we
        # assume this *does not* break the compliance
        return True

    return rr == sample_rr
예제 #6
0
 def get_object_at(self, row, column):
     """Returns an object this container contains at the given position
     """
     uid = self.get_uid_at(row, column)
     if not api.is_uid(uid):
         return None
     return api.get_object_by_uid(uid, default=None)
예제 #7
0
def _get_object(context, value):
    """Resolve a UID to an object.

    :param context: context is the object containing the field's schema.
    :type context: BaseContent
    :param value: A UID.
    :type value: string
    :return: Returns a Content object or None.
    :rtype: BaseContent
    """
    if not value:
        return None
    if api.is_brain(value):
        return api.get_object(value)
    if api.is_object(value):
        return value
    if api.is_uid(value):
        uc = api.get_tool('uid_catalog', context=context)
        brains = uc(UID=value)
        if len(brains) == 0:
            # Broken Reference!
            logger.warn("Reference on {} with UID {} is broken!"
                        .format(repr(context), value))
            return None
        return brains[0].getObject()
    return None
예제 #8
0
    def metadata_to_searchable_text(self, brain, key, value):
        """Parse the given metadata to text

        :param brain: ZCatalog Brain
        :param key: The name of the metadata column
        :param value: The raw value of the metadata column
        :returns: Searchable and translated unicode value or None
        """
        if not value:
            return u""
        if value is Missing.Value:
            return u""
        if api.is_uid(value):
            return u""
        if isinstance(value, (bool)):
            return u""
        if isinstance(value, (list, tuple)):
            for v in value:
                return self.metadata_to_searchable_text(brain, key, v)
        if isinstance(value, (dict)):
            for k, v in value.items():
                return self.metadata_to_searchable_text(brain, k, v)
        if self.is_date(value):
            return self.to_str_date(value)
        if "state" in key.lower():
            return self.translate_review_state(value,
                                               api.get_portal_type(brain))
        if not isinstance(value, basestring):
            value = str(value)
        return safe_unicode(value)
예제 #9
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
예제 #10
0
 def process_value(self, value):
     """Process publication value
     """
     # UID -> SuperModel
     if api.is_uid(value):
         # Do not process "0" as the portal object
         # -> Side effect in specifications when the value is "0"
         if value == "0":
             return "0"
         return self.to_super_model(value)
     # Content -> SuperModel
     elif api.is_object(value):
         return self.to_super_model(value)
     # String -> Unicode
     elif isinstance(value, basestring):
         return safe_unicode(value).encode("utf-8")
     # DateTime -> DateTime
     elif isinstance(value, DateTime):
         return value
     # Process list values
     elif isinstance(value, (LazyMap, list, tuple)):
         return map(self.process_value, value)
     # Process dict values
     elif isinstance(value, (dict)):
         return {k: self.process_value(v) for k, v in value.iteritems()}
     # Process function
     elif safe_callable(value):
         return self.process_value(value())
     # Always return the unprocessed value last
     return value
예제 #11
0
def to_service_uid(uid_brain_obj_str):
    """Resolves the passed in element to a valid uid. Returns None if the value
    cannot be resolved to a valid uid
    """
    if api.is_uid(uid_brain_obj_str) and uid_brain_obj_str != "0":
        return uid_brain_obj_str

    if api.is_object(uid_brain_obj_str):
        obj = api.get_object(uid_brain_obj_str)

        if IAnalysisService.providedBy(obj):
            return api.get_uid(obj)

        elif IRoutineAnalysis.providedBy(obj):
            return obj.getServiceUID()

        else:
            logger.error("Type not supported: {}".format(obj.portal_type))
            return None

    if isinstance(uid_brain_obj_str, six.string_types):
        # Maybe is a keyword?
        query = dict(portal_type="AnalysisService",
                     getKeyword=uid_brain_obj_str)
        brains = api.search(query, SETUP_CATALOG)
        if len(brains) == 1:
            return api.get_uid(brains[0])

        # Or maybe a title
        query = dict(portal_type="AnalysisService", title=uid_brain_obj_str)
        brains = api.search(query, SETUP_CATALOG)
        if len(brains) == 1:
            return api.get_uid(brains[0])

    return None
예제 #12
0
 def get_brain(self, uid, catalog):
     if not api.is_uid(uid):
         return None
     query = dict(UID=uid)
     brains = api.search(query, catalog)
     if brains and len(brains) == 1:
         return brains[0]
     return None
예제 #13
0
 def get_brain(self, uid, catalog):
     if not api.is_uid(uid):
         return None
     query = dict(UID=uid)
     brains = api.search(query, catalog)
     if brains and len(brains) == 1:
         return brains[0]
     return None
예제 #14
0
 def to_super_model(self, thing):
     """Wraps an object into a Super Model
     """
     if api.is_uid(thing):
         return SuperModel(thing)
     if not api.is_object(thing):
         raise TypeError("Expected a portal object, got '{}'".format(
             type(thing)))
     return thing
예제 #15
0
    def get_object(self, brain_or_object_or_uid):
        """Get the full content object. Returns None if the param passed in is
        not a valid, not a valid object or not found

        :param brain_or_object_or_uid: UID/Catalog brain/content object
        :returns: content object
        """
        if api.is_uid(brain_or_object_or_uid):
            return api.get_object_by_uid(brain_or_object_or_uid, default=None)
        if api.is_object(brain_or_object_or_uid):
            return api.get_object(brain_or_object_or_uid)
        return None
예제 #16
0
def get_task(task_uid):
    """Resolves the task for the given task uid
    """
    if not api.is_uid(task_uid) or task_uid == "0":
        # 400 Bad Request, wrong task uid
        _fail(412, "Task uid empty or no valid format")

    task = qapi.get_queue().get_task(task_uid)
    if not task:
        _fail(404, "Task {}".format(task_uid))

    return task
예제 #17
0
    def addDepartment(self, dep):
        """Adds a department

        :param dep: UID or department object
        :returns: True when the department was added
        """
        if api.is_uid(dep):
            dep = api.get_object_by_uid(dep)
        deps = self.getDepartments()
        if dep not in deps:
            return False
        deps.append(dep)
        self.setDepartments(deps)
        return True
예제 #18
0
    def __call__(self):
        form = self.request.form

        # Form submit toggle
        form_submitted = form.get("submitted", False)
        form_store = form.get("button_store", False)
        form_cancel = form.get("button_cancel", False)

        # Get the container
        container = self.get_container()
        if not container:
            return self.redirect(message=_s("No items selected"),
                                 level="warning")
        if not IStorageSamplesContainer.providedBy(container):
            logger.warn("Not a samples container: {}").format(repr(container))
            self.redirect(redirect_url=self.get_next_url())

        # If container is full, there is no way to add more samples there
        if container.is_full():
            message = _("Cannot store samples. Samples container {} is full")
            return self.redirect(message=message.format(api.get_id(container)),
                                 level="warning")

        # Handle store
        if form_submitted and form_store:
            alpha_position = form.get("position")
            sample_uid = form.get("sample_uid")
            if not alpha_position or not api.is_uid(sample_uid):
                message = _("No position or not valid sample selected")
                return self.redirect(message=message)

            sample = api.get_object(sample_uid)
            logger.info("Storing sample {} in {} at {}".format(
                api.get_id(sample), api.get_id(container), alpha_position))

            # Store
            position = container.alpha_to_position(alpha_position)
            if container.add_object_at(sample, position[0], position[1]):
                message = _("Stored sample {} at position {}").format(
                    api.get_id(sample), alpha_position)
                if container.is_full():
                    return self.redirect(redirect_url=self.get_next_url())
                return self.redirect(redirect_url=self.get_fallback_url(),
                                     message=message)

        # Handle cancel
        if form_submitted and form_cancel:
            return self.redirect(message=_("Sample storing canceled"))

        return self.template()
예제 #19
0
    def removeDepartment(self, dep):
        """Removes a department

        :param dep: UID or department object
        :returns: True when the department was removed
        """
        if api.is_uid(dep):
            dep = api.get_object_by_uid(dep)
        deps = self.getDepartments()
        if dep not in deps:
            return False
        deps.remove(dep)
        self.setDepartments(deps)
        return True
예제 #20
0
    def addReferenceAnalysis(self, service):
        """
        Creates a new Reference Analysis object based on this Sample
        Reference, with the type passed in and associates the newly
        created object to the Analysis Service passed in.

        :param service: Object, brain or UID of the Analysis Service
        :param reference_type: type of ReferenceAnalysis, where 'b' is is
        Blank and 'c' is Control
        :type reference_type: A String
        :returns: the newly created Reference Analysis
        :rtype: string
        """
        if api.is_uid(service) or api.is_brain(service):
            return self.addReferenceAnalysis(api.get_object(service))

        if not IAnalysisService.providedBy(service):
            return None

        interim_fields = service.getInterimFields()
        analysis = _createObjectByType("ReferenceAnalysis", self, id=tmpID())
        # Copy all the values from the schema
        # TODO Add Service as a param in ReferenceAnalysis constructor and do
        #      this logic there instead of here
        discard = [
            'id',
        ]
        keys = service.Schema().keys()
        for key in keys:
            if key in discard:
                continue
            if key not in analysis.Schema().keys():
                continue
            val = service.getField(key).get(service)
            # Campbell's mental note:never ever use '.set()' directly to a
            # field. If you can't use the setter, then use the mutator in order
            # to give the value. We have realized that in some cases using
            # 'set' when the value is a string, it saves the value
            # as unicode instead of plain string.
            # analysis.getField(key).set(analysis, val)
            mutator_name = analysis.getField(key).mutator
            mutator = getattr(analysis, mutator_name)
            mutator(val)
        analysis.setAnalysisService(service)
        ref_type = self.getBlank() and 'b' or 'c'
        analysis.setReferenceType(ref_type)
        analysis.setInterimFields(interim_fields)
        analysis.unmarkCreationFlag()
        renameAfterCreation(analysis)
        return analysis
예제 #21
0
    def __init__(self, thing):

        # Type based initializers
        if isinstance(thing, basestring) and thing == "0":
            self.init_with_instance(api.get_portal())
        elif api.is_uid(thing):
            self.init_with_uid(thing)
        elif api.is_brain(thing):
            self.init_with_brain(thing)
        elif api.is_object(thing):
            self.init_with_instance(thing)
        else:
            raise TypeError("Can not initialize a SuperModel with '{}'".format(
                repr(thing)))
예제 #22
0
    def process(self, task):
        """Transition the objects from the task
        """
        # The worksheet is the context
        worksheet = self.context

        uids = task.get("uids", [])
        slots = task.get("slots", [])

        # Sanitize the slots list and pad with empties
        slots = map(lambda s: _api.to_int(s, None) or "", slots)
        slots += [""] * abs(len(uids) - len(slots))

        # Sort analyses so those with an assigned slot are added first
        # Note numeric values get precedence over strings, empty strings here
        uids_slots = zip(uids, slots)
        uids_slots = sorted(uids_slots, key=lambda i: i[1])

        # Remove those with no valid uids
        uids_slots = filter(lambda us: _api.is_uid(us[0]), uids_slots)

        # Remove duplicate uids while keeping the order
        seen = set()
        uids_slots = filter(lambda us: not (us[0] in seen or seen.add(us[0])),
                            uids_slots)

        # Remove uids that are already in the worksheet (just in case)
        layout = filter(None, worksheet.getLayout() or [])
        existing = map(lambda r: r.get("analysis_uid"), layout)
        uids_slots = filter(lambda us: us[0] not in existing, uids_slots)

        # 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_for(task, items=uids_slots)

        # Process the first chunk
        for uid, slot in chunks[0]:
            # Add the analysis
            slot = slot or None
            analysis = _api.get_object_by_uid(uid)
            worksheet.addAnalysis(analysis, slot)

        # Reindex the worksheet
        worksheet.reindexObject()

        if chunks[1]:
            # Unpack the remaining analyses-slots and add them to the queue
            uids, slots = zip(*chunks[1])
            api.add_assign_task(worksheet, analyses=uids, slots=slots)
예제 #23
0
 def get_client_from_query(self, query, purge=False):
     """Resolves the client from the query passed-in
     """
     keys = ["getPrimaryReferrerUID", "getClientUID", "getParentUID", "UID"]
     for key in keys:
         uid = query.get(key)
         if not api.is_uid(uid) or uid == "0":
             continue
         client = api.get_object_by_uid(uid)
         if IClient.providedBy(client):
             if purge:
                 # Remove the key:value from the query
                 del (query[key])
             return client
     return None
예제 #24
0
def get_task_uid(task_or_uid, default=_marker):
    """Returns the task unique identifier
    :param task_or_uid: QueueTask/task uid/dict
    :param default: (Optional) fallback value
    :return: the task's unique identifier
    """
    if api.is_uid(task_or_uid) and task_or_uid != "0":
        return task_or_uid
    if isinstance(task_or_uid, QueueTask):
        return get_task_uid(task_or_uid.task_uid, default=default)
    if isinstance(task_or_uid, dict):
        task_uid = task_or_uid.get("task_uid", None)
        return get_task_uid(task_uid, default=default)
    if default is _marker:
        raise ValueError("{} is not supported".format(repr(task_or_uid)))
    return default
예제 #25
0
    def getResultRange(self, values, uid_keyword_service):
        if not uid_keyword_service:
            return None

        if api.is_object(uid_keyword_service):
            uid_keyword_service = api.get_uid(uid_keyword_service)

        key = "keyword"
        if api.is_uid(uid_keyword_service) and uid_keyword_service != "0":
            # We always assume a uid of "0" refers to portal
            key = "uid"

        # Find out the item for the given uid/keyword
        from bika.lims.content.analysisspec import ResultsRangeDict
        value = filter(lambda v: v.get(key) == uid_keyword_service, values)
        return value and ResultsRangeDict(dict(value[0].items())) or None
예제 #26
0
    def __init__(self, name, request, context, *arg, **kw):
        super(QueueTask, self).__init__(*arg, **kw)
        if api.is_uid(context):
            context_uid = context
            context_path = kw.get("context_path")
            if not context_path:
                raise ValueError("context_path is missing")

        elif api.is_object(context):
            context_uid = api.get_uid(context)
            context_path = api.get_path(context)

        else:
            raise TypeError("No valid context object")

        # Set defaults
        kw = kw or {}
        task_uid = str(kw.get("task_uid", tmpID()))
        uids = map(str, kw.get("uids", []))
        created = api.to_float(kw.get("created"), default=time.time())
        status = kw.get("status", None)
        min_sec = api.to_int(kw.get("min_seconds"), default=get_min_seconds())
        max_sec = api.to_int(kw.get("max_seconds"), default=get_max_seconds())
        priority = api.to_int(kw.get("priority"), default=10)
        retries = api.to_int(kw.get("retries"), default=get_max_retries())
        unique = self._is_true(kw.get("unique", False))
        chunks = api.to_int(kw.get("chunk_size"), default=get_chunk_size(name))
        username = kw.get("username", self._get_authenticated_user(request))
        err_message = kw.get("error_message", None)

        self.update({
            "task_uid": task_uid,
            "name": name,
            "context_uid": context_uid,
            "context_path": context_path,
            "uids": uids,
            "created": created,
            "status": status and str(status) or None,
            "error_message": err_message and str(err_message) or None,
            "min_seconds": min_sec,
            "max_seconds": max_sec,
            "priority": priority,
            "retries": retries,
            "unique": unique,
            "chunk_size": chunks,
            "username": str(username),
        })
예제 #27
0
    def resolve_uid(self, result_range):
        """Resolves the uid key for the result_range passed in if it does not
        exist when contains a keyword
        """
        value = result_range.copy()
        uid = value.get("uid")
        if api.is_uid(uid) and uid != "0":
            return value

        # uid key does not exist or is not valid, try to infere from keyword
        keyword = value.get("keyword")
        if keyword:
            query = dict(portal_type="AnalysisService", getKeyword=keyword)
            brains = api.search(query, SETUP_CATALOG)
            if len(brains) == 1:
                uid = api.get_uid(brains[0])
        value["uid"] = uid
        return value
예제 #28
0
    def resolve_to_uid(item):
        if api.is_uid(item):
            return item
        elif IAnalysisService.providedBy(item):
            return item.UID()
        elif IRoutineAnalysis.providedBy(item):
            return item.getServiceUID()

        bsc = api.get_tool("bika_setup_catalog")
        brains = bsc(portal_type='AnalysisService', getKeyword=item)
        if brains:
            return brains[0].UID
        brains = bsc(portal_type='AnalysisService', title=item)
        if brains:
            return brains[0].UID
        raise RuntimeError(
            str(item) + " should be the UID, title, keyword "
            " or title of an AnalysisService.")
예제 #29
0
    def resolve_uid(self, raw_dict):
        """Returns a copy of the raw dictionary passed in, but with additional
        key "uid". It's value is inferred from "keyword" if present
        """
        value = raw_dict.copy()
        uid = value.get("uid")
        if api.is_uid(uid) and uid != "0":
            return value

        # uid key does not exist or is not valid, try to infere from keyword
        keyword = value.get("keyword")
        if keyword:
            query = dict(portal_type="AnalysisService", getKeyword=keyword)
            brains = api.search(query, SETUP_CATALOG)
            if len(brains) == 1:
                uid = api.get_uid(brains[0])
        value["uid"] = uid
        return value
예제 #30
0
    def get_form_value(self, form_key, object_brain_uid, default=None):
        """Returns a value from the request's form for the given uid, if any
        """
        if form_key not in self.request.form:
            return default

        uid = object_brain_uid
        if not api.is_uid(uid):
            uid = api.get_uid(object_brain_uid)

        values = self.request.form.get(form_key)
        if isinstance(values, list):
            if len(values) == 0:
                return default
            if len(values) > 1:
                logger.warn("Multiple set of values for {}".format(form_key))
            values = values[0]

        return values.get(uid, default)
예제 #31
0
def _process_value(value):
    """Convert the value into a human readable diff string
    """
    if not value:
        value = _("Not set")
    # XXX: bad data, e.g. in AS Method field
    elif value == "None":
        value = _("Not set")
    # 0 is detected as the portal UID
    elif value == "0":
        pass
    elif api.is_uid(value):
        value = _get_title_or_id_from_uid(value)
    elif isinstance(value, (dict)):
        value = json.dumps(sorted(value.items()), indent=1)
    elif isinstance(value, (list, tuple)):
        value = sorted(map(_process_value, value))
        value = "; ".join(value)
    elif isinstance(value, unicode):
        value = api.safe_unicode(value).encode("utf8")
    return str(value)
예제 #32
0
    def _get_service_uid(self, item):
        if api.is_uid(item):
            return item

        if not api.is_object(item):
            logger.warn("Not an UID: {}".format(item))
            return None

        obj = api.get_object(item)
        if IAnalysisService.providedBy(obj):
            return api.get_uid(obj)

        if IAnalysis.providedBy(obj) and IRequestAnalysis.providedBy(obj):
            return obj.getServiceUID()

        # An object, but neither an Analysis nor AnalysisService?
        # This should never happen.
        msg = "ARAnalysesField doesn't accept objects from {} type. " \
              "The object will be dismissed."
        logger.warn(msg.format(api.get_portal_type(obj)))
        return None