Esempio n. 1
0
def sync_sources(db_session: SessionLocal, project: Project):
    """Syncs sources from external sources."""
    plugin = plugin_service.get_active_instance(
        db_session=db_session, plugin_type="source", project_id=project.id
    )

    if not plugin:
        log.debug(f"No active plugins were found. PluginType: 'source' ProjectId: {project.id}")
        return

    log.debug(f"Getting source information via: {plugin.plugin.slug}")

    sources = source_service.get_all(db_session=db_session, project_id=project.id)

    for s in sources:
        log.debug(f"Syncing Source. Source: {s}")
        if not s.external_id:
            log.debug(f"Skipping source, no externalId Source: {s}")
            continue

        data = plugin.instance.get(external_id=s.external_id)

        if data:
            for k, v in data.items():
                setattr(s, k, v)

            db_session.commit()
Esempio n. 2
0
def remove_participant(user_email: str, incident: Incident,
                       db_session: SessionLocal):
    """Removes a participant."""
    inactivated = inactivate_participant(user_email, incident, db_session)

    if inactivated:
        participant = get_by_incident_id_and_email(db_session=db_session,
                                                   incident_id=incident.id,
                                                   email=user_email)

        log.debug(
            f"Removing {participant.individual.name} from {incident.name} incident..."
        )

        participant.service = None

        db_session.add(participant)
        db_session.commit()

        event_service.log(
            db_session=db_session,
            source="Dispatch Core App",
            description=f"{participant.individual.name} has been removed",
            incident_id=incident.id,
        )
Esempio n. 3
0
def add_participant(
    user_email: str,
    incident: Incident,
    db_session: SessionLocal,
    service_id: int = None,
    role: ParticipantRoleType = ParticipantRoleType.participant,
):
    """Adds a participant."""
    # we get or create a new individual
    individual = individual_service.get_or_create(db_session=db_session,
                                                  incident=incident,
                                                  email=user_email)

    # we get or create a new participant
    participant_role = ParticipantRoleCreate(role=role)
    participant = get_or_create(
        db_session=db_session,
        incident_id=incident.id,
        individual_id=individual.id,
        service_id=service_id,
        participant_roles=[participant_role],
    )

    individual.participant.append(participant)
    incident.participants.append(participant)

    # we update the commander, reporter, scribe, or liaison foreign key
    if role == ParticipantRoleType.incident_commander:
        incident.commander_id = participant.id
        incident.commanders_location = participant.location
    elif role == ParticipantRoleType.reporter:
        incident.reporter_id = participant.id
        incident.reporters_location = participant.location
    elif role == ParticipantRoleType.scribe:
        incident.scribe_id = participant.id
    elif role == ParticipantRoleType.liaison:
        incident.liaison_id = participant.id

    # we add and commit the changes
    db_session.add(participant)
    db_session.add(individual)
    db_session.add(incident)
    db_session.commit()

    event_service.log(
        db_session=db_session,
        source="Dispatch Core App",
        description=
        f"{individual.name} added to incident with {participant_role.role} role",
        incident_id=incident.id,
    )

    return participant
Esempio n. 4
0
def calculate_incidents_response_cost(db_session: SessionLocal,
                                      project: Project):
    """Calculates and saves the response cost for all incidents."""
    response_cost_type = incident_cost_type_service.get_default(
        db_session=db_session, project_id=project.id)
    if response_cost_type is None:
        log.warning(
            f"A default cost type for response cost does not exist in the {project.name} project. Response costs won't be calculated."
        )
        return

    # we want to update the response cost of all incidents, all the time
    incidents = incident_service.get_all(db_session=db_session,
                                         project_id=project.id)
    for incident in incidents:
        try:
            # we get the response cost for the given incident
            incident_response_cost = get_by_incident_id_and_incident_cost_type_id(
                db_session=db_session,
                incident_id=incident.id,
                incident_cost_type_id=response_cost_type.id,
            )

            if incident_response_cost is None:
                # we create the response cost if it doesn't exist
                incident_cost_type = IncidentCostTypeRead.from_orm(
                    response_cost_type)
                incident_cost_in = IncidentCostCreate(
                    incident_cost_type=incident_cost_type, project=project)
                incident_response_cost = create(
                    db_session=db_session, incident_cost_in=incident_cost_in)

            # we calculate the response cost amount
            amount = calculate_incident_response_cost(incident.id, db_session)

            # we don't need to update the cost amount if it hasn't changed
            if incident_response_cost.amount == amount:
                continue

            # we save the new incident cost amount
            incident_response_cost.amount = amount
            incident.incident_costs.append(incident_response_cost)
            db_session.add(incident)
            db_session.commit()

            log.debug(
                f"Response cost amount for {incident.name} incident has been updated in the database."
            )

        except Exception as e:
            # we shouldn't fail to update all incidents when one fails
            log.exception(e)
