예제 #1
0
def setup_handler(context):
    """Generic setup handler
    """
    if context.readDataFile("{}.txt".format(PRODUCT_NAME)) is None:
        return

    logger.info("{} setup handler [BEGIN]".format(PRODUCT_NAME.upper()))
    portal = context.getSite()

    # Setup patient content type
    add_patient_folder(portal)

    # Configure visible navigation items
    setup_navigation_types(portal)

    # Setup catalogs
    setup_catalogs(portal)

    # Apply ID format to content types
    setup_id_formatting(portal)

    # Setup workflow (for field permissions mostly)
    setup_workflow(portal)

    logger.info("{} setup handler [DONE]".format(PRODUCT_NAME.upper()))
예제 #2
0
def post_install(portal_setup):
    """Runs after the last import step of the *default* profile
    This handler is registered as a *post_handler* in the generic setup profile
    :param portal_setup: SetupTool
    """
    logger.info("{} install handler [BEGIN]".format(PRODUCT_NAME.upper()))
    context = portal_setup._getImportContext(PROFILE_ID)  # noqa
    portal = context.getSite()  # noqa

    logger.info("{} install handler [DONE]".format(PRODUCT_NAME.upper()))
예제 #3
0
def afterUpgradeStepHandler(event):
    """Event handler that is executed after running an upgrade step of senaite.core
    """
    if not is_installed():
        return
    logger.info("Run senaite.patient.afterUpgradeStepHandler ...")
    portal = get_portal()
    setup_navigation_types(portal)
    setup_id_formatting(portal)
    setup_workflow(portal)
    logger.info("Run senaite.patient.afterUpgradeStepHandler [DONE]")
예제 #4
0
def post_uninstall(portal_setup):
    """Runs after the last import step of the *uninstall* profile
    This handler is registered as a *post_handler* in the generic setup profile
    :param portal_setup: SetupTool
    """
    logger.info("{} uninstall handler [BEGIN]".format(PRODUCT_NAME.upper()))

    # https://docs.plone.org/develop/addons/components/genericsetup.html#custom-installer-code-setuphandlers-py
    profile_id = "profile-{}:uninstall".format(PRODUCT_NAME)
    context = portal_setup._getImportContext(profile_id)  # noqa
    portal = context.getSite()  # noqa

    logger.info("{} uninstall handler [DONE]".format(PRODUCT_NAME.upper()))
예제 #5
0
def setup_id_formatting(portal, format_definition=None):
    """Setup default ID formatting
    """
    if not format_definition:
        logger.info("Setting up ID formatting ...")
        for formatting in ID_FORMATTING:
            setup_id_formatting(portal, format_definition=formatting)
        logger.info("Setting up ID formatting [DONE]")
        return

    bs = portal.bika_setup
    p_type = format_definition.get("portal_type", None)
    if not p_type:
        return

    form = format_definition.get("form", "")
    if not form:
        logger.info("Param 'form' for portal type {} not set [SKIP")
        return

    logger.info("Applying format '{}' for {}".format(form, p_type))
    ids = list()
    for record in bs.getIDFormatting():
        if record.get('portal_type', '') == p_type:
            continue
        ids.append(record)
    ids.append(format_definition)
    bs.setIDFormatting(ids)
예제 #6
0
def migrate_to_patient_catalog(portal):
    """Migrate portal_catalog -> patient_catalog
    """
    logger.info("Migrate patient catalog...")

    # 1. Setup catalogs
    setup_catalogs(portal)

    # 2. Clean up indexes
    for catalog_id, idx_id in DELETE_INDEXES:
        catalog = api.get_tool(catalog_id)
        indexes = get_indexes(catalog)
        if idx_id in indexes:
            del_index(catalog, idx_id)
            logger.info("Deleted index '%s' from catalog '%s'" %
                        (idx_id, catalog_id))

    # 3. Clean up columns
    for catalog_id, column in DELETE_COLUMNS:
        catalog = api.get_tool(catalog_id)
        columns = get_columns(catalog)
        if column in columns:
            del_column(catalog, column)
            logger.info("Deleted column '%s' from catalog '%s'" %
                        (column, catalog_id))

    # 4. Reindex patient catalog
    patient_catalog = api.get_tool(PATIENT_CATALOG)
    patient_catalog.clearFindAndRebuild()

    logger.info("Migrate patient catalog [DONE]")
