# By: Riasat Ullah
# This file contains all the views related to task instances/incidents.

from analytics.instance_analyzer import InstanceAnalyzer
from data_syncers import syncer_task_instances
from dbqueries import db_business_services, db_events, db_instance_utilities, db_integrations, db_live_call_routing,\
    db_policies, db_tasks, db_task_instances, db_users, db_workflows
from exceptions.user_exceptions import InvalidRequest, MaliciousSource, NoOneIsOnCall, UnauthorizedRequest
from modules.alert_logger import AlertLogger
from modules import custom_action_manager
from modules.event_allocator import EventAllocator
from modules.notice_allocator import NoticeAllocator
from modules.instance_comparator import InstanceComparator
from modules.workflow_manager import WorkflowManager
from objects.instance_state import InstanceState
from objects.events import AcknowledgeEvent, AddImpactedBusinessServiceEvent, AddRespondersEvent, AddSubscribersEvent, \
    EditTitleEvent, MergeEvent, NotateEvent, ReassignEvent, RemoveImpactedBusinessServiceEvent, \
    RemoveSubscribersEvent, ResolveEvent, SnoozeEvent, StatusUpdateEvent, UnAcknowledgeEvent, UnMergeEvent, \
    UpdateTagsEvent, UrgencyAmendmentEvent
from rest_framework.decorators import api_view
from rest_framework.response import Response
from translators import label_translator as _lt
from utils import app_notice, constants, errors, info, logging, mail, permissions, times, tokenizer, var_names
from utils.db_connection import CACHE_CLIENT, CONN_POOL
from validations import request_validator
import configuration
import datetime
import jwt