Esempio n. 5
0
def create_evergreen_reminder(db_session: SessionLocal, project: Project,
                              owner_email: str, resource_groups: Any):
    """Contains the logic for evergreen reminders."""
    plugin = plugin_service.get_active_instance(db_session=db_session,
                                                plugin_type="email",
                                                project_id=project.id)
    if not plugin:
        log.warning("Evergreen reminder not sent, no email plugin enabled.")
        return

    notification_template = EVERGREEN_REMINDER

    items = []
    for resource_type, resources in resource_groups.items():
        for resource in resources:
            weblink = getattr(resource, "weblink", None)
            if not weblink:
                weblink = DISPATCH_UI_URL

            items.append({
                "resource_type":
                resource_type.replace("_", " ").title(),
                "name":
                resource.name,
                "description":
                getattr(resource, "description", None),
                "weblink":
                weblink,
            })

    notification_type = "evergreen-reminder"
    name = subject = notification_text = "Evergreen Reminder"
    success = plugin.instance.send(
        owner_email,
        notification_text,
        notification_template,
        notification_type,
        name=name,
        subject=subject,
        items=items,  # plugin expect dicts
    )

    if success:
        for item in items:
            item.evergreen_last_reminder_at = datetime.utcnow()

        db_session.commit()
    else:
        log.error(f"Unable to send evergreen message. Email: {owner_email}")
Esempio n. 6
0
def remove_participant(user_email: str, incident_id: int,
                       db_session: SessionLocal):
    """Removes a participant."""
    # We load the incident
    incident = incident_service.get(db_session=db_session,
                                    incident_id=incident_id)

    # We get information about the individual
    contact_plugin = plugin_service.get_active(db_session=db_session,
                                               plugin_type="contact")
    individual_info = contact_plugin.instance.get(user_email)
    individual_fullname = individual_info["fullname"]

    log.debug(
        f"Removing {individual_fullname} from incident {incident.name}...")

    participant = get_by_incident_id_and_email(db_session=db_session,
                                               incident_id=incident_id,
                                               email=user_email)

    if not participant:
        log.debug(
            f"Can't remove {individual_fullname}. They're not an active participant of incident {incident.name}."
        )
        return False

    # We mark the participant as inactive
    participant.is_active = False

    # We make the participant renounce to their active roles
    participant_active_roles = participant_role_service.get_all_active_roles(
        db_session=db_session, participant_id=participant.id)
    for participant_active_role in participant_active_roles:
        participant_role_service.renounce_role(
            db_session=db_session, participant_role=participant_active_role)

    # We add and commit the changes
    db_session.add(participant)
    db_session.commit()

    event_service.log(
        db_session=db_session,
        source="Dispatch Core App",
        description=f"{participant.individual.name} removed from incident",
        incident_id=incident_id,
    )

    return True