예제 #7
0
def update_patient(instance):
    if instance.isMedicalRecordTemporary():
        return
    mrn = instance.getMedicalRecordNumberValue()
    # Allow empty value when patients are not required for samples
    if mrn is None:
        return
    patient = patient_api.get_patient_by_mrn(mrn, include_inactive=True)
    if patient is None:
        logger.info("Creating new Patient with MRN #: {}".format(mrn))
        patient = patient_api.create_empty_patient()
        # XXX: Sync the values back from Sample -> Patient?
        values = get_patient_fields(instance)
        patient_api.update_patient(patient, **values)
예제 #8
0
def update_workflow(portal, workflow_id, settings):
    """Updates the workflow with workflow_id with the settings passed-in
    """
    logger.info("Updating workflow '{}' ...".format(workflow_id))
    wf_tool = api.get_tool("portal_workflow")
    workflow = wf_tool.getWorkflowById(workflow_id)
    if not workflow:
        logger.warn("Workflow '{}' not found [SKIP]".format(workflow_id))
    states = settings.get("states", {})
    for state_id, values in states.items():
        update_workflow_state(workflow, state_id, values)

    transitions = settings.get("transitions", {})
    for transition_id, values in transitions.items():
        update_workflow_transition(workflow, transition_id, values)
예제 #9
0
def fix_patients_fullname(portal):
    """Update the value of attribute 'firstname' with the value of 'fullname'
    """
    logger.info("Fixing patients full names ...")
    for patient in portal.patients.objectValues():
        if patient.get_firstname():
            # This one has the value set already
            continue

        raw = patient.__dict__
        firstname = raw.get("fullname", None)
        if firstname:
            patient.set_firstname(firstname)
            del (patient.__dict__["fullname"])
            patient.reindexObject()

    logger.info("Fixing patients full names ... [DONE]")
예제 #10
0
def migrate_birthdates(portal):
    """Migrate all birthdates from patients to be timezone aware
    """
    logger.info("Migrate patient birthdate timezones ...")
    catalog = api.get_tool(PATIENT_CATALOG)
    results = catalog({"portal_type": "Patient"})
    timezone = dtime.get_os_timezone()
    for brain in results:
        patient = api.get_object(brain)
        birthdate = patient.birthdate
        if birthdate:
            # clean existing time and timezone
            date = birthdate.strftime("%Y-%m-%d")
            # append current OS timezone if possible
            if timezone:
                date = date + " %s" % timezone
            patient.set_birthdate(date)
            patient.reindexObject()

    logger.info("Migrate patient birthdate timezones [DONE]")
예제 #11
0
def migrate_patient_item_to_container(portal):
    """Migrate patient objects to be folderish

    Base class changed from Item -> Container

    https://community.plone.org/t/changing-dx-content-type-base-class-from-item-to-container
    http://blog.redturtle.it/2013/02/25/migrating-dexterity-items-to-dexterity-containers
    """
    logger.info("Migrate patients to be folderish ...")
    patients = portal.patients
    for patient in patients.objectValues():
        pid = patient.getId()
        patients._delOb(pid)
        patient.__class__ = Patient
        patients._setOb(pid, patient)
        BTreeFolder2Base._initBTrees(patients[pid])
        patients[pid].reindexObject()

    transaction.commit()
    logger.info("Migrate patients to be folderish [DONE]")
예제 #12
0
def update_workflow_transition(workflow, transition_id, settings):
    logger.info("Updating workflow '{}', transition: '{}'".format(
        workflow.id, transition_id))
    if transition_id not in workflow.transitions:
        workflow.transitions.addTransition(transition_id)
    transition = workflow.transitions.get(transition_id)
    transition.setProperties(title=settings.get("title"),
                             new_state_id=settings.get("new_state"),
                             after_script_name=settings.get(
                                 "after_script", ""),
                             actbox_name=settings.get("action",
                                                      settings.get("title")))
    guard = transition.guard or Guard()
    guard_props = {
        "guard_permissions": "",
        "guard_roles": "",
        "guard_expr": ""
    }
    guard_props = settings.get("guard", guard_props)
    guard.changeFromProperties(guard_props)
    transition.guard = guard