@api_view(['POST'])
def list_task_instances(request, conn=None):
    '''
    Gets a list of incidents with basic information.
    :param request: Http request
    :param conn: db connection
    :return: Http response -> list of dict
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        optional_fields = [var_names.status, var_names.assignee_type, var_names.keywords,
                           var_names.row_limit, var_names.row_offset]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, [], optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)
            status_type = request.data[var_names.status] if var_names.status in request.data else None
            assignee_type = request.data[var_names.assignee_type] if var_names.assignee_type in request.data else None
            keywords = request.data[var_names.keywords] if var_names.keywords in request.data else None
            row_limit = request.data[var_names.row_limit] if var_names.row_limit in request.data else None
            row_offset = request.data[var_names.row_offset] if var_names.row_offset in request.data else None

            if assignee_type == constants.team_assignee and\
                    not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if permissions.has_user_permission(user_perm, permissions.USER_INCIDENTS_VIEW_PERMISSION):
                if status_type is not None and status_type not in [constants.open_state, constants.resolved_state]:
                    return Response(_lt.get_label(errors.err_invalid_request, lang), status=401)

                do_adv_check = permissions.get_user_advanced_check_status(user_perm, org_perm)[0]

                incidents = db_task_instances.list_instances(
                    conn, times.get_current_timestamp(), org_id, user_id,
                    open_instances=None if status_type is None
                    else True if status_type == constants.open_state else False,
                    assignee_type=assignee_type, row_limit=row_limit, row_offset=row_offset,
                    search_words=keywords, check_adv_perm=do_adv_check
                )
                return Response(incidents)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except InvalidRequest as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def get_instance_details(request, conn=None):
    '''
    Gets all the details of a single instance.
    :param request: Http request
    :param conn: db connection
    :return: Http response -> dict
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.organization_instance_id]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)
            org_inst_id = request.data[var_names.organization_instance_id]

            if permissions.has_user_permission(user_perm, permissions.USER_INCIDENTS_VIEW_PERMISSION):
                do_adv_check = permissions.get_user_advanced_check_status(user_perm, org_perm)[0]

                inst_obj_dict = db_task_instances.get_instance_details(
                    conn, times.get_current_timestamp(), org_id, org_instance_id=org_inst_id,
                    check_adv_perm=do_adv_check, user_id=user_id
                )
                if len(inst_obj_dict) == 0:
                    return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
                else:
                    inst_obj = list(inst_obj_dict.values())[0]
                    return Response(inst_obj.to_dict())
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, ValueError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def get_instance_payload(request, conn=None):
    '''
    Gets all the payload of the task of an instance
    :param request: Http request
    :param conn: db connection
    :return: Http response -> dict
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.organization_instance_id]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)
            org_inst_id = request.data[var_names.organization_instance_id]

            if permissions.has_user_permission(user_perm, permissions.USER_INCIDENTS_VIEW_PERMISSION):
                payload = db_task_instances.get_instance_payload(conn, org_id, org_inst_id)
                return Response(payload)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError, ValueError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def list_instance_alerts(request, conn=None):
    '''
    Get the list of all task alerts that are associated to an instance.
    together with a particular instance.
    :param request: Http request
    :param conn: db connection
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)
            instance_id = request.data[var_names.instance_id]

            if permissions.has_user_permission(user_perm, permissions.USER_INCIDENTS_VIEW_PERMISSION):
                # We are not doing an advanced permission check here because the user will already have access
                # to the instance if this is being called. Avoiding the check will allow the query run faster.
                alert_list = db_tasks.get_task_alerts(conn, times.get_current_timestamp(), org_id,
                                                      instance_id=instance_id)
                return Response(alert_list)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def list_past_instances(request, conn=None):
    '''
    Gets the list of instances similar to a given instance
    that have occurred in the last 6 months.
    :param request: Http request
    :param conn: db connection
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.has_org_permission(org_perm, permissions.ORG_PAST_INCIDENTS_PERMISSION):

                if permissions.has_user_permission(user_perm, permissions.USER_INCIDENTS_VIEW_PERMISSION):

                    instance_id = request.data[var_names.instance_id]
                    current_time = times.get_current_timestamp()

                    inst_dict = db_task_instances.get_instances(conn, current_time, instance_id=instance_id)

                    if len(inst_dict) == 0:
                        raise LookupError(errors.err_unknown_resource)

                    inst_obj = inst_dict[instance_id]
                    instance_timestamp = inst_obj.instance_timestamp
                    created_by = inst_obj.task.details[var_names.created_by]
                    serv_id = inst_obj.task.details[var_names.service_id]
                    integration_id = inst_obj.task.details[var_names.integration_id]
                    min_start = datetime.datetime.combine((instance_timestamp - datetime.timedelta(days=180)),
                                                          datetime.datetime.min.time())

                    past_instances = db_task_instances.get_instances(
                        conn, instance_timestamp, org_id=org_id, service_id=serv_id, integration_id=integration_id,
                        created_by=created_by, min_timestamp=min_start, active=False, skip_instance_id=instance_id
                    )

                    similar_instances_date_dict = dict()
                    for i in range(0, 181):
                        similar_instances_date_dict[
                            (min_start.date() + datetime.timedelta(days=i)).strftime(constants.date_hyphen_format)] = []

                    if len(past_instances) > 0:
                        all_instances = list(past_instances.values())
                        all_instances.append(inst_obj)

                        inst_comparator = InstanceComparator(all_instances, instance_id)
                        similar_instances_list = inst_comparator.get_similar_instance_details()

                        if len(similar_instances_list) > 0:
                            # Replace the user ID of the resolver with their display name. There is a known
                            # limitation in this step. Ideally, the user ID should be mapped based on the
                            # instance timestamp. However, in order to save time we map it based on the current time.
                            # If the instance was resolved by a user who has since been removed from the organization
                            # then there will not be any map available for them at the current time and resolved by
                            # would stay empty.
                            resolver_ids = [int(item[var_names.resolved_by]) for item in similar_instances_list
                                            if item[var_names.resolved_by] is not None]
                            user_name_map = db_users.get_multiple_users_display_name(conn, current_time, org_id,
                                                                                     resolver_ids)
                            for item in similar_instances_list:
                                if item[var_names.resolved_by] is not None \
                                        and int(item[var_names.resolved_by]) in user_name_map:
                                    item[var_names.resolved_by] = user_name_map[int(item[var_names.resolved_by])]

                                item_date_str = item[var_names.instance_timestamp].date().strftime(
                                    constants.date_hyphen_format)
                                if item_date_str in similar_instances_date_dict:
                                    similar_instances_date_dict[item_date_str].append(item)

                            holder = []
                            for item in similar_instances_list:
                                id_ = item[var_names.instance_id]
                                inst = past_instances[id_]

                                holder.append({
                                    var_names.instance_id: id_,
                                    var_names.organization_instance_id: inst.organization_instance_id,
                                    var_names.instance_timestamp: inst.instance_timestamp,
                                    var_names.resolved_on: inst.resolved_on,
                                    var_names.assignee_level: inst.level,
                                    var_names.task_id: inst.task.taskid,
                                    var_names.task_title: inst.task.details[var_names.task_title],
                                    var_names.urgency_level: inst.task.details[var_names.urgency_level],
                                    var_names.service_id: inst.task.details[var_names.service_id],
                                    var_names.service_name: None,
                                    var_names.tags: None,
                                    var_names.assignees: [],
                                    var_names.events: inst.events,
                                    var_names.impacted_business_services: None
                                })

                            inst_analyzer = InstanceAnalyzer(configuration.standard_timezone, holder)
                            mean_duration = inst_analyzer.get_average_response_effort()
                            total_count = inst_analyzer.get_aggregate_instance_count()
                            week_count = inst_analyzer.get_aggregate_instance_count_within_period(
                                (instance_timestamp - datetime.timedelta(days=6)).date(), instance_timestamp.date())

                            data = {
                                var_names.mean_resolution_time: mean_duration,
                                var_names.total_incident_count: total_count,
                                var_names.week_incident_count: week_count,
                                var_names.incidents: similar_instances_date_dict
                            }
                            return Response(data)

                    return Response({
                        var_names.mean_resolution_time: 0,
                        var_names.total_incident_count: 0,
                        var_names.week_incident_count: 0,
                        var_names.incidents: similar_instances_date_dict
                    })
                else:
                    return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            else:
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def list_similar_ongoing_instances(request, conn=None):
    '''
    Gets the list of active instances similar to a given instance.
    :param request: Http request
    :param conn: db connection
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.has_org_permission(org_perm, permissions.ORG_INTELLIGENT_GROUPING_PERMISSION):

                if permissions.has_user_permission(user_perm, permissions.USER_INCIDENTS_VIEW_PERMISSION):

                    instance_id = request.data[var_names.instance_id]
                    current_time = times.get_current_timestamp()

                    inst_dict = db_task_instances.get_instances(conn, current_time, instance_id=instance_id)

                    if len(inst_dict) == 0:
                        raise LookupError(errors.err_unknown_resource)

                    inst_obj = inst_dict[instance_id]
                    current_time = times.get_current_timestamp()
                    created_by = inst_obj.task.details[var_names.created_by]
                    serv_id = inst_obj.task.details[var_names.service_id]
                    integration_id = inst_obj.task.details[var_names.integration_id]

                    current_instances = db_task_instances.get_instances(
                        conn, current_time, org_id=org_id, service_id=serv_id, integration_id=integration_id,
                        created_by=created_by, active=True, skip_instance_id=instance_id
                    )

                    holder = []
                    all_assignees = []
                    all_services = []
                    all_impacted_business_services = []

                    if len(current_instances) > 0:
                        all_instances = list(current_instances.values())
                        all_instances.append(inst_obj)

                        inst_comparator = InstanceComparator(all_instances, instance_id)
                        sim_inst_list = inst_comparator.get_similar_instance_details()

                        if len(sim_inst_list) > 0:
                            sim_inst_det = db_task_instances.get_instance_details(
                                conn, current_time, org_id,
                                instance_id=[item[var_names.instance_id] for item in sim_inst_list]
                            )

                            for item in sim_inst_list:
                                id_ = item[var_names.instance_id]
                                inst = sim_inst_det[id_]
                                holder.append(inst.to_dict())
                                if inst.assignees is not None:
                                    all_assignees += inst.assignees
                                if inst.task.details[var_names.services] is not None:
                                    all_services.append(inst.task.details[var_names.services])
                                if inst.impacted_business_services is not None:
                                    all_impacted_business_services += inst.impacted_business_services

                    return Response({
                        var_names.total_incident_count: len(holder),
                        var_names.assignees: all_assignees,
                        var_names.services: all_services,
                        var_names.impacted_business_services: all_impacted_business_services,
                        var_names.incidents: holder
                    })
                else:
                    return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            else:
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def acknowledge(request, conn=None, cache=None):
    '''
    Allows a user to acknowledge a task (instance of a task).
    :param request: Http Request
    :param conn: db connection
    :param cache: cache client
    :return: Http Response -> (timestamp)
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)

            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            instance_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            current_time = times.get_current_timestamp()

            if permissions.can_user_respond_to_incidents(user_perm):
                event = AcknowledgeEvent(instance_id, current_time, access_method, user_id)
                updated_next_alert = syncer_task_instances.acknowledge(
                    conn, cache, event, org_id=org_id,
                    has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                    has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm),
                    org_perm=org_perm
                )
                return Response(updated_next_alert)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.info(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def resolve(request, conn=None, cache=None):
    '''
    Allows a user to resolve a task (instance of a task).
    :param request: Http Request
    :param conn: db connection
    :param cache: cache client
    :return: Http Response -> (str)
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method]
        optional_fields = [var_names.skip_syncing]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields, optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            instance_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            skip_syncing = request.data[var_names.skip_syncing] if var_names.skip_syncing in request.data else None
            current_time = times.get_current_timestamp()

            if permissions.can_user_respond_to_incidents(user_perm):
                event = ResolveEvent(instance_id, current_time, access_method, user_id)
                syncer_task_instances.resolve(
                    conn, cache, event, org_id=org_id,
                    has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                    has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm),
                    lang=lang, skip_syncing=skip_syncing, org_perm=org_perm
                )
                return Response(_lt.get_label(info.msg_success, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.info(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def escalate(request, conn=None, cache=None):
    '''
    Allows a user to escalate a task to another policy.
    :param request: Http Request
    :param conn: db connection
    :param cache: cache client
    :return: Http Response -> str
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id]
        optional_fields = [var_names.access_method]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields, optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            instance_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]\
                if var_names.access_method in request.data else constants.app
            event_timestamp = times.get_current_timestamp()

            if permissions.can_user_respond_to_incidents(user_perm):
                instance = db_task_instances.get_instances(conn, event_timestamp, instance_id=instance_id)[instance_id]

                # handle group escalations
                all_policies = []
                policy_ids_from_instances = [assignee.for_policy_id for assignee in instance.assignees]
                if len(policy_ids_from_instances) > 0:
                    all_policies = db_policies.get_policies(conn, event_timestamp,
                                                            with_policyid=policy_ids_from_instances)

                allocator = EventAllocator(all_policies, None, None, None, None)
                allocator.handle_instance_escalation(event_timestamp, instance, escalated_by=user_id,
                                                     access_method=access_method)

                if len(allocator.escalations) == 0:
                    logging.error(errors.err_policy_no_escalations_available)
                    return Response(_lt.get_label(errors.err_policy_no_escalations_available, lang), status=400)
                else:
                    syncer_task_instances.escalate(
                        conn, cache, allocator.escalations, org_id=org_id,
                        has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                        has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm)
                    )

                    return Response(_lt.get_label(info.msg_success, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def reassign(request, conn=None, cache=None):
    '''
    Allows a user to re-assign a task to another policy.
    :param request: Http Request
    :param conn: db connection
    :param cache: cache client
    :return: Http Response -> str
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method, var_names.reassign_to]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            instance_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            reassign_to = request.data[var_names.reassign_to]
            current_time = times.get_current_timestamp()

            if permissions.can_user_respond_to_incidents(user_perm):
                new_pol_ids = db_policies.list_policy_ids_from_ref_ids(conn, current_time, org_id, reassign_to,
                                                                       unmasked=False)

                event = ReassignEvent(instance_id, current_time, access_method, user_id, new_pol_ids)
                syncer_task_instances.reassign(
                    conn, cache, event, org_id=org_id,
                    has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                    has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm))

                return Response(_lt.get_label(info.msg_success, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError, NoOneIsOnCall) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def snooze(request, conn=None, cache=None):
    '''
    Snooze a task for a few minutes.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method, var_names.snooze_for]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            instance_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            snooze_for = int(request.data[var_names.snooze_for])
            current_time = times.get_current_timestamp()

            if permissions.can_user_respond_to_incidents(user_perm):
                event = SnoozeEvent(instance_id, current_time, access_method, user_id, snooze_for)
                syncer_task_instances.snooze(
                    conn, cache, event, org_id=org_id,
                    has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                    has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm)
                )

                return Response(_lt.get_label(info.msg_success, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def un_acknowledge(request, conn=None, cache=None):
    '''
    Un-acknowledge an incident.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            instance_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            current_time = times.get_current_timestamp()

            if permissions.can_user_respond_to_incidents(user_perm):
                instance = db_task_instances.get_instances(conn, current_time, instance_id=instance_id)[instance_id]
                pol_dict = db_policies.get_policies(conn, current_time, with_policyid=list(instance.for_policy_ids()))
                for_policies = list(pol_dict.values()) if len(pol_dict) > 0 else []
                next_alert_time = InstanceState.calculate_next_alert_timestamp(instance.level, for_policies,
                                                                               current_time)
                event = UnAcknowledgeEvent(instance_id, current_time, access_method, user_id, next_alert_time)
                syncer_task_instances.un_acknowledge(
                    conn, cache, event, org_id=org_id,
                    has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                    has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm),
                    org_perm=org_perm
                )

                return Response(_lt.get_label(info.msg_success, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def amend_urgency(request, conn=None, cache=None):
    '''
    Amend the urgency level of an incident.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method, var_names.urgency_level]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            instance_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            new_urgency = request.data[var_names.urgency_level]
            current_time = times.get_current_timestamp()

            if permissions.can_user_respond_to_incidents(user_perm):
                event = UrgencyAmendmentEvent(instance_id, current_time, access_method, new_urgency, user_id)
                syncer_task_instances.amend_urgency(
                    conn, cache, [event], org_id=org_id,
                    has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                    has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm),
                    org_perm=org_perm
                )
                return Response(_lt.get_label(info.msg_success, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def add_responders(request, conn=None, cache=None):
    '''
    Add responders to an incident
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method, var_names.assignees]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            instance_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            new_assignees = request.data[var_names.assignees]
            current_time = times.get_current_timestamp()

            if permissions.has_org_permission(org_perm, permissions.ORG_ADD_RESPONDERS_PERMISSION):
                if permissions.can_user_respond_to_incidents(user_perm):
                    new_pol_ids = db_policies.list_policy_ids_from_ref_ids(conn, current_time, org_id, new_assignees,
                                                                           unmasked=False)

                    event = AddRespondersEvent(instance_id, current_time, access_method, new_pol_ids, user_id)
                    notifier = NoticeAllocator()
                    notifier = syncer_task_instances.add_responders(
                        conn, cache, event, org_id=org_id,
                        has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                        has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm),
                        notifier=notifier
                    )

                    if len(notifier.email_messages) > 0:
                        mail.AmazonSesBulkDispatcher(notifier.email_messages).start()

                    if len(notifier.push_notices) > 0:
                        app_notice.NoticeSender(notifier.push_notices).start()

                    if len(notifier.alert_logs) > 0:
                        AlertLogger(conn, notifier.alert_logs).start()

                    return Response(_lt.get_label(info.msg_success, lang))
                else:
                    return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            else:
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def notate(request, conn=None, cache=None):
    '''
    Add a note to an incident
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method, var_names.notes]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)

            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)
            instance_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            note = request.data[var_names.notes]
            current_time = times.get_current_timestamp()

            if not permissions.can_user_respond_to_incidents(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            event = NotateEvent(instance_id, current_time, access_method, user_id, note)
            syncer_task_instances.notate(
                conn, cache, event, org_id, org_perm,
                permissions.can_user_have_component_role(user_perm, org_perm),
                permissions.can_user_have_team_role(user_perm, org_perm),
                permissions.is_user_admin(user_perm)
            )
            return Response(_lt.get_label(info.msg_success, lang))
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def merge(request, conn=None, cache=None):
    '''
    Merge an instance with another instance.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method, var_names.related_instance_id]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.can_user_respond_to_incidents(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            inst_id = request.data[var_names.instance_id]
            rel_inst_id = request.data[var_names.related_instance_id]
            access_method = request.data[var_names.access_method]
            current_time = times.get_current_timestamp()

            if inst_id != rel_inst_id:
                event = MergeEvent(inst_id, current_time, access_method, rel_inst_id, user_id)
                syncer_task_instances.merge(
                    conn, cache, event, org_id=org_id,
                    has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                    has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm)
                )

            return Response(_lt.get_label(info.msg_success, lang))
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def un_merge(request, conn=None, cache=None):
    '''
    Un-merge an instance from another instance.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.task_ref_id, var_names.access_method]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.can_user_respond_to_incidents(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            current_time = times.get_current_timestamp()
            inst_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            task_ref_id = request.data[var_names.task_ref_id]
            task_ref_id_map = db_tasks.get_task_ids_from_ref_ids(conn, current_time, org_id, [task_ref_id],
                                                                 unmasked=False)
            if len(task_ref_id_map) == 0:
                raise InvalidRequest(errors.err_unknown_resource)

            task_id = list(task_ref_id_map.values())[0]

            event = UnMergeEvent(inst_id, current_time, access_method, task_id, user_id)
            syncer_task_instances.un_merge(
                conn, cache, event, org_id=org_id,
                has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm)
            )

            return Response(_lt.get_label(info.msg_success, lang))
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def redact(request, conn=None, cache=None):
    '''
    Redacts an incident. Be careful with this. This action cannot be undone.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.has_org_permission(org_perm, permissions.ORG_INCIDENT_REDACTION_PERMISSION):
                if permissions.is_user_owner(user_perm):
                    instance_id = request.data[var_names.instance_id]
                    current_time = times.get_current_timestamp()

                    syncer_task_instances.redact(conn, cache, current_time, instance_id, org_id, user_id)
                    return Response(_lt.get_label(info.msg_success, lang))
                else:
                    return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
            else:
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def add_subscribers(request, conn=None, cache=None):
    '''
    Add subscribers to an instance. Only user subscribers can be added.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method, var_names.subscribers]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            inst_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            subscriber_pref_names = request.data[var_names.subscribers]
            current_time = times.get_current_timestamp()

            if not permissions.has_org_permission(org_perm, permissions.ORG_INCIDENT_STATUS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            can_self_subscribe = True if subscriber_pref_names is None and\
                permissions.has_user_permission(user_perm, permissions.USER_INCIDENTS_SUBSCRIBE_PERMISSION) else False

            if can_self_subscribe or\
                    (subscriber_pref_names is not None and permissions.can_user_respond_to_incidents(user_perm)):

                if subscriber_pref_names is None:
                    subscriber_user_ids = [user_id]
                else:
                    subscriber_user_ids = db_users.get_user_ids_from_preferred_usernames(
                        conn, current_time, org_id, subscriber_pref_names)

                if len(subscriber_user_ids) > 0:
                    event = AddSubscribersEvent(inst_id, current_time, access_method, subscriber_user_ids, user_id)

                    syncer_task_instances.add_subscribers(
                        conn, cache, event, org_id=org_id,
                        is_sys_action=True if can_self_subscribe else False,
                        has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                        has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm)
                    )

                    return Response(_lt.get_label(info.msg_success, lang))
                else:
                    return Response(_lt.get_label(errors.err_unknown_resource, lang), status=400)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def remove_subscribers(request, conn=None, cache=None):
    '''
    Remove subscribers from an instance.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method, var_names.subscribers]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            inst_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            subscriber_pref_names = request.data[var_names.subscribers]
            current_time = times.get_current_timestamp()

            if not permissions.has_org_permission(org_perm, permissions.ORG_INCIDENT_STATUS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if (subscriber_pref_names is None and
                permissions.has_user_permission(user_perm, permissions.USER_INCIDENTS_SUBSCRIBE_PERMISSION)) or\
                    (subscriber_pref_names is not None and permissions.can_user_respond_to_incidents(user_perm)):

                if subscriber_pref_names is None:
                    subscriber_user_ids = [user_id]
                else:
                    subscriber_user_ids = db_users.get_user_ids_from_preferred_usernames(
                        conn, current_time, org_id, subscriber_pref_names)

                if len(subscriber_user_ids) > 0:
                    event = RemoveSubscribersEvent(inst_id, current_time, access_method, subscriber_user_ids, user_id)

                    syncer_task_instances.remove_subscribers(
                        conn, cache, event, org_id=org_id,
                        has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                        has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm)
                    )

                    return Response(_lt.get_label(info.msg_success, lang))
                else:
                    return Response(_lt.get_label(errors.err_unknown_resource, lang), status=400)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def update_status(request, conn=None, cache=None):
    '''
    Post a status update for an instance.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method, var_names.status_update]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_INCIDENT_STATUS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if not permissions.can_user_respond_to_incidents(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            instance_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            new_status = request.data[var_names.status_update]
            current_time = times.get_current_timestamp()

            event = StatusUpdateEvent(instance_id, current_time, access_method, new_status, user_id)
            syncer_task_instances.update_status(
                conn, cache, event, org_id, org_perm=org_perm,
                has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm)
            )
            return Response(_lt.get_label(info.msg_success, lang))
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def add_impacting_business_service(request, conn=None, cache=None):
    '''
    Add a new impacted business service to an incident.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method, var_names.business_service_ref_id]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_INCIDENT_STATUS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if not permissions.can_user_respond_to_incidents(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            instance_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            bus_ref_id = request.data[var_names.business_service_ref_id]
            current_time = times.get_current_timestamp()

            bus_id, bus_name = db_business_services.get_business_service_id_and_name_from_ref_id(
                conn, current_time, org_id, bus_ref_id
            )

            event = AddImpactedBusinessServiceEvent(instance_id, current_time, access_method, bus_id, user_id)
            syncer_task_instances.add_impacted_business_service(
                conn, cache, event, bus_name, org_id=org_id,
                has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm)
            )

            return Response(_lt.get_label(info.msg_success, lang))
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def remove_impacting_business_service(request, conn=None, cache=None):
    '''
    Remove an impacted business service from an incident.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method, var_names.business_service_ref_id]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_INCIDENT_STATUS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if not permissions.can_user_respond_to_incidents(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            instance_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]
            bus_ref_id = request.data[var_names.business_service_ref_id]
            current_time = times.get_current_timestamp()

            bus_id, bus_name = db_business_services.get_business_service_id_and_name_from_ref_id(
                conn, current_time, org_id, bus_ref_id
            )

            event = RemoveImpactedBusinessServiceEvent(instance_id, current_time, access_method, bus_id, user_id)
            syncer_task_instances.remove_impacted_business_service(
                conn, cache, event, org_id=org_id,
                has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm)
            )

            return Response(_lt.get_label(info.msg_success, lang))
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def run_response_set(request, conn=None):
    '''
    Run a response set on an incident
    :param request: Http request
    :param conn: db connection
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        try:
            return Response(_lt.get_label(errors.err_invalid_request, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def run_workflow(request, conn=None, cache=None):
    '''
    Run a workflow on an incident.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.workflow_ref_id, var_names.access_method]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_WORKFLOWS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            instance_id = request.data[var_names.instance_id]
            flow_ref_id = request.data[var_names.workflow_ref_id]
            access_method = request.data[var_names.access_method]
            current_time = times.get_current_timestamp()
            flow_id = db_workflows.get_workflow_id_from_ref_id(conn, current_time, org_id, flow_ref_id)

            if db_workflows.has_run_permission(conn, current_time, org_id, flow_id, user_id,
                                               permissions.can_user_respond_to_incidents(user_perm)):
                WorkflowManager(conn, cache, org_id, org_perm, instance_id, workflow_ids=[flow_id],
                                access_method=access_method, lang=lang).execute_workflow()
                return Response(_lt.get_label(info.msg_success, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def add_conference_bridge(request, conn=None, cache=None):
    '''
    Add a conference bridge to an incident.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.access_method]
        optional_fields = [var_names.conference_id, var_names.conference_phone, var_names.conference_url]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields, optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_CONFERENCE_BRIDGES_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if not permissions.can_user_respond_to_incidents(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            instance_id = request.data[var_names.instance_id]
            access_method = request.data[var_names.access_method]

            conf_id = request.data[var_names.conference_id] if var_names.conference_id in request.data else None
            conf_phone = request.data[var_names.conference_phone]\
                if var_names.conference_phone in request.data else None
            conf_url = request.data[var_names.conference_url] if var_names.conference_url in request.data else None
            current_time = times.get_current_timestamp()

            if conf_id is not None:
                conf_details = db_instance_utilities.get_conference_bridge_details(conn, current_time, conf_id)
            else:
                if conf_phone is None and conf_url is None:
                    raise InvalidRequest(errors.err_conference_bridge_phone_url_invalid)

                conf_details = {
                    var_names.conference_phone: conf_phone,
                    var_names.conference_url: conf_url,
                    var_names.integration_type: None,
                    var_names.external_id: None,
                    var_names.external_info: None
                }

            notifier = NoticeAllocator()
            notifier = syncer_task_instances.add_conference_bridge(
                conn, cache, current_time, notifier, org_id, instance_id, conf_details, access_method,
                user_id=user_id, is_sys_action=True
            )

            if len(notifier.email_messages) > 0:
                mail.AmazonSesBulkDispatcher(notifier.email_messages).start()

            if len(notifier.push_notices) > 0:
                app_notice.NoticeSender(notifier.push_notices).start()

            if len(notifier.alert_logs) > 0:
                AlertLogger(conn, notifier.alert_logs).start()

            return Response(_lt.get_label(info.msg_success, lang))
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def list_task_alerts(request, conn=None):
    '''
    Gets a list of all alerts that have been created in the organization, except for pre-scheduled alerts.
    :param request: Http request
    :param conn: db connection
    :return: Http response -> list of dict
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        optional_fields = [var_names.assignee_type, var_names.row_limit, var_names.row_offset]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, [], optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)
            assignee_type = request.data[var_names.assignee_type] if var_names.assignee_type in request.data \
                else constants.user_assignee
            row_limit = request.data[var_names.row_limit] if var_names.row_limit in request.data else None
            row_offset = request.data[var_names.row_offset] if var_names.row_offset in request.data else None

            if assignee_type == constants.team_assignee and\
                    not permissions.has_org_permission(org_perm, permissions.ORG_TEAMS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if permissions.has_user_permission(user_perm, permissions.USER_INCIDENTS_VIEW_PERMISSION):
                do_adv_check = permissions.get_user_advanced_check_status(user_perm, org_perm)[0]
                alerts = db_tasks.get_task_alerts(conn, times.get_current_timestamp(), org_id, row_limit=row_limit,
                                                  row_offset=row_offset, user_id=user_id, check_adv_perm=do_adv_check)
                return Response(alerts)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except InvalidRequest as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def execute_custom_action(request, conn=None, cache=None):
    '''
    Sync an incident with an external vendor's incident equivalent.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.integration_key]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_INTEGRATION_SECONDARY_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if not permissions.can_user_respond_to_incidents(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            instance_id = request.data[var_names.instance_id]
            integ_key = request.data[var_names.integration_key]
            current_time = times.get_current_timestamp()

            integ_details = db_integrations.get_comprehensive_integration_details(
                conn, current_time, org_id, integration_key=integ_key, for_custom_action=True)

            if len(integ_details) == 1:
                integ_details = integ_details[0]
                inst_obj = db_task_instances.get_instances(conn, current_time, instance_id)[instance_id]

                exe_status, exe_output = custom_action_manager.execute_custom_action(
                    conn, cache, current_time, org_id, org_perm, instance_id, inst_obj, integ_details,
                    integ_key, user_id=user_id, run_manually=True, dedup_key=None, lang=lang,
                    has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                    has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm)
                )

                if exe_status in [200, 201]:
                    return Response(_lt.get_label(info.msg_incident_action_executed, lang))
                else:
                    return Response(_lt.get_label(errors.err_system_error, lang), status=500)
            else:
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def edit_title(request, conn=None, cache=None):
    '''
    Edit the title of an incident.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.task_title, var_names.access_method]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_WORKFLOWS_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if not permissions.can_user_respond_to_incidents(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            instance_id = request.data[var_names.instance_id]
            new_title = request.data[var_names.task_title]
            access_method = request.data[var_names.access_method]
            current_time = times.get_current_timestamp()

            event = EditTitleEvent(instance_id, current_time, access_method, user_id, new_title)
            syncer_task_instances.edit_title(
                conn, cache, event, org_id=org_id,
                has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm)
            )

            return Response(_lt.get_label(info.msg_success, lang))
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def live_call_numbers(request, conn=None):
    '''
    Get the caller and receiver phone numbers of a live call associated to a given instance.
    :param request: Http request
    :param conn: db connection
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_LIVE_CALL_ROUTING_SECONDARY_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
            if not permissions.has_user_permission(user_perm, permissions.USER_INCIDENTS_RESPOND_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            inst_id = request.data[var_names.instance_id]
            current_time = times.get_current_timestamp()
            det = db_live_call_routing.get_call_numbers(conn, current_time, org_id, inst_id)
            return Response(det)
        except InvalidRequest as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def update_tags(request, conn=None):
    '''
    Update tags associated to an incident.
    :param request: Http request
    :param conn: db connection
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.tags, var_names.access_method]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_CONTEXTUAL_SEARCH_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if not permissions.can_user_respond_to_incidents(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            instance_id = request.data[var_names.instance_id]
            tags = request.data[var_names.tags]
            access_method = request.data[var_names.access_method]

            current_time = times.get_current_timestamp()
            event = UpdateTagsEvent(instance_id, current_time, access_method, tags, user_id)

            db_events.book_update_tags_event(
                conn, event, org_id=org_id,
                has_comp_perm=permissions.can_user_have_component_role(user_perm, org_perm),
                has_team_perm=permissions.can_user_have_team_role(user_perm, org_perm)
            )
            return Response(_lt.get_label(info.msg_success, lang))
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def link_instance(request, conn=None):
    '''
    Link a task instance with a vendor equivalent incident item. Incidents are only linked tracking (not syncing).
    :param request: Http request
    :param conn: db connection
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.integration_type, var_names.vendor_id]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_INTEGRATION_CUSTOMER_SERVICE_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if not permissions.can_user_respond_to_incidents(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            inst_id = request.data[var_names.instance_id]
            integ_type = request.data[var_names.integration_type]
            ticket_id = str(request.data[var_names.vendor_id])
            current_time = times.get_current_timestamp()

            db_events.link_instance(conn, current_time, org_id, inst_id, integ_type, ticket_id, user_id)
            return Response(_lt.get_label(info.msg_success, lang))
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def unlink_instance(request, conn=None):
    '''
    Unlink an instance from the vendor equivalent incident item.
    :param request: Http request
    :param conn: db connection
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.instance_id, var_names.integration_type, var_names.vendor_id]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_INTEGRATION_CUSTOMER_SERVICE_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if not permissions.can_user_respond_to_incidents(user_perm):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            inst_id = request.data[var_names.instance_id]
            integ_type = request.data[var_names.integration_type]
            ticket_id = str(request.data[var_names.vendor_id])
            current_time = times.get_current_timestamp()

            db_events.unlink_instance(conn, current_time, org_id, inst_id, integ_type, ticket_id)
            return Response(_lt.get_label(info.msg_success, lang))
        except (InvalidRequest, LookupError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def get_linked_instances(request, conn=None):
    '''
    Get the details of a TaskCall instances that are linked to a particular vendor and its incident equivalent item.
    :param request: Http request
    :param conn: db connection
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.integration_type, var_names.vendor_id]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_org_permission(org_perm, permissions.ORG_INTEGRATION_CUSTOMER_SERVICE_PERMISSION):
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

            if not permissions.has_user_permission(user_perm, permissions.USER_INCIDENTS_VIEW_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            current_time = times.get_current_timestamp()
            integ_type = request.data[var_names.integration_type]
            ticket_id = str(request.data[var_names.vendor_id])
            inst_id_list = db_task_instances.get_linked_instances(conn, current_time, org_id, integ_type, ticket_id)

            inst_obj_list = []
            if inst_id_list is not None and len(inst_id_list) > 0:
                inst_obj_dict = db_task_instances.get_instance_details(conn, current_time, org_id,
                                                                       instance_id=inst_id_list)
                inst_obj_list = [item.to_dict() for item in list(inst_obj_dict.values())]

            return Response(inst_obj_list)
        except InvalidRequest as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)


@api_view(['POST'])
def create_onboarding_test_instance(request, conn=None, cache=None):
    '''
    Create a test incident.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: Http response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            cache = CACHE_CLIENT if cache is None else cache
            request_validator.validate_fields(request, [])
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if not permissions.has_user_permission(user_perm, permissions.USER_INCIDENTS_CREATE_PERMISSION):
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)

            current_time = times.get_current_timestamp()
            user_pol_id = db_users.get_user(conn, current_time, user_id=user_id)[user_id].policy_id
            trig_method = constants.internal
            urgency = 5
            title = 'Welcome Test Incident'
            text_msg = '''
            [Fri Dec 16 01:46:23 2005] [error] [client 1.2.3.4] Directory index forbidden by rule: /home/test/
            [Fri Dec 16 01:54:34 2005] [error] [client 1.2.3.4] Directory index forbidden by rule: /apache/web/test2
            [Fri Dec 16 02:25:55 2005] [error] [client 1.2.3.4] Client sent malformed Host header
            [Mon Dec 19 23:02:01 2005] [error] [client 1.2.3.4] Authentication error: "/~dcid/test1": Password Mismatch
            '''
            trig_info = {
                var_names.utc_timestamp: current_time,
                var_names.title: title,
                var_names.description: text_msg,
                var_names.service_ref_id: None,
                var_names.urgency_level: urgency,
                var_names.trigger_method: trig_method,
                var_names.source_payload: None,
                var_names.notes: None,
                var_names.tags: None,
                var_names.dedup_key: None,
                var_names.integration_key: None,
                var_names.snapshots: ['https://taskcallapp.com/images/app/SampleGraph.png'],
                var_names.voice_messages: None,
                var_names.vendor_url: None
            }
            syncer_task_instances.create_task(
                conn, cache, current_time, org_id, current_time.date(), title, configuration.standard_timezone,
                current_time.time(), assignees=[user_pol_id], text_msg=text_msg, urgency_level=urgency,
                trigger_method=trig_method, trigger_info=trig_info
            )
            return Response(info.msg_success)
        except InvalidRequest as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except MaliciousSource as e:
            logging.error(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except (UnauthorizedRequest, jwt.ExpiredSignatureError, jwt.InvalidSignatureError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_authorization, lang), status=401)
        except Exception as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_system_error, lang), status=500)
        finally:
            CONN_POOL.put_db_conn(conn)