Esempio n. 7
0
def add_participant(
    user_email: str,
    incident_id: id,
    db_session: SessionLocal,
    service: Service = None,
    role: ParticipantRoleType = None,
):
    """Adds a participant."""
    # We load the incident
    incident = incident_service.get(db_session=db_session,
                                    incident_id=incident_id)

    # We get or create a new individual
    individual = individual_service.get_or_create(db_session=db_session,
                                                  email=user_email)

    # We create a role for the participant
    participant_role_in = ParticipantRoleCreate(role=role)

    participant_role = participant_role_service.create(
        db_session=db_session, participant_role_in=participant_role_in)

    # We get or create a new participant
    participant = get_or_create(
        db_session=db_session,
        incident_id=incident.id,
        individual_id=individual.id,
        service=service,
        participant_roles=[participant_role],
    )

    individual.participant.append(participant)
    incident.participants.append(participant)

    # We add and commit the changes
    db_session.add(individual)
    db_session.add(incident)
    db_session.commit()

    event_service.log(
        db_session=db_session,
        source="Dispatch Core App",
        description=
        f"{individual.name} added to incident with {participant_role.role} role",
        incident_id=incident_id,
    )

    return participant
Esempio n. 8
0
def reactivate_participant(user_email: str, incident_id: int,
                           db_session: SessionLocal):
    """Reactivates a participant."""
    # We load the incident
    incident = incident_service.get(db_session=db_session,
                                    incident_id=incident_id)

    # We get information about the individual
    contact_plugin = plugin_service.get_active(db_session=db_session,
                                               plugin_type="contact")
    individual_info = contact_plugin.instance.get(user_email)
    individual_fullname = individual_info["fullname"]

    log.debug(
        f"Reactivating {individual_fullname} on incident {incident.name}...")

    participant = get_by_incident_id_and_email(db_session=db_session,
                                               incident_id=incident_id,
                                               email=user_email)

    if not participant:
        log.debug(
            f"{individual_fullname} is not an inactive participant of incident {incident.name}."
        )
        return False

    # We mark the participant as active
    participant.is_active = True

    # We create a role for the participant
    participant_role_in = ParticipantRoleCreate(
        role=ParticipantRoleType.participant)
    participant_role = participant_role_service.create(
        db_session=db_session, participant_role_in=participant_role_in)
    participant.participant_roles.append(participant_role)

    # We add and commit the changes
    db_session.add(participant)
    db_session.commit()

    event_service.log(
        db_session=db_session,
        source="Dispatch Core App",
        description=f"{individual_fullname} reactivated",
        incident_id=incident_id,
    )

    return True
Esempio n. 9
0
def sync_document_terms(db_session: SessionLocal, project: Project):
    """Performs term extraction from known documents."""
    p = plugin_service.get_active_instance(
        db_session=db_session, plugin_type="storage", project_id=project.id
    )

    if not p:
        log.debug("Tried to sync document terms but couldn't find any active storage plugins.")
        return

    terms = term_service.get_all(db_session=db_session, project_id=project.id).all()
    log.debug(f"Fetched {len(terms)} terms from database.")

    term_strings = [t.text.lower() for t in terms if t.discoverable]
    phrases = build_term_vocab(term_strings)
    matcher = build_phrase_matcher("dispatch-term", phrases)

    documents = get_all(db_session=db_session)
    for doc in documents:
        log.debug(f"Processing document. Name: {doc.name}")

        try:
            if "sheet" in doc.resource_type:
                mime_type = "text/csv"
            else:
                mime_type = "text/plain"

            doc_text = p.instance.get(doc.resource_id, mime_type)
            extracted_terms = list(set(extract_terms_from_text(doc_text, matcher)))

            matched_terms = (
                db_session.query(Term)
                .filter(func.upper(Term.text).in_([func.upper(t) for t in extracted_terms]))
                .all()
            )

            log.debug(f"Extracted the following terms from {doc.weblink}. Terms: {extracted_terms}")

            if matched_terms:
                doc.terms = matched_terms
                db_session.commit()

        except Exception as e:
            # even if one document fails we don't want them to all fail
            log.exception(e)
