def _apply_filter_by_client(self): # If the current context is a Client, filter Patients by Client UID if IClient.providedBy(self.context): client_uid = api.get_uid(self.context) self.contentFilter['getPrimaryReferrerUID'] = client_uid return # If the current user is a Client contact, filter the Patients in # accordance. For the rest of users (LabContacts), the visibility of # the patients depend on their permissions user = api.get_current_user() roles = user.getRoles() if 'Client' not in roles: return # Are we sure this a ClientContact? # May happen that this is a Plone member, w/o having a ClientContact # assigned or having a LabContact assigned... weird contact = api.get_user_contact(user) if not contact or ILabContact.providedBy(contact): return # Is the parent from the Contact a Client? client = api.get_parent(contact) if not client or not IClient.providedBy(client): return client_uid = api.get_uid(client) self.contentFilter['getPrimaryReferrerUID'] = client_uid
def changeWorkflowState(content, wf_id, state_id, **kw): """Change the workflow state of an object @param content: Content obj which state will be changed @param state_id: name of the state to put on content @param kw: change the values of same name of the state mapping @return: True if succeed. Otherwise, False """ portal_workflow = api.get_tool("portal_workflow") workflow = portal_workflow.getWorkflowById(wf_id) if not workflow: logger.error("%s: Cannot find workflow id %s" % (content, wf_id)) return False wf_state = { 'action': kw.get("action", None), 'actor': kw.get("actor", api.get_current_user().id), 'comments': "Setting state to %s" % state_id, 'review_state': state_id, 'time': DateTime() } # Change status and update permissions portal_workflow.setStatusOf(wf_id, content, wf_state) workflow.updateRoleMappingsFor(content) # Map changes to catalog indexes = ["allowedRolesAndUsers", "review_state", "is_active"] content.reindexObject(idxs=indexes) return True
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()
def folderitems(self): """Custom folderitems :returns: listing items """ # XXX: Should be done via the Worflow # Check edit permissions self.allow_edit = False member = api.get_current_user() roles = member.getRoles() if set(roles).intersection(ALLOW_EDIT): self.allow_edit = True # Analysis Services retrieval and custom item creation items = [] services = self.get_services() for num, service in enumerate(services): item = self.folderitem(service, {}, num) if item: items.append(item) self.categories = self.get_sorted_categories(items) return items
def _apply_filter_by_client(self): """ If the user has the role Client, the user can not see batches from client objects he/she does not belong to. """ # If the current context is a Client, filter Batches by Client UID if IClient.providedBy(self.context): client_uid = api.get_uid(self.context) self.contentFilter['getClientUID'] = client_uid return # If the current user is a Client contact, filter the Batches in # accordance. For the rest of users (LabContacts), the visibility of # the Batches depend on their permissions user = api.get_current_user() roles = user.getRoles() if 'Client' not in roles: return # Are we sure this a ClientContact? # May happen that this is a Plone member, w/o having a ClientContact # assigned or having a LabContact assigned... weird contact = api.get_user_contact(user) if not contact or ILabContact.providedBy(contact): return # Is the parent from the Contact a Client? client = api.get_parent(contact) if not client or not IClient.providedBy(client): return client_uid = api.get_uid(client) self.contentFilter['getClientUID'] = client_uid
def guard_deliver(context): """Guard for deliver transition. Returns true if a Courier has been assigned to the Sample and the Sample (context) is active. Note we do not check for roles or client here because permissions for clients when the sample is in state `sample_shipped` are already defined in the workflow definition. """ sample = get_sample(context) if not sample: return False # If sample is inactive, we cannot deliver the sample to the lab if not api.is_active(sample): return False # If sample does not have a courier assigned, we cannot deliver if not sample.Schema()['Courier'].get(sample): return False # If the current user is a Client contact, do not allow to deliver user = api.get_current_user() if "Client" in user.getRoles(): return False return True
def user_has_super_roles(): """Return whether the current belongs to superuser roles """ member = api.get_current_user() super_roles = ["LabManager", "Manager"] diff = filter(lambda role: role in super_roles, member.getRoles()) return len(diff) > 0
def before_sample(analysis_request): """Method triggered before "sample" transition for the Analysis Request passed in is performed """ if not analysis_request.getDateSampled(): analysis_request.setDateSampled(DateTime()) if not analysis_request.getSampler(): analysis_request.setSampler(api.get_current_user().id)
def __call__(self): url = api.get_url(api.get_portal()) current_user = api.get_current_user() contact = api.get_user_contact(current_user) if contact: parent = api.get_parent(contact) url = api.get_url(parent) return self.request.response.redirect(url)
def _folder_item_analyst(self, obj, item): is_editable = self.is_analysis_edition_allowed(obj) if not is_editable: item['Analyst'] = obj.getAnalystName return # Analyst is editable item['Analyst'] = obj.getAnalyst or api.get_current_user().id item['choices']['Analyst'] = self.get_analysts()
def guard_sample(analysis_request): """Returns whether 'sample' transition can be performed or not. Returns True only if the analysis request has the DateSampled and Sampler set or if the user belongs to the Samplers group """ if analysis_request.getDateSampled() and analysis_request.getSampler(): return True current_user = api.get_current_user() return "Sampler" in current_user.getRolesInContext(analysis_request)
def user_can_delete_attachments(self): """Checks if the current logged in user is allowed to delete attachments """ context = self.context user = api.get_current_user() if not self.is_ar_editable(): return False return (self.user_can_add_attachments() and not user.allowed(context, ["Client"])) or \ self.user_can_update_attachments()
def is_edit_allowed(self): """Check if edit is allowed """ current_user = api.get_current_user() roles = current_user.getRoles() if "LabManager" in roles: return True if "Manager" in roles: return True return False
def _get_authenticated_user(self, request): authenticated_user = request.get("AUTHENTICATED_USER") if authenticated_user: if hasattr(authenticated_user, "getId"): return authenticated_user.getId() if isinstance(authenticated_user, six.string_types): return authenticated_user # Pick current user current_user = api.get_current_user() return current_user and current_user.id or ""
def guard_send_to_pot(context): """Guard for sending the sample to the point of testing """ if not api.is_active(context): return False # If the current user is a Client contact, do not allow to deliver user = api.get_current_user() if "Client" in user.getRoles(): return False return True
def __call__(self): plone.protect.CheckAuthenticator(self.request) curr_user = api.get_current_user() contact = api.get_user_contact(curr_user, contact_types=['Contact']) parent = contact and contact.getParent() or None if parent and not IClient.providedBy(parent): parent = None ret = {'ClientTitle': parent and parent.Title() or '', 'ClientID': parent and parent.getClientID() or '', 'ClientSysID': parent and parent.id or '', 'ClientUID': parent and parent.UID() or '',} return json.dumps(ret)
def folderitems(self): """Processed once for all analyses """ # XXX: Should be done via the Worflow # Check edit permissions self.allow_edit = False member = api.get_current_user() roles = member.getRoles() if set(roles).intersection(ALLOW_EDIT): self.allow_edit = True items = super(AnalysisProfileAnalysesView, self).folderitems() self.categories.sort() return items
def current_user(self): user = api.get_current_user() # XXX: we're missing here LDAP properties! # needs to be fixed in the API. properties = api.get_user_properties(user) properties.update({ "userid": user.getId(), "username": user.getUserName(), "roles": user.getRoles(), "email": user.getProperty("email"), "fullname": user.getProperty("fullname"), }) return properties
def to_history_record(self, value): """Transforms the value to an history record """ user = api.get_current_user() contact = api.get_user_contact(user) fullname = contact and contact.getFullname() or "" if not contact: # get the fullname from the user properties props = api.get_user_properties(user) fullname = props.get("fullname", "") return RemarksHistoryRecord(user_id=user.id, user_name=fullname, content=value.strip())
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")
def isVisible(self, field, mode="view", default="visible"): edit_modes = ["sample_received", "to_be_verified"] if mode == "edit": if api.get_review_status(self.context) not in edit_modes: return "invisible" # Only Lab Manager can edit Assay Date! allowed_roles = ["LabManager", "Manager", "Analyst"] user = api.get_current_user() user_roles = user.getRolesInContext(self.context) allowed_roles = filter(lambda r: r in user_roles, allowed_roles) if not allowed_roles: return "invisible" return default
def get_current_client(self, default=None): """Returns the client the current user belongs to """ user = api.get_current_user() roles = user.getRoles() if 'Client' not in roles: return default contact = api.get_user_contact(user) if not contact or ILabContact.providedBy(contact): return default client = api.get_parent(contact) if not client or not IClient.providedBy(client): return default return client
def after_reinstate(analysis_request): """Method triggered after a 'reinstate' transition for the Analysis Request passed in is performed. Sets its status to the last status before it was cancelled. Reinstates the descendant partitions and all the analyses associated to the analysis request as well. """ do_action_to_descendants(analysis_request, "reinstate") do_action_to_analyses(analysis_request, "reinstate") # Force the transition to previous state before the request was cancelled prev_status = get_prev_status_from_history(analysis_request, "cancelled") changeWorkflowState(analysis_request, AR_WORKFLOW_ID, prev_status, action="reinstate", actor=api.get_current_user().getId()) analysis_request.reindexObject()
def changeWorkflowState(content, wf_id, state_id, **kw): """Change the workflow state of an object @param content: Content obj which state will be changed @param state_id: name of the state to put on content @param kw: change the values of same name of the state mapping @return: True if succeed. Otherwise, False """ portal_workflow = api.get_tool("portal_workflow") workflow = portal_workflow.getWorkflowById(wf_id) if not workflow: logger.error("%s: Cannot find workflow id %s" % (content, wf_id)) return False wf_state = { 'action': kw.get("action", None), 'actor': kw.get("actor", api.get_current_user().id), 'comments': "Setting state to %s" % state_id, 'review_state': state_id, 'time': DateTime() } # Get old and new state info old_state = workflow._getWorkflowStateOf(content) new_state = workflow.states.get(state_id, None) if new_state is None: raise WorkflowException( "Destination state undefined: {}".format(state_id)) # Change status and update permissions portal_workflow.setStatusOf(wf_id, content, wf_state) workflow.updateRoleMappingsFor(content) # Notify the object has been transitioned notify( AfterTransitionEvent(content, workflow, old_state, new_state, None, wf_state, None)) # Map changes to catalog indexes = ["allowedRolesAndUsers", "review_state", "is_active"] content.reindexObject(idxs=indexes) return True
def guard_submit(analysis): """Return whether the transition "submit" can be performed or not """ # Cannot submit without a result if not analysis.getResult(): return False # Cannot submit with interims without value for interim in analysis.getInterimFields(): if not interim.get("value", ""): return False # Cannot submit if attachment not set, but is required if not analysis.getAttachment(): if analysis.getAttachmentOption() == 'r': return False # Check if can submit based on the Analysis Request state if IRequestAnalysis.providedBy(analysis): point_of_capture = analysis.getPointOfCapture() # Cannot submit if the Sample has not been received if point_of_capture == "lab" and not analysis.isSampleReceived(): return False # Cannot submit if the Sample has not been sampled if point_of_capture == "field" and not analysis.isSampleSampled(): return False # Check if the current user can submit if is not assigned if not analysis.bika_setup.getAllowToSubmitNotAssigned(): if not user_has_super_roles(): # Cannot submit if unassigned if not analysis.getAnalyst(): return False # Cannot submit if assigned analyst is not the current user if analysis.getAnalyst() != api.get_current_user().getId(): return False # Cannot submit unless all dependencies are submitted or can be submitted for dependency in analysis.getDependencies(): if not is_submitted_or_submittable(dependency): return False return True
def guard_process(context): """Guard for process (partitioning) process Only Primary Analysis Requests can be partitioned """ sample = get_sample(context) if not sample: return False if not api.is_active(sample): return False # If the sample is not a primary sample, do not allow processing if sample.Schema()['PrimarySample'].get(sample): return False # If the current user is a Client contact, do not allow to deliver user = api.get_current_user() if "Client" in user.getRoles(): return False return True
def __call__(self): """Handle request parameters and render the form """ logger.info(u"ListingView::__call__") self.portal = api.get_portal() self.mtool = api.get_tool("portal_membership") self.workflow = api.get_tool("portal_workflow") self.member = api.get_current_user() self.translate = self.context.translate # Call update hook self.update() # handle subpath calls if len(self.traverse_subpath) > 0: return self.handle_subpath() # Call before render hook self.before_render() return self.template(self.context)
def guard_send_to_lab(context): """ Guard for send_to_lab transition. Returns true if the current user is a client contact, the Sample (context) is active and it belongs to the same client. """ sample = get_sample(context) if not sample: return False # If Sample is inactive, we cannot send the sample to the lab if not api.is_active(sample): return False # Only users from role Client can send the sample to the lab user = api.get_current_user() user_roles = user.getRoles() # Only contacts from the client the Sample belongs to if "Client" in user_roles: client = sample.aq_parent if not client.getContactFromUsername(user.id): return False return True
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
def current_user_was_last_verifier(analysis): """Returns whether the current user was the last verifier or not """ verifiers = analysis.getVerificators() return verifiers and verifiers[:-1] == api.get_current_user().getId()