예제 #13
0
def upgrade(tool):
    portal = tool.aq_inner.aq_parent
    setup = portal.portal_setup
    ut = UpgradeUtils(portal)
    ver_from = ut.getInstalledVersion(PRODUCT_NAME)

    if ut.isOlderVersion(PRODUCT_NAME, version):
        logger.info("Skipping upgrade of {0}: {1} > {2}".format(
            PRODUCT_NAME, ver_from, version))
        return True

    logger.info("Upgrading {0}: {1} -> {2}".format(PRODUCT_NAME, ver_from,
                                                   version))

    # -------- ADD YOUR STUFF BELOW --------

    # Allow/Disallow to verify/publish samples with temporary MRN
    setup.runImportStepFromProfile(PROFILE_ID, "plone.app.registry")
    # Update schema interface
    setup.runImportStepFromProfile(PROFILE_ID, "typeinfo")
    setup.runImportStepFromProfile(PROFILE_ID, "workflow")

    # https://github.com/senaite/senaite.patient/pull/24
    migrate_patient_item_to_container(portal)

    # https://github.com/senaite/senaite.patient/pull/14
    migrate_to_patient_catalog(portal)

    # Firstname + lastname instead of fullname
    fix_patients_fullname(portal)

    logger.info("{0} upgraded to version {1}".format(PRODUCT_NAME, version))
    return True
예제 #14
0
def update_workflow_state(workflow, status_id, settings):
    logger.info("Updating workflow '{}', status: '{}' ...".format(
        workflow.id, status_id))

    # Create the status (if does not exist yet)
    new_status = workflow.states.get(status_id)
    if not new_status:
        workflow.states.addState(status_id)
        new_status = workflow.states.get(status_id)

    # Set basic info (title, description, etc.)
    new_status.title = settings.get("title", new_status.title)
    new_status.description = settings.get("description",
                                          new_status.description)

    # Set transitions
    trans = settings.get("transitions", ())
    if settings.get("preserve_transitions", False):
        trans = tuple(set(new_status.transitions + trans))
    new_status.transitions = trans

    # Set permissions
    update_workflow_state_permissions(workflow, new_status, settings)
예제 #15
0
def upgrade(tool):
    portal = tool.aq_inner.aq_parent
    setup = portal.portal_setup  # noqa
    ut = UpgradeUtils(portal)
    ver_from = ut.getInstalledVersion(PRODUCT_NAME)

    if ut.isOlderVersion(PRODUCT_NAME, version):
        logger.info("Skipping upgrade of {0}: {1} > {2}".format(
            PRODUCT_NAME, ver_from, version))
        return True

    logger.info("Upgrading {0}: {1} -> {2}".format(PRODUCT_NAME, ver_from,
                                                   version))

    # -------- ADD YOUR STUFF BELOW --------

    # add dateindex for birthdates
    setup_catalogs(portal)

    # migrate birthdates w/o time but with valid timezone
    migrate_birthdates(portal)

    logger.info("{0} upgraded to version {1}".format(PRODUCT_NAME, version))
    return True
예제 #16
0
def add_patient_folder(portal):
    """Adds the initial Patient folder
    """
    if portal.get("patients") is None:
        logger.info("Adding Patient Folder")
        portal.invokeFactory("PatientFolder", "patients", title="Patients")
예제 #17
0
def update_workflow_state_permissions(workflow, status, settings):
    # Copy permissions from another state?
    permissions_copy_from = settings.get("permissions_copy_from", None)
    if permissions_copy_from:
        logger.info("Copying permissions from '{}' to '{}' ...".format(
            permissions_copy_from, status.id))
        copy_from_state = workflow.states.get(permissions_copy_from)
        if not copy_from_state:
            logger.info("State '{}' not found [SKIP]".format(copy_from_state))
        else:
            for perm_id in copy_from_state.permissions:
                perm_info = copy_from_state.getPermissionInfo(perm_id)
                acquired = perm_info.get("acquired", 1)
                roles = perm_info.get("roles", acquired and [] or ())
                logger.info(
                    "Setting permission '{}' (acquired={}): '{}'".format(
                        perm_id, repr(acquired), ', '.join(roles)))
                status.setPermission(perm_id, acquired, roles)

    # Override permissions
    logger.info("Overriding permissions for '{}' ...".format(status.id))
    state_permissions = settings.get('permissions', {})
    if not state_permissions:
        logger.info("No permissions set for '{}' [SKIP]".format(status.id))
        return
    for permission_id, roles in state_permissions.items():
        state_roles = roles and roles or ()
        if isinstance(state_roles, tuple):
            acq = 0
        else:
            acq = 1
        logger.info("Setting permission '{}' (acquired={}): '{}'".format(
            permission_id, repr(acq), ', '.join(state_roles)))
        # Check if this permission is defined globally for this workflow
        if permission_id not in workflow.permissions:
            workflow.permissions = workflow.permissions + (permission_id, )
        status.setPermission(permission_id, acq, state_roles)