Esempio n. 10
0
def reactivate_participant(user_email: str,
                           incident: Incident,
                           db_session: SessionLocal,
                           service_id: int = None):
    """Reactivates a participant."""
    participant = get_by_incident_id_and_email(db_session=db_session,
                                               incident_id=incident.id,
                                               email=user_email)

    if not participant:
        log.debug(
            f"{user_email} is not an inactive participant of {incident.name} incident."
        )
        return False

    log.debug(
        f"Reactivating {participant.individual.name} on {incident.name} incident..."
    )

    # we get the last active role
    participant_role = participant_role_service.get_last_active_role(
        db_session=db_session, participant_id=participant.id)
    # we create a new role based on the last active role
    participant_role_in = ParticipantRoleCreate(role=participant_role.role)
    participant_role = participant_role_service.create(
        db_session=db_session, participant_role_in=participant_role_in)
    participant.participant_roles.append(participant_role)

    if service_id:
        service = service_service.get(db_session=db_session,
                                      service_id=service_id)
        participant.service = service

    db_session.add(participant)
    db_session.commit()

    event_service.log(
        db_session=db_session,
        source="Dispatch Core App",
        description=f"{participant.individual.name} has been reactivated",
        incident_id=incident.id,
    )

    return True
Esempio n. 11
0
def create_reminder(
    db_session: SessionLocal, project: Project, owner_email: str, documents: List[Document]
):
    """Contains the logic for document evergreen reminders."""
    # send email
    contact_fullname = contact_weblink = DISPATCH_HELP_EMAIL
    plugin = plugin_service.get_active_instance(
        db_session=db_session, plugin_type="email", project_id=project.id
    )
    if not plugin:
        log.warning("Document reminder not sent, no email plugin enabled.")
        return

    notification_template = DOCUMENT_EVERGREEN_REMINDER

    items = []
    for doc in documents:
        items.append(
            {
                "name": doc.name,
                "description": doc.description,
                "weblink": doc.weblink,
            }
        )
    notification_type = "document-evergreen-reminder"
    name = subject = notification_text = "Document Evergreen Reminder"
    plugin.instance.send(
        owner_email,
        notification_text,
        notification_template,
        notification_type,
        name=name,
        subject=subject,
        contact_fullname=contact_fullname,
        contact_weblink=contact_weblink,
        items=items,  # plugin expect dicts
    )

    for doc in documents:
        doc.evergreen_last_reminder_at = datetime.utcnow()
        db_session.add(doc)

    db_session.commit()
Esempio n. 12
0
def install_plugins(force):
    """Installs all plugins, or only one."""
    from dispatch.database.core import SessionLocal
    from dispatch.plugin import service as plugin_service
    from dispatch.plugin.models import Plugin
    from dispatch.common.utils.cli import install_plugins
    from dispatch.plugins.base import plugins

    install_plugins()

    db_session = SessionLocal()
    for p in plugins.all():
        record = plugin_service.get_by_slug(db_session=db_session, slug=p.slug)
        if not record:
            click.secho(
                f"Installing plugin... Slug: {p.slug} Version: {p.version}",
                fg="blue")
            record = Plugin(
                title=p.title,
                slug=p.slug,
                type=p.type,
                version=p.version,
                author=p.author,
                author_url=p.author_url,
                multiple=p.multiple,
                description=p.description,
            )
            db_session.add(record)

        if force:
            click.secho(
                f"Updating plugin... Slug: {p.slug} Version: {p.version}",
                fg="blue")
            # we only update values that should change
            record.title = p.title
            record.version = p.version
            record.author = p.author
            record.author_url = p.author_url
            record.description = p.description
            record.type = p.type
            db_session.add(record)

        db_session.commit()
