# By: Riasat Ullah
# This file contains service related views.

from data_syncers import syncer_services
from dbqueries import db_integrations, db_policies, db_services, db_tasks, db_task_instances
from dbqueries.integrations import db_autotask, db_jira, db_monday, db_servicenow
from exceptions.user_exceptions import DependencyFound, InvalidRequest, UnauthorizedRequest
from integrations import jira_cloud, jira_server, monday, sentry, team_dynamix
from rest_framework.decorators import api_view
from rest_framework.response import Response
from taskcallrest import settings
from translators import label_translator as _lt
from utils import cdn_enablers, constants, errors, info, integration_type_names as intt, key_manager, logging, \
    permissions, times, tokenizer, var_names
from utils.db_connection import CACHE_CLIENT, CONN_POOL
from validations import request_validator, string_validator
import configuration
import datetime
import jwt


@api_view(['POST'])
def create_service(request, conn=None):
    '''
    Creates a new service for the organization.
    :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.service_name, var_names.description, var_names.policy_ref_id]
        optional_fields = [var_names.re_trigger_minutes, var_names.support_days, var_names.support_start,
                           var_names.support_end, var_names.timezone, var_names.de_prioritize, var_names.re_prioritize,
                           var_names.allow_grouping]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields, optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.has_user_permission(user_perm, permissions.USER_COMPONENTS_EDIT_PERMISSION):
                current_time = times.get_current_timestamp()
                ref_key = db_services.create_service(
                    conn, current_time, org_id, request.data[var_names.service_name],
                    request.data[var_names.description], request.data[var_names.policy_ref_id],
                    re_trigger_minutes=request.data[var_names.re_trigger_minutes]
                    if var_names.re_trigger_minutes in request.data else None,
                    support_days=request.data[var_names.support_days]
                    if var_names.support_days in request.data else None,
                    support_start=request.data[var_names.support_start]
                    if var_names.support_start in request.data else None,
                    support_end=request.data[var_names.support_end] if var_names.support_end in request.data else None,
                    support_timezone=request.data[var_names.timezone] if var_names.timezone in request.data else None,
                    de_prioritize=request.data[var_names.de_prioritize]
                    if var_names.de_prioritize in request.data else None,
                    re_prioritize=request.data[var_names.re_prioritize]
                    if var_names.re_prioritize in request.data else None,
                    allow_grouping=request.data[var_names.allow_grouping]
                    if var_names.allow_grouping in request.data else None
                )

                masked_ref_key = key_manager.conceal_reference_key(ref_key)
                return Response(masked_ref_key)
            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 edit_service(request, conn=None, cache=None):
    '''
    Edit an existing service.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.service_ref_id, var_names.service_name, var_names.description,
                           var_names.policy_ref_id]
        optional_fields = [var_names.re_trigger_minutes, var_names.support_days, var_names.support_start,
                           var_names.support_end, var_names.timezone, var_names.de_prioritize, var_names.re_prioritize,
                           var_names.allow_grouping]
        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 permissions.can_user_edit_components(user_perm, org_perm):
                do_adv_check, do_comp_check, do_team_check =\
                    permissions.get_user_advanced_check_status(user_perm, org_perm)

                current_time = times.get_current_timestamp()
                serv_ref_id = request.data[var_names.service_ref_id]
                syncer_services.edit_service(
                    conn, cache, current_time, serv_ref_id, org_id, user_id, request.data[var_names.service_name],
                    request.data[var_names.description], request.data[var_names.policy_ref_id],
                    re_trigger_minutes=request.data[var_names.re_trigger_minutes]
                    if var_names.re_trigger_minutes in request.data else None,
                    support_days=request.data[var_names.support_days]
                    if var_names.support_days in request.data else None,
                    support_start=request.data[var_names.support_start]
                    if var_names.support_start in request.data else None,
                    support_end=request.data[var_names.support_end] if var_names.support_end in request.data else None,
                    support_timezone=request.data[var_names.timezone] if var_names.timezone in request.data else None,
                    de_prioritize=request.data[var_names.de_prioritize]
                    if var_names.de_prioritize in request.data else None,
                    re_prioritize=request.data[var_names.re_prioritize]
                    if var_names.re_prioritize in request.data else None,
                    allow_grouping=request.data[var_names.allow_grouping]
                    if var_names.allow_grouping in request.data else None,
                    check_adv_perm=do_adv_check,
                    has_comp_perm=do_comp_check,
                    has_team_perm=do_team_check
                )
                return Response(_lt.get_label(info.msg_service_edited, lang))
            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 PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        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 delete_service(request, conn=None, cache=None):
    '''
    Deletes a service.
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.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 permissions.can_user_edit_components(user_perm, org_perm):
                do_adv_check, do_comp_check, do_team_check =\
                    permissions.get_user_advanced_check_status(user_perm, org_perm)

                current_time = times.get_current_timestamp()
                serv_ref_id = request.data[var_names.service_ref_id]
                syncer_services.delete_service(conn, cache, current_time, org_id, user_id, serv_ref_id,
                                               check_adv_perm=do_adv_check,
                                               has_comp_perm=do_comp_check,
                                               has_team_perm=do_team_check)
                return Response(_lt.get_label(info.msg_service_deleted, 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 DependencyFound as e:
            logging.info(e.message + e.additional_message)
            return Response(_lt.get_label(e.message, lang) + e.additional_message, 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 enable_service(request, conn=None, cache=None):
    '''
    Enable or disable a service
    :param request: Http request
    :param conn: db connection
    :param cache: cache client
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        expected_fields = [var_names.service_ref_id, var_names.is_enabled]
        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.can_user_edit_components(user_perm, org_perm):
                do_adv_check, do_comp_check, do_team_check =\
                    permissions.get_user_advanced_check_status(user_perm, org_perm)

                current_time = times.get_current_timestamp()
                serv_ref_id = request.data[var_names.service_ref_id]
                to_enable = request.data[var_names.is_enabled]

                syncer_services.enable_service(
                    conn, cache, current_time, serv_ref_id, org_id, user_id, to_enable,
                    check_adv_perm=do_adv_check, has_comp_perm=do_comp_check, has_team_perm=do_team_check
                )
                return Response(_lt.get_label(info.msg_service_edited, lang))
            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 PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        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_services(request, conn=None):
    '''
    Gets the list of services as a directory.
    :param request: Http request
    :param conn: db connection
    :return: JSON response -> list
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.can_user_view_components(user_perm):
                do_adv_check = permissions.get_user_advanced_check_status(user_perm, org_perm)[0]
                current_time = times.get_current_timestamp()

                data_list = db_services.list_services(conn, current_time, org_id, user_id, check_adv_perm=do_adv_check)

                if len(data_list) > 0:
                    all_pol_ids = [item[var_names.policy_id] for item in data_list]
                    all_pol_obj = db_policies.get_policies(conn, current_time, with_policyid=all_pol_ids,
                                                           with_org_id=org_id, for_display=True)
                    for serv in data_list:
                        pol_obj = all_pol_obj[serv[var_names.policy_id]]
                        serv[var_names.on_call] = [[item[1], item[0]] for item in pol_obj.get_on_call(level_number=1)]
                        del serv[var_names.policy_id]

                return Response(data_list)
            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_service_details(request, conn=None):
    '''
    Gets the details of a service.
    :param request: Http request
    :param conn: db connection
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        optional_fields = [var_names.service_ref_id]
        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)

            if permissions.can_user_view_components(user_perm):
                do_adv_check = permissions.get_user_advanced_check_status(user_perm, org_perm)[0]
                current_time = times.get_current_timestamp()

                data = db_services.get_service_details(conn, current_time, org_id, user_id,
                                                       request.data[var_names.service_ref_id],
                                                       check_adv_perm=do_adv_check)
                return Response(data)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), 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_service_integrations(request, conn=None):
    '''
    Get all the integrations of a service.
    :param request: Http request
    :param conn: db connection
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        optional_fields = [var_names.service_ref_id]
        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)

            if permissions.can_user_view_components(user_perm):
                do_adv_check = permissions.get_user_advanced_check_status(user_perm, org_perm)[0]
                current_time = times.get_current_timestamp()
                data = db_services.get_service_integrations(conn, current_time, org_id,
                                                            request.data[var_names.service_ref_id],
                                                            user_id=user_id, check_adv_perm=do_adv_check)

                for item in data:
                    if item[var_names.integration_type] == intt.autotask:
                        item[var_names.additional_info] = db_autotask.externalize_autotask_mappings(
                            conn, current_time, org_id, item[var_names.additional_info])
                    elif item[var_names.integration_type] == intt.servicenow:
                        item[var_names.additional_info] = db_servicenow.externalize_servicenow_mappings(
                            conn, current_time, org_id, item[var_names.additional_info])

                return Response(data)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), 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 add_service_integration(request, conn=None, cache=None):
    '''
    Creates a new internal endpoint integration. Internal endpoint integrations are those that are done
    by allocating a separate internal endpoint to receive data from the external vendor.
    :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.service_ref_id, var_names.integration_type, var_names.integration_name]
        optional_fields = [var_names.email, var_names.integration_url, var_names.access_token,
                           var_names.secret_token, var_names.vendor_endpoint, var_names.vendor_endpoint_name,
                           var_names.vendor_account_name, var_names.incoming_events, var_names.outgoing_events,
                           var_names.conditions_map, var_names.payload_map, var_names.is_public,
                           var_names.additional_info, var_names.external_id, var_names.external_info]
        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 permissions.can_user_edit_components(user_perm, org_perm):
                do_adv_check, do_comp_check, do_team_check =\
                    permissions.get_user_advanced_check_status(user_perm, org_perm)

                current_time = times.get_current_timestamp()
                integ_type = request.data[var_names.integration_type]
                out_events = request.data[var_names.outgoing_events]\
                    if var_names.outgoing_events in request.data else None
                addn_info = request.data[var_names.additional_info]\
                    if var_names.additional_info in request.data else None
                ext_info = request.data[var_names.external_info] if var_names.external_info in request.data else None
                integ_key = key_manager.generate_reference_key()

                # Make sure that the integration key in the assigned url is concealed.
                integ_url = request.data[var_names.integration_url] if var_names.integration_url in request.data\
                    else intt.get_integration_url(integ_type, key_manager.conceal_reference_key(integ_key))

                # If integration is for a custom action, then confirm that the account has the correct permission
                if integ_type in [intt.custom_endpoint, intt.rundeck] and not permissions.has_org_permission(
                        org_perm, permissions.ORG_CUSTOM_ACTION_PERMISSION):
                    return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

                # If recent changes integration, check if organization has recent changes permission
                if integ_type in configuration.allowed_recent_changes_integrations and\
                        not permissions.has_org_permission(org_perm, permissions.ORG_RECENT_CHANGES_PERMISSION):
                    return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

                # De-duplication of external ID is handled in the db query for all integrations.

                # Autotask
                if integ_type == intt.autotask:
                    if not permissions.has_org_permission(org_perm, permissions.ORG_INTEGRATION_ITSM_PERMISSION):
                        return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

                    # include the custom action event in the outgoing events
                    out_events = [constants.custom_action_event] if out_events is None\
                        else list(set(out_events + [constants.custom_action_event]))

                    addn_info = db_autotask.internalize_autotask_mappings(conn, current_time, org_id, addn_info)

                # Freshdesk
                elif integ_type == intt.freshdesk:
                    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)

                    # include the custom action event in the outgoing events
                    out_events = [constants.custom_action_event] if out_events is None\
                        else list(set(out_events + [constants.custom_action_event]))

                # Freshservice
                elif integ_type == intt.freshservice:
                    if not permissions.has_org_permission(org_perm, permissions.ORG_INTEGRATION_ITSM_PERMISSION):
                        return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

                    # include the custom action event in the outgoing events
                    out_events = [constants.custom_action_event] if out_events is None\
                        else list(set(out_events + [constants.custom_action_event]))

                elif integ_type == intt.haloitsm:
                    if not permissions.has_org_permission(org_perm, permissions.ORG_INTEGRATION_ITSM_PERMISSION):
                        return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

                    # include the custom action event in the outgoing events
                    out_events = [constants.custom_action_event] if out_events is None \
                        else list(set(out_events + [constants.custom_action_event]))

                # Jira Cloud
                elif integ_type == intt.jira_cloud:
                    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)

                    # include the custom action event in the outgoing events
                    out_events = [constants.custom_action_event] if out_events is None\
                        else list(set(out_events + [constants.custom_action_event]))

                    jira_jql = addn_info[var_names.jira_jql]
                    if jira_jql is not None and not string_validator.is_empty_string(jira_jql):
                        jira_cloud_id = request.data[var_names.vendor_endpoint_name]

                        # If an organization_integration_type_details entry exists for a given Jira cloud account
                        # for the organization, then access and refresh tokens are not sent in the payload. They
                        # are updated prior to the successful addition of the integration. We do this because the
                        # old tokens are naturally expired in the Jira authorization process. So, the new tokens
                        # have to be stored regardless.
                        if ext_info is not None:
                            access_token = ext_info[var_names.access_token]
                            refresh_token = ext_info[var_names.refresh_token]
                        else:
                            jira_req_det = db_jira.get_jira_request_acceptance_details(conn, current_time, org_id,
                                                                                       cloud_id=jira_cloud_id)
                            access_token = jira_req_det[var_names.access_token]
                            refresh_token = jira_req_det[var_names.refresh_token]

                        integ_url = jira_cloud.tc_jira_incoming_url.format(jira_cloud_id)
                        webhook_id, webhook_error = jira_cloud.create_jira_webhook(
                            conn, current_time, org_id, integ_url, jira_jql, cloud_id=jira_cloud_id,
                            access_token=access_token, refresh_token=refresh_token
                        )
                        if webhook_id is not None:
                            addn_info[var_names.webhook_id] = webhook_id
                        else:
                            err = _lt.get_label(errors.err_jql_invalid, lang)
                            if webhook_error is not None:
                                err += ': ' + webhook_error
                            return Response(err, status=400)
                    else:
                        addn_info[var_names.webhook_id] = None

                # Jira Server
                elif integ_type == intt.jira_server:
                    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)

                    # include the custom action event in the outgoing events
                    out_events = [constants.custom_action_event] if out_events is None\
                        else list(set(out_events + [constants.custom_action_event]))

                    jira_jql = addn_info[var_names.jira_jql]
                    if jira_jql is not None and not string_validator.is_empty_string(jira_jql):
                        jira_server_host = request.data[var_names.vendor_endpoint]

                        # If an organization_integration_type_details entry exists for a given Jira cloud account
                        # for the organization, then access and refresh tokens are not sent in the payload. They
                        # are updated prior to the successful addition of the integration. We do this because the
                        # old tokens are naturally expired in the Jira authorization process. So, the new tokens
                        # have to be stored regardless.
                        if ext_info is not None:
                            admin_user = ext_info[var_names.username]
                            admin_password = ext_info[var_names.password]
                        else:
                            jira_host_det = db_jira.get_jira_server_host_details(
                                conn, current_time, org_id, host_address=jira_server_host)
                            admin_user = jira_host_det[var_names.username]
                            admin_password = jira_host_det[var_names.password]

                        integ_url = jira_server.tc_jira_incoming_url.format(
                            key_manager.conceal_reference_key(integ_key))
                        webhook_id = jira_server.create_jira_webhook(
                            conn, current_time, org_id, integ_url, jira_jql, srv_host=jira_server_host,
                            srv_admin=admin_user, srv_pwd=admin_password
                        )
                        if webhook_id is not None:
                            addn_info[var_names.webhook_id] = webhook_id
                        else:
                            return Response(_lt.get_label(errors.err_jql_invalid, lang), status=400)
                    else:
                        addn_info[var_names.webhook_id] = None

                # monday.com
                elif integ_type == intt.monday:
                    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)

                    # include the custom action event in the outgoing events
                    out_events = [constants.custom_action_event] if out_events is None\
                        else list(set(out_events + [constants.custom_action_event]))

                    monday_account_id = request.data[var_names.vendor_endpoint_name]
                    if ext_info is not None:
                        access_token = ext_info[var_names.access_token]
                    else:
                        mon_req_det = db_monday.get_monday_request_acceptance_details(
                            conn, current_time, org_id, account_id=monday_account_id)
                        access_token = mon_req_det[var_names.access_token]
                    monday_board_id = addn_info[var_names.monday_board_id]
                    monday_webhook_details = addn_info[var_names.webhooks]
                    if monday_webhook_details is not None and len(monday_webhook_details) > 0:
                        fmt_wh_det = []
                        all_webhook_ids = monday.create_monday_webhook(
                            conn, current_time, org_id, integ_url, monday_board_id,
                            monday_webhook_details, access_token=access_token
                        )
                        for i in range(0, len(monday_webhook_details)):
                            if all_webhook_ids[i] is not None:
                                fmt_wh_det.append({**monday_webhook_details[i],
                                                   **{var_names.webhook_id: all_webhook_ids[i]}})

                        addn_info[var_names.webhooks] = fmt_wh_det if len(fmt_wh_det) > 0 else None

                # Custom Endpoint, Rundeck
                elif integ_type in [intt.custom_endpoint, intt.rundeck]:
                    if not permissions.has_org_permission(org_perm, permissions.ORG_CUSTOM_ACTION_PERMISSION):
                        return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

                    # include the custom action event in the outgoing events
                    out_events = [constants.custom_action_event] if out_events is None\
                        else list(set(out_events + [constants.custom_action_event]))

                # ServiceNow
                elif integ_type == intt.servicenow:
                    if not permissions.has_org_permission(org_perm, permissions.ORG_INTEGRATION_ITSM_PERMISSION):
                        return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

                    # include the custom action event in the outgoing events
                    out_events = [constants.custom_action_event] if out_events is None\
                        else list(set(out_events + [constants.custom_action_event]))

                    addn_info = db_servicenow.internalize_servicenow_mappings(conn, current_time, org_id, addn_info)

                # TeamDynamix
                elif integ_type == intt.team_dynamix:
                    if not permissions.has_org_permission(org_perm, permissions.ORG_INTEGRATION_ITSM_PERMISSION):
                        return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

                    # include the custom action event in the outgoing events
                    out_events = [constants.custom_action_event] if out_events is None\
                        else list(set(out_events + [constants.custom_action_event]))

                    # If an organization_integration_type_details entry exists for a given TeamDynamix account
                    # for the organization, then username and password are not sent in the payload. They
                    # are updated prior to the successful addition of the integration.
                    if ext_info is not None:
                        acc_domain = request.data[var_names.vendor_endpoint_name]
                        admin_user = ext_info[var_names.username]
                        admin_password = ext_info[var_names.password]
                        admin_uid = team_dynamix.get_admin_uid(acc_domain, admin_user, admin_password)
                        if admin_uid is None:
                            return Response(_lt.get_label(errors.err_team_dynamix_invalid_admin_credentials, lang),
                                            status=403)
                        else:
                            ext_info[var_names.user_object_id] = admin_uid

                # Zendesk
                elif integ_type == intt.zendesk:
                    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)

                    # include the custom action event in the outgoing events
                    out_events = [constants.custom_action_event] if out_events is None\
                        else list(set(out_events + [constants.custom_action_event]))

                # Save the actual integration here
                syncer_services.add_service_integration(
                    conn, cache, current_time, org_id, request.data[var_names.service_ref_id],
                    integ_type, integ_key, request.data[var_names.integration_name],
                    integ_email=request.data[var_names.email] if var_names.email in request.data else None,
                    integ_url=integ_url,
                    access_token=request.data[var_names.access_token]
                    if var_names.access_token in request.data else None,
                    secret_token=request.data[var_names.secret_token]
                    if var_names.secret_token in request.data else None,
                    vendor_endpoint=request.data[var_names.vendor_endpoint]
                    if var_names.vendor_endpoint in request.data else None,
                    vendor_endpoint_name=request.data[var_names.vendor_endpoint_name]
                    if var_names.vendor_endpoint_name in request.data else None,
                    vendor_account_name=request.data[var_names.vendor_account_name]
                    if var_names.vendor_account_name in request.data else None,
                    incoming_events=request.data[var_names.incoming_events]
                    if var_names.incoming_events in request.data else None,
                    outgoing_events=out_events,
                    conditions_map=request.data[var_names.conditions_map]
                    if var_names.conditions_map in request.data else None,
                    payload_map=request.data[var_names.payload_map] if var_names.payload_map in request.data else None,
                    public_access=request.data[var_names.is_public] if var_names.is_public in request.data else None,
                    additional_info=addn_info,
                    external_id=request.data[var_names.external_id] if var_names.external_id in request.data else None,
                    external_info=ext_info,
                    updated_by=user_id,
                    check_adv_perm=do_adv_check,
                    has_comp_perm=do_comp_check,
                    has_team_perm=do_team_check
                )

                return Response(_lt.get_label(info.msg_service_integration_added, lang))
            else:
                return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)
        except AssertionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(errors.err_invalid_request, lang), status=401)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), 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 edit_service_integration(request, conn=None, cache=None):
    '''
    Allows an organization admin to remove a particular internal endpoint integration.
    Internal endpoint integrations are those that are done by allocating a separate internal endpoint
    to receive data from the external vendor.
    :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.service_ref_id, var_names.integration_key, var_names.integration_name,
                           var_names.integration_type]
        optional_fields = [var_names.additional_info]
        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 permissions.can_user_edit_components(user_perm, org_perm):
                do_adv_check, do_comp_check, do_team_check =\
                    permissions.get_user_advanced_check_status(user_perm, org_perm)

                serv_ref = key_manager.unmask_reference_key(request.data[var_names.service_ref_id])
                integ_key = request.data[var_names.integration_key]
                integ_name = request.data[var_names.integration_name]
                integ_add_info = request.data[var_names.additional_info]\
                    if var_names.additional_info in request.data else None

                # existing integration details
                current_time = times.get_current_timestamp()
                curr_integ_details = db_integrations.get_comprehensive_integration_details(
                    conn, current_time, org_id, integration_key=integ_key)[0]
                curr_integ_type = curr_integ_details[var_names.integration_type]
                curr_add_info = curr_integ_details[var_names.additional_info]

                # If integration is for a custom action, then confirm that the account has the correct permission
                if curr_integ_type in [intt.custom_endpoint, intt.rundeck] and not permissions.has_org_permission(
                        org_perm, permissions.ORG_CUSTOM_ACTION_PERMISSION):
                    return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

                # Autotask
                if curr_integ_type == intt.autotask:
                    if not permissions.has_org_permission(org_perm, permissions.ORG_INTEGRATION_ITSM_PERMISSION):
                        return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

                    integ_add_info = db_autotask.internalize_autotask_mappings(conn, current_time, org_id,
                                                                               integ_add_info)

                # Jira Cloud
                elif curr_integ_type == intt.jira_cloud and\
                        curr_add_info[var_names.jira_jql] != integ_add_info[var_names.jira_jql]:

                    integ_url = jira_cloud.tc_jira_incoming_url.format(curr_integ_details[var_names.vendor_endpoint_name])
                    new_jql = integ_add_info[var_names.jira_jql]
                    old_webhook_id = curr_add_info[var_names.webhook_id]

                    if old_webhook_id is not None and (new_jql is None or string_validator.is_empty_string(new_jql)):
                        jira_cloud.delete_jira_webhook(conn, current_time, org_id, integ_key, old_webhook_id)
                        curr_add_info[var_names.webhook_id] = None
                    else:
                        webhook_id, webhook_error = jira_cloud.create_jira_webhook(
                            conn, current_time, org_id, integ_url, integ_add_info[var_names.jira_jql],
                            integ_key=integ_key, webhook_to_del=old_webhook_id
                        )
                        if webhook_id is not None:
                            curr_add_info[var_names.webhook_id] = webhook_id
                        else:
                            err = _lt.get_label(errors.err_jql_invalid, lang)
                            if webhook_error is not None:
                                err += ': ' + webhook_error
                            return Response(err, status=400)

                # Jira Server
                elif curr_integ_type == intt.jira_server and\
                        curr_add_info[var_names.jira_jql] != integ_add_info[var_names.jira_jql]:

                    integ_url = jira_server.tc_jira_incoming_url.format(integ_key)
                    new_jql = integ_add_info[var_names.jira_jql]
                    old_webhook_id = curr_add_info[var_names.webhook_id]

                    if old_webhook_id is not None and (new_jql is None or string_validator.is_empty_string(new_jql)):
                        jira_server.delete_jira_webhook(conn, current_time, org_id, integ_key, old_webhook_id)
                        curr_add_info[var_names.webhook_id] = None
                    else:
                        webhook_id = jira_server.create_jira_webhook(
                            conn, current_time, org_id, integ_url, integ_add_info[var_names.jira_jql],
                            integ_key=integ_key, webhook_to_del=old_webhook_id
                        )
                        if webhook_id is not None:
                            curr_add_info[var_names.webhook_id] = webhook_id
                        else:
                            return Response(_lt.get_label(errors.err_jql_invalid, lang), status=400)

                # monday.com
                elif curr_integ_type == intt.monday and\
                        curr_add_info[var_names.webhooks] != integ_add_info[var_names.webhooks]:

                    integ_url = curr_integ_details[var_names.integration_url]
                    old_webhook_details = curr_add_info[var_names.webhooks]
                    new_board_id = integ_add_info[var_names.monday_board_id]
                    new_webhook_details = integ_add_info[var_names.webhooks]

                    if old_webhook_details is not None and len(old_webhook_details) > 0:
                        for item in old_webhook_details:
                            monday.delete_monday_webhook(conn, current_time, org_id, integ_key,
                                                         item[var_names.webhook_id])

                    if new_webhook_details is not None and len(new_webhook_details) > 0:
                        fmt_wh_det = []
                        all_webhook_ids = monday.create_monday_webhook(
                            conn, current_time, org_id, integ_url, new_board_id, new_webhook_details,
                            integ_key=integ_key
                        )
                        for i in range(0, len(new_webhook_details)):
                            if all_webhook_ids[i] is not None:
                                fmt_wh_det.append({**new_webhook_details[i],
                                                   **{var_names.webhook_id: all_webhook_ids[i]}})

                        integ_add_info[var_names.webhooks] = fmt_wh_det if len(fmt_wh_det) > 0 else None
                        del curr_add_info[var_names.webhooks]

                # ServiceNow
                elif curr_integ_type == intt.servicenow:
                    if not permissions.has_org_permission(org_perm, permissions.ORG_INTEGRATION_ITSM_PERMISSION):
                        return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

                    integ_add_info = db_servicenow.internalize_servicenow_mappings(conn, current_time, org_id,
                                                                                   integ_add_info)

                # Combine additional info details from before with the new ones to make sure that attributes that
                # have not been included in the new one are not removed. Not all details are sent back from the
                # user side Javascript. In some cases this is not true. Hence, those need to be handled separately.
                if curr_add_info is None or\
                        curr_integ_type in [intt.custom_endpoint, intt.rundeck, intt.servicenow, intt.zendesk]:
                    new_add_info = integ_add_info
                else:
                    new_add_info = {**curr_add_info, **integ_add_info}

                syncer_services.edit_service_integration(
                    conn, cache, current_time, org_id, serv_ref, user_id, integ_key, integ_name,
                    additional_info=new_add_info, check_adv_perm=do_adv_check, has_comp_perm=do_comp_check,
                    has_team_perm=do_team_check
                )
                return Response(_lt.get_label(info.msg_service_integration_edited, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), 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 delete_service_integration(request, conn=None, cache=None):
    '''
    Allows an organization admin to remove a particular internal endpoint integration.
    Internal endpoint integrations are those that are done by allocating a separate internal endpoint
    to receive data from the external vendor.
    :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.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 permissions.can_user_edit_components(user_perm, org_perm):
                do_adv_check, do_comp_check, do_team_check =\
                    permissions.get_user_advanced_check_status(user_perm, org_perm)
                cdn_key_info = None

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

                curr_integ_details = db_integrations.get_comprehensive_integration_details(
                    conn, current_time, org_id, integration_key=integ_key)[0]
                curr_integ_type = curr_integ_details[var_names.integration_type]
                curr_add_info = curr_integ_details[var_names.additional_info]

                # If integration is for a custom action, then confirm that the account has the correct permission
                if curr_integ_type in [intt.custom_endpoint, intt.rundeck] and not permissions.has_org_permission(
                        org_perm, permissions.ORG_CUSTOM_ACTION_PERMISSION):
                    return Response(_lt.get_label(errors.err_subscription_rights, lang), status=403)

                # Handle integration specific actions here before processing the deletion internally
                if curr_integ_type == intt.jira_cloud and curr_add_info is not None:
                    webhook_id = curr_add_info[var_names.webhook_id]
                    if webhook_id is not None:
                        jira_cloud.delete_jira_webhook(conn, current_time, org_id, integ_key, webhook_id)

                elif curr_integ_type == intt.jira_server and curr_add_info is not None:
                    webhook_id = curr_add_info[var_names.webhook_id]
                    if webhook_id is not None:
                        jira_server.delete_jira_webhook(conn, current_time, org_id, integ_key, webhook_id)

                elif curr_integ_type == intt.monday and curr_add_info is not None:
                    webhooks = curr_add_info[var_names.webhooks]
                    if webhooks is not None:
                        for item in webhooks:
                            monday.delete_monday_webhook(conn, current_time, org_id, integ_key,
                                                         item[var_names.webhook_id])

                # Handle cdn routing specific matters for the US region here.
                if settings.REGION == constants.aws_us_ohio:
                    if curr_integ_type == intt.google_chat and curr_add_info is not None:
                        cdn_key_info = (
                            intt.google_chat,
                            cdn_enablers.create_cdn_cache_key(
                                intt.google_chat, curr_add_info[var_names.team_id], curr_add_info[var_names.channel_id]
                            )
                        )

                    elif curr_integ_type == intt.microsoft_teams and curr_add_info is not None:
                        cdn_key_info = (
                            intt.microsoft_teams,
                            cdn_enablers.create_cdn_cache_key(
                                intt.microsoft_teams, curr_add_info[var_names.tenant_id],
                                curr_add_info[var_names.channel_id]
                            )
                        )

                    elif curr_integ_type == intt.sentry and curr_add_info is not None:
                        cdn_key_info = (
                            intt.sentry,
                            cdn_enablers.create_cdn_cache_key(
                                intt.sentry, curr_add_info[sentry.str_sentry_installation_id]
                            )
                        )
                    elif curr_integ_type == intt.slack and curr_add_info is not None:
                        cdn_key_info = (
                            intt.slack,
                            cdn_enablers.create_cdn_cache_key(
                                intt.slack, curr_add_info[var_names.team_id], curr_add_info[var_names.channel_id]
                            )
                        )

                syncer_services.delete_service_integration(conn, cache, current_time, org_id, user_id, integ_key,
                                                           check_adv_perm=do_adv_check,
                                                           has_comp_perm=do_comp_check,
                                                           has_team_perm=do_team_check,
                                                           cdn_key_info=cdn_key_info)

                return Response(_lt.get_label(info.msg_service_integration_deleted, lang))
            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 transfer_service_integration(request, conn=None, cache=None):
    '''
    Allows an organization admin to remove a particular internal endpoint integration.
    Internal endpoint integrations are those that are done by allocating a separate internal endpoint
    to receive data from the external vendor.
    :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.integration_key, var_names.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 permissions.can_user_edit_components(user_perm, org_perm):
                do_adv_check, do_comp_check, do_team_check =\
                    permissions.get_user_advanced_check_status(user_perm, org_perm)

                current_time = times.get_current_timestamp()
                syncer_services.transfer_service_integration(conn, cache, current_time, org_id, user_id,
                                                             request.data[var_names.integration_key],
                                                             request.data[var_names.service_ref_id],
                                                             check_adv_perm=do_adv_check,
                                                             has_comp_perm=do_comp_check,
                                                             has_team_perm=do_team_check)
                return Response(_lt.get_label(info.msg_service_integration_transferred, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), 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_all_service_maintenances(request, conn=None):
    '''
    Gets the maintenance windows of all services across the organization.
    :param request: Http request
    :param conn: db connection
    :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
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.can_user_view_components(user_perm):
                do_adv_check = permissions.get_user_advanced_check_status(user_perm, org_perm)[0]
                current_time = times.get_current_timestamp()
                data = db_services.get_all_service_maintenances(conn, current_time, org_id, user_id,
                                                                check_adv_perm=do_adv_check)
                return Response(data)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), 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 add_service_maintenance(request, conn=None, cache=None):
    '''
    Creates a new internal endpoint integration. Internal endpoint integrations are those that are done
    by allocating a separate internal endpoint to receive data from the external vendor.
    :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.service_ref_id, var_names.maintenance_start, var_names.maintenance_end,
                           var_names.timezone, var_names.reason]
        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.can_user_edit_components(user_perm, org_perm):
                do_adv_check, do_comp_check, do_team_check =\
                    permissions.get_user_advanced_check_status(user_perm, org_perm)

                current_time = times.get_current_timestamp()
                serv_ref_id = request.data[var_names.service_ref_id]
                mnt_start = times.get_timestamp_from_string(request.data[var_names.maintenance_start])
                mnt_end = times.get_timestamp_from_string(request.data[var_names.maintenance_end])
                mnt_tz = request.data[var_names.timezone]

                syncer_services.add_service_maintenance(conn, cache, current_time, serv_ref_id, org_id, user_id,
                                                        mnt_start, mnt_end, mnt_tz,
                                                        reason=request.data[var_names.reason],
                                                        check_adv_perm=do_adv_check,
                                                        has_comp_perm=do_comp_check,
                                                        has_team_perm=do_team_check)
                return Response(_lt.get_label(info.msg_service_maintenance_added, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), 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 delete_service_maintenance(request, conn=None, cache=None):
    '''
    Creates a new internal endpoint integration. Internal endpoint integrations are those that are done
    by allocating a separate internal endpoint to receive data from the external vendor.
    :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.service_ref_id, var_names.maintenance_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.can_user_edit_components(user_perm, org_perm):
                do_adv_check, do_comp_check, do_team_check =\
                    permissions.get_user_advanced_check_status(user_perm, org_perm)

                current_time = times.get_current_timestamp()
                serv_ref_id = request.data[var_names.service_ref_id]
                mnt_id = request.data[var_names.maintenance_id]

                syncer_services.delete_service_maintenance(conn, cache, current_time, org_id, user_id,
                                                           serv_ref_id, mnt_id,
                                                           check_adv_perm=do_adv_check,
                                                           has_comp_perm=do_comp_check,
                                                           has_team_perm=do_team_check)
                return Response(_lt.get_label(info.msg_service_maintenance_removed, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), 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_service_recent_incidents(request, conn=None):
    '''
    Get the summary of the incidents that have recently occurred on a service.
    :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.service_ref_id]
        optional_fields = [var_names.days_buffer]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields, optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.can_user_view_components(user_perm):
                current_time = times.get_current_timestamp()
                serv_ref_id = request.data[var_names.service_ref_id]
                buffer = 30 if var_names.days_buffer not in request.data else request.data[var_names.days_buffer]
                min_time = current_time - datetime.timedelta(days=buffer)
                min_time = datetime.datetime.combine(min_time, datetime.datetime.min.time())

                data_list = db_task_instances.list_instances(conn, current_time, org_id, user_id,
                                                             service_ref_id=serv_ref_id,
                                                             min_timestamp=min_time)
                return Response(data_list)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), 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_service_recent_suppressed_alerts(request, conn=None):
    '''
    Get the task alerts that have been recently suppressed on this service.
    :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.service_ref_id]
        optional_fields = [var_names.days_buffer]
        try:
            conn = CONN_POOL.get_db_conn() if conn is None else conn
            request_validator.validate_fields(request, expected_fields, optional_fields)
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.can_user_view_components(user_perm):
                current_time = times.get_current_timestamp()
                serv_ref_id = request.data[var_names.service_ref_id]
                buffer = 30 if var_names.days_buffer not in request.data else request.data[var_names.days_buffer]
                min_date = (current_time - datetime.timedelta(days=buffer)).date()

                # 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 to run faster.
                data_list = db_tasks.get_task_alerts(conn, current_time, org_id, status=constants.suppressed_state,
                                                     service_ref_id=serv_ref_id, min_trigger_date=min_date)
                return Response(data_list)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), 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_service_dependencies(request, conn=None):
    '''
    Get all the service dependencies (both technical and business). This will be needed for the service graph.
    :param request: Http request
    :param conn: db connection
    :return: JSON 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
            request_validator.validate_fields(request, [])
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.can_user_view_components(user_perm):
                current_time = times.get_current_timestamp()
                details = db_services.get_system_dependencies(conn, current_time, org_id)

                if len(details) > 0:
                    all_pol_ids = [details[key][var_names.policy_id] for key in details
                                   if details[key][var_names.is_technical]]
                    all_pol_obj = db_policies.get_policies(conn, current_time, with_policyid=all_pol_ids,
                                                           with_org_id=org_id, for_display=True)
                    for key in details:
                        serv_dep = details[key]
                        if serv_dep[var_names.is_technical]:
                            pol_obj = all_pol_obj[serv_dep[var_names.policy_id]]

                            serv_dep[var_names.policy] =\
                                [pol_obj.policy_name, key_manager.conceal_reference_key(pol_obj.reference_id)]
                            serv_dep[var_names.on_call] = [[item[1], item[0]]
                                                           for item in pol_obj.get_on_call(level_number=1)]
                        else:
                            serv_dep[var_names.policy] = None
                            serv_dep[var_names.on_call] = None

                        del serv_dep[var_names.policy_id]

                return Response(details)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        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_service_specific_technical_dependencies(request, conn=None):
    '''
    Get only the technical dependencies of a service.
    :param request: Http request
    :param conn: db connection
    :return: JSON response
    '''
    if request.method == 'POST':
        lang = request_validator.get_user_language(request)
        optional_fields = [var_names.service_ref_id, var_names.organization_instance_id]
        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)

            if permissions.can_user_view_components(user_perm):
                srv_ref = request.data[var_names.service_ref_id] if var_names.service_ref_id in request.data else None
                org_inst_id = request.data[var_names.organization_instance_id]\
                    if var_names.organization_instance_id in request.data else None
                current_time = times.get_current_timestamp()
                tech_deps = db_services.get_service_technical_dependencies(
                    conn, current_time, org_id, service_ref_id=srv_ref, org_instance_id=org_inst_id)
                return Response(tech_deps)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        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_service_dependency(request, conn=None):
    '''
    Add a  new system dependency (technical or business).
    :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.dependency_from, var_names.dependency_to]
        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.can_user_edit_components(user_perm, org_perm):
                do_adv_check, do_comp_check, do_team_check = \
                    permissions.get_user_advanced_check_status(user_perm, org_perm)

                current_time = times.get_current_timestamp()
                db_services.add_system_dependency(
                    conn, current_time, org_id, user_id, request.data[var_names.dependency_from],
                    request.data[var_names.dependency_to], check_adv_perm=do_adv_check,
                    has_comp_perm=do_comp_check, has_team_perm=do_team_check
                )
                return Response(_lt.get_label(info.msg_success, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        except (LookupError, TypeError) as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=400)
        except DependencyFound as e:
            logging.exception(e.message + e.additional_message)
            return Response(_lt.get_label(e.message, lang) + e.additional_message, 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 delete_service_dependency(request, conn=None):
    '''
    Remove an existing system dependency (technical or business).
    :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.dependency_from, var_names.dependency_to]
        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.can_user_edit_components(user_perm, org_perm):
                do_adv_check, do_comp_check, do_team_check = \
                    permissions.get_user_advanced_check_status(user_perm, org_perm)

                current_time = times.get_current_timestamp()
                db_services.delete_system_dependency(
                    conn, current_time, org_id, user_id, request.data[var_names.dependency_from],
                    request.data[var_names.dependency_to], check_adv_perm=do_adv_check,
                    has_comp_perm=do_comp_check, has_team_perm=do_team_check
                )
                return Response(_lt.get_label(info.msg_success, lang))
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        except PermissionError as e:
            logging.exception(str(e))
            return Response(_lt.get_label(str(e), lang), status=403)
        except (LookupError, TypeError) 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_component_dependencies(request, conn=None):
    '''
    Get all the service dependencies (both technical and business). This is only used for the mobile app.
    :param request: Http request
    :param conn: db connection
    :return: JSON 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
            request_validator.validate_fields(request, [])
            user_id, org_id, user_perm, org_perm = tokenizer.authorize_request(request)

            if permissions.can_user_view_components(user_perm):
                current_time = times.get_current_timestamp()
                details = db_services.list_system_component_state(conn, current_time, org_id)

                if len(details) > 0:
                    all_pol_ids = [item[var_names.policy_id] for item in details if item[var_names.is_technical]]
                    all_pol_obj = db_policies.get_policies(conn, current_time, with_policyid=all_pol_ids,
                                                           with_org_id=org_id, for_display=True)
                    for serv_dep in details:
                        if serv_dep[var_names.is_technical]:
                            pol_obj = all_pol_obj[serv_dep[var_names.policy_id]]

                            serv_dep[var_names.policy] =\
                                [pol_obj.policy_name, key_manager.conceal_reference_key(pol_obj.reference_id)]
                            serv_dep[var_names.on_call] = [[item[1], item[0]]
                                                           for item in pol_obj.get_on_call(level_number=1)]
                        else:
                            serv_dep[var_names.policy] = None
                            serv_dep[var_names.on_call] = None

                        del serv_dep[var_names.policy_id]

                return Response(details)
            else:
                return Response(_lt.get_label(errors.err_user_rights, lang), status=403)
        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)