production-taskbar / backend / helpdesk / sysaid.py
sysaid.py
Raw
import io
import logging
import os
import re
import urllib.parse
from datetime import datetime
from typing import Any, Dict, Tuple

import requests
from django.core.cache import cache
from django.utils.timezone import make_aware

from .models import Department, Issue, Reciever, Status

api_url = os.environ.get('DATA_ACQUISITION_URL')


def is_sysaid(reciever: Reciever) -> int:
    sysaid_match = re.match(r'sys.?aid', reciever.name, re.IGNORECASE)
    return True if sysaid_match else False


def parse_username(responsibility: str) -> str:
    string = responsibility.replace('.', ' ').title()
    result = string.split('\\')
    if result.__len__() >= 2: return result[-1]
    return string


def url_encode(string: str) -> str:
    return urllib.parse.quote(string)


def create_sysaid_ticket(config: Dict[str, Any],
                         data: Dict[str, Any]) -> Tuple[bool, Dict[str, Any]]:

    def generate_body(data: Dict[str, Any]) -> str:
        template = "formID=0&reRoute=1&isLogged=1&noframe=null&type=null&subType=null&populateSR_id=182806&customFormCodeHiddenValue=&paneMessage=&paneType=&paneBtnArrayButtons=&panePreSubmitFunc=&panePreSubmitFunc2=&paneCancelFunc=&paneTextRow=&centerPopup=&parentPageName=SubmitSR.jsp&tabID=180&populateSR=&changedFields=null%5Eproblem_type%5Esubcategory%5EthirdLevelCategory%5Etitle%5Edesc&userChanged=0&requestUser={request_user}&autoAttach2ContactCiHidden=true&company={company_id}&problem_type=07.+Field_Support&subcategory=10.+FS_Ukraine&thirdLevelCategory=+&autoDescriptionTemplate=N&title={title}&desc={desc}&selectUrgency={urgency}&selectImpact=1&cust_list1={impact}&computer={hostname}&autoAttach2AssetCiHidden=true&removeAction=&notes=&noteToAdd=&verifyText=&location={location_id}&Apply=&OK=OK&Cancel=&Addtokb=&subAction=&reopenNote=&pageID=1&subPageID=1&replacePage=Y&changes=0&currentSupportLevel=0&CustomColumn150sr=2&CustomColumn170sr=Choose+Admin+group+who+will+be+informed+by+email.+If+you+don%27t+wish+to+inform+your+team+by+email%2C+Choose+Admin+group%3A+none&CustomColumn130sr=&CustomColumn175sr=&newActivities=&deletedActivities=&existingActiviteies=&changeCategory=0&resp=none&assignCounter=0&CustomColumn122sr=&followupUser=null&CustomColumn158sr=2&dueDate=&CustomColumn166sr=When+you+set+the+Security+Incident+or+MI+Flag+you+need+to+follow+Information+Security+Incident+management+procedure+or+Major+Incident+Procedure.+&autoMessages=true&custDate1=&hidden_disable_email_notifications_for_end_users=false&quick_name=null&quickSrId=182806&custDate2=&workaround=&CustomColumn162sr=&followupText=&adminGroup=none&CustomColumn180sr=&CustomColumn10sr=2&CustomColumn181sr=2&CustomColumn182sr=&CustomColumn176sr=&CustomColumn119sr=&selectPriority=1&custNotes=&CustomColumn12sr=&userManager=null&CustomColumn9sr=2&custText1=&custText2=&custInt1=0&custInt2=0&CustomColumn184sr=&projectID=0&attachedCIId=0&emailAccount=+&cc=&CustomColumn4sr=&updateUser=SEBN%5Cnuri.ramadan&CustomColumn146sr=2&CustomColumn154sr=&taskID=0&resolution=&solution=&CustomColumn5sr=&responsibleManager=null&followupPlannedDate=&CustomColumn6sr=&maxSupportLevel=0&CustomColumn138sr=2&cust_list2=0&CustomColumn174sr=&successRating=0&agreement=0&CustomColumn134sr=1&escalation=0&followupActualDate="

        department = Department.objects.get(pk=data['department_id'])
        location_id = config['locations'][department.location.name]
        body = template.format(title=url_encode(data['title']),
                               desc=url_encode(data['description']),
                               urgency=data['urgency'],
                               impact=data['impact'],
                               hostname=url_encode(data['hostname']),
                               request_user=config['request_user'],
                               location_id=location_id,
                               company_id=config.get('company_id', None))
        return body

    def parse_issue_id(string: str) -> int | None:
        pattern = config['response_id_regex']
        result = re.search(pattern, string)
        if (result):
            issue_id = result.group(1)
            return int(issue_id)

        return None

    server = config['server']

    url = f'{server}SubmitSR.jsp'
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Connection': 'close',
        'Origin': server,
        'Referer': url,
        'Cookie': config['cookie']
    }
    body = generate_body(data)
    response = requests.post(url, data=body, headers=headers)
    issue_id = parse_issue_id(response.text)
    if issue_id:
        href = f'{server}index.jsp#/SREdit.jsp?id={issue_id}'
        text = f'<b>Sysaid ticket</b> <a href="{href}">#{issue_id}</a>'

        return (True, {'issue_id': issue_id, 'text': text})
    return (False, {
        'status_code': response.status_code,
        'text': response.text
    })


def fetch_sysaid_ticket(id: int) -> Any:
    url = f'{api_url}sebn-data-acquisition/api/sebn-taskbar-manager/service-req/'
    response = requests.post(url, json={"id": id})
    if response.status_code == 200:
        return response.json()
    logging.error(f'Error on fetch_sysaid_ticket: {response.status_code}')
    return None


def save_sysaid_fields(issue: Issue, fields: Dict[str, str]) -> Issue:

    issue_status_id = fields['status']

    cached_existed_status_ids = cache.get('status_ids', [])

    if not cached_existed_status_ids:
        cached_existed_status_ids = Status.objects.all().values(
            'id', 'redmine_code', 'sysaid_code')
        cache.set('status_ids', cached_existed_status_ids)

    for s in cached_existed_status_ids:
        if s['sysaid_code'] == issue_status_id:
            issue.status_id = s['id']    # type: ignore

    ## not cached old code
    # status = Status.objects.filter(sysaid_code=fields['status']).first()
    # if status: issue.status = status

    if (fields['responsibility']):
        issue.responsibility = parse_username(fields['responsibility'])
    issue.comments = fields['notes']
    if (fields['update_time']):
        issue.update_datetime = make_aware(
            datetime.fromisoformat(fields['update_time']))
    if (fields['close_time']):
        issue.close_datetime = make_aware(
            datetime.fromisoformat(fields['close_time']))
    issue.save()
    return issue


def fetch_layout(hostname: str) -> Tuple[Any, str] | None:
    url = f'{api_url}sebn-material-requests-manager/api/location/'
    hostname_url = f'{api_url}sebn-material-requests-manager/locate/{hostname}'
    response = requests.post(url, json={"hostname": hostname})
    if response.status_code == 200:
        return (io.BytesIO(response.content).read(), hostname_url)
    return None