Esempio n. 13
0
def auto_tagger(db_session: SessionLocal, project: Project):
    """Attempts to take existing tags and associate them with incidents."""
    tags = tag_service.get_all(db_session=db_session, project_id=project.id).all()
    log.debug(f"Fetched {len(tags)} tags from database.")

    tag_strings = [t.name.lower() for t in tags if t.discoverable]
    phrases = build_term_vocab(tag_strings)
    matcher = build_phrase_matcher("dispatch-tag", phrases)

    for incident in get_all(db_session=db_session, project_id=project.id).all():
        plugin = plugin_service.get_active_instance(
            db_session=db_session, project_id=incident.project.id, plugin_type="storage"
        )

        log.debug(f"Processing incident. Name: {incident.name}")

        doc = incident.incident_document

        if doc:
            try:
                mime_type = "text/plain"
                text = plugin.instance.get(doc.resource_id, mime_type)
            except Exception as e:
                log.debug(f"Failed to get document. Reason: {e}")
                log.exception(e)
                continue

            extracted_tags = list(set(extract_terms_from_text(text, matcher)))

            matched_tags = (
                db_session.query(Tag)
                .filter(func.upper(Tag.name).in_([func.upper(t) for t in extracted_tags]))
                .all()
            )

            incident.tags.extend(matched_tags)
            db_session.commit()

            log.debug(
                f"Associating tags with incident. Incident: {incident.name}, Tags: {extracted_tags}"
            )
Esempio n. 14
0
def assign_role_flow(incident: "Incident", assignee_email: str,
                     assignee_role: str, db_session: SessionLocal):
    """Attempts to assign a role to a participant.

    Returns:
        str:
        - "role_assigned", if role assigned.
        - "role_not_assigned", if not role assigned.
        - "assignee_has_role", if assignee already has the role.

    """
    # we get the participant that holds the role assigned to the assignee
    participant_with_assignee_role = participant_service.get_by_incident_id_and_role(
        db_session=db_session, incident_id=incident.id, role=assignee_role)

    # we get the participant for the assignee
    assignee_participant = participant_service.get_by_incident_id_and_email(
        db_session=db_session, incident_id=incident.id, email=assignee_email)

    if participant_with_assignee_role is assignee_participant:
        return "assignee_has_role"

    if participant_with_assignee_role:
        # we make the participant renounce to the role that has been given to the assignee
        participant_active_roles = get_all_active_roles(
            db_session=db_session,
            participant_id=participant_with_assignee_role.id)
        for participant_active_role in participant_active_roles:
            if participant_active_role.role == assignee_role:
                renounce_role(db_session=db_session,
                              participant_role=participant_active_role)
                break

        # we check if the participant has other active roles
        participant_active_roles = get_all_active_roles(
            db_session=db_session,
            participant_id=participant_with_assignee_role.id)
        if participant_active_roles.count() == 0:
            # we give the participant a new participant role
            add_role(
                db_session=db_session,
                participant_id=participant_with_assignee_role.id,
                participant_role=ParticipantRoleType.participant,
            )

        log.debug(
            f"We made {participant_with_assignee_role.individual.name} renounce to their {assignee_role} role."
        )

    if assignee_participant:
        # we make the assignee renounce to the participant role, if they have it
        participant_active_roles = get_all_active_roles(
            db_session=db_session, participant_id=assignee_participant.id)
        for participant_active_role in participant_active_roles:
            if participant_active_role.role == ParticipantRoleType.participant:
                renounce_role(db_session=db_session,
                              participant_role=participant_active_role)
                break

        # we give the assignee the new role
        add_role(
            db_session=db_session,
            participant_id=assignee_participant.id,
            participant_role=assignee_role,
        )

        # we update the commander, reporter, scribe, or liaison foreign key
        if assignee_role == ParticipantRoleType.incident_commander:
            incident.commander_id = assignee_participant.id
        elif assignee_role == ParticipantRoleType.reporter:
            incident.reporter_id = assignee_participant.id
        elif assignee_role == ParticipantRoleType.scribe:
            incident.scribe_id = assignee_participant.id
        elif assignee_role == ParticipantRoleType.liaison:
            incident.liaison_id = assignee_participant.id

        # we add and commit the changes
        db_session.add(incident)
        db_session.commit()

        event_service.log(
            db_session=db_session,
            source="Dispatch Core App",
            description=
            f"{assignee_participant.individual.name} has been assigned the role of {assignee_role}",
            incident_id=incident.id,
        )

        return "role_assigned"

    log.debug(
        f"We were not able to assign the {assignee_role} role to {assignee_email}."
    )

    return "role_not_assigned"