<commit_before>commonfields:
  id: jira
  version: -1
name: jira
display: Jira
category: IT Services
image: data:image/png;base64,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
description: Issue tracking product, developed by Atlassian
detaileddescription: |
  For fetching incidents, please update the query param according to JQL: https://confluence.atlassian.com/jirasoftwarecloud/advanced-searching-764478330.html
  Update there the project you want to fetch from like:  "project = soc AND  status=open".
  This will fetch for first time all tickets in your system (include past) that are in open status and in project soc, after first run, it will create incident only for new tickets,
  If you wish to start in first time from a specific position, use "Issue index to start fetching incidents from" param.
  
  you can also fetch incidents by time (by issues created field) by turning on the  "Use created field to fetch incidents" field, instead of using id's.  
configuration:
- display: Jira URL, in the format https://demisto.atlassian.net/
  name: url
  defaultvalue: ""
  type: 0
  required: true
- display: Username
  name: username
  defaultvalue: ""
  type: 0
  required: true
- display: Password
  name: password
  defaultvalue: ""
  type: 4
  required: true
- display: Insecure
  name: insecure
  defaultvalue: "true"
  type: 8
  required: false
- display: Query for fetching incident in JQL
  name: query
  defaultvalue: status=open
  type: 0
  required: false
- display: Issue index to start fetching incidents from
  name: idOffset
  defaultvalue: "10000"
  type: 0
  required: false
- display: Fetch incidents
  name: isFetch
  defaultvalue: ""
  type: 8
  required: false
- display: Incident type
  name: incidentType
  defaultvalue: ""
  type: 13
  required: false
- display: Use created field to fetch incidents
  name: fetchByCreated
  defaultvalue: ""
  type: 8
  required: false  
script:
  script: |-
    // handle '/' at the end of the url
    if (params.url[params.url.length - 1] != '/') {
        params.url = params.url + '/';
    }

    var getCookies = function() {
        var result = http(
            params.url+'rest/auth/1/session',
            {
                Headers: {'Content-Type': ['application/json']},
                Method: 'POST',
                Username: params.username,
                Password: <PASSWORD>,
                Body: JSON.stringify({'username':params.username,'password':<PASSWORD>}),
            },
            params.insecure
        );
        if (result.StatusCode !== 200 && result.StatusCode !== 201) {
            throw 'Failed to create auth cookie, request status code: ' + result.StatusCode + ', check that username/password are correct';
        }
        return result.Cookies;
    };

    var addQueryParam = function(urlSuffix, paramName, value){
        if (value && value.length > 0){
            urlSuffix = urlSuffix + '&' + paramName + '=' + value;
        }
        return urlSuffix;
    };

    var uploadFile = function(entryId, issueId) {
        var cookies = getCookies();
        var res = httpMultipart(
            params.url+'rest/api/2/issue/' + issueId + '/attachments',
            entryId,
            {
                Method: 'POST',
                Cookies: cookies,
                Username: params.username,
                Password: <PASSWORD>,
                Headers: {'X-Atlassian-Token': ['no-check']},
            },
            {
            },
            params.insecure
        );
        if (res.StatusCode !== 200) {
            return 'Failed to execute request:' + res.StatusCode + ', body: ' + res.Body;
        }
        return JSON.parse(res.Body);
    };

    var runQuery = function(query, startAt, maxResults) {
        var cookies = getCookies();
        var url = params.url+'rest/api/2/search?jql='+encodeURIComponent(query);
        url = addQueryParam(url,'startAt',startAt);
        url = addQueryParam(url,'maxResults',maxResults);
        var result = http(
            url,
            {
                Headers: {'Content-Type': ['application/json']},
                Method: 'GET',
                Username: params.username,
                Password: <PASSWORD>,
                Cookies: cookies,
            },
            params.insecure
        );
        if (result.StatusCode !== 200) {
            throw 'Failed to jira-issue-query, request status code: ' + result.StatusCode + ', body: ' + result.Body;
        }
        return JSON.parse(result.Body);
    };


    var cleanNullFields = function(obj) {
        for(prop in obj){
            if(obj[prop] === null || obj[prop] === undefined || obj[prop] ==="" )
            delete obj[prop];
        }
        return obj;
    }


    var generateMDContextGetIssue = function(data) {
        var getIssueObj = {md: [] , context: {Ticket: []}};
        if(!Array.isArray(data)) {
            data = [data];
        }
        data.forEach(function (element) {
            mdObj ={};
            contextObj = {};

            var id = dq(element, 'id');
            mdObj['id'] = id;
            contextObj['Id'] = id;

            var key = dq(element, 'key');
            mdObj['key'] = key;
            contextObj['Key'] = key;

            var assignee = dq(element, 'fields.assignee.displayName') + "(" + dq(element, 'fields.assignee.emailAddress') + ")";
            mdObj['assignee'] = assignee;
            contextObj['Assignee'] = assignee;

            mdObj['reporter'] = dq(element, 'fields.reporter.displayName') + "(" + dq(element, 'fields.reporter.emailAddress') + ")";

            var creator = dq(element, 'fields.creator.displayName') + "(" + dq(element, 'fields.creator.emailAddress') + ")";
            mdObj['creator'] = creator;
            contextObj['Creator'] = creator;

            var summary = dq(element, 'fields.summary');
            mdObj['summary'] = summary;
            contextObj['Summary'] = summary;

            var status = dq(element, 'fields.status.name')
            mdObj['status'] = status;
            contextObj['Status'] = status;

            mdObj['issueType'] = dq(element, 'fields.issuetype.description');
            mdObj['priority'] = dq(element, 'fields.priority.name');
            mdObj['project'] = dq(element, 'fields.project.name');
            mdObj['labels'] = dq(element, 'fields.labels');
            mdObj['description'] = dq(element, 'fields.description');
            mdObj['duedate'] = dq(element, 'fields.duedate');
            mdObj['ticket_link'] = dq(element, 'self');
            mdObj['creted'] = dq(element, 'fields.created');
            var attachments = dq(element, 'fields.attachment');
            if(Array.isArray(attachments) && attachments.length > 0) {
                var attachmentNames = [];
                attachments.forEach(function (attach) {
                    attachmentNames.push(attach['filename']);
                });
                mdObj['attachment'] = attachmentNames.join();
            }
            getIssueObj['md'].push(mdObj);
            getIssueObj['context'].Ticket.push(contextObj);
        });
        return getIssueObj;
    }

    var generateMdContextCreateIssue = function(data) {
        var createIssueObj = {md: [] , context: {Ticket: []}};
        createIssueObj['md'].push(data);
        var id = dq(data, 'id');
        createIssueObj['context'].Ticket.push({ID: id});
        return createIssueObj;
    }


    var generateMdCommentOrLinkIssue = function(data) {
        var commentOrLinkMd = [];
        if(!Array.isArray(data)) {
            data = [data];
        }
        data.forEach(function (element) {
            mdObj ={};
            mdObj['ID'] = dq(element, 'id');
            mdObj['key'] = dq(element, 'updateAuthor.key');
            mdObj['commnet'] = dq(element, 'body');
            mdObj['ticket_link'] = dq(element, 'self');
            commentOrLinkMd.push(mdObj);
        });
        return commentOrLinkMd;
    }

    var generateMdUplosdIssue = function(data) {
        var uploadMd = [];
        if(!Array.isArray(data)) {
            data = [data];
        }
        data.forEach(function (element) {
            mdObj ={};
            mdObj['ID'] = dq(element, 'id');
            mdObj['key'] = dq(element, 'updateAuthor.key');
            mdObj['attachment'] = dq(element, 'fields.attachment');
            mdObj['ticket_link'] = dq(element, 'self');
            uploadMd.push(mdObj);
        });
        return uploadMd;
    }


    var createIncidentFromTicket = function(issue) {
        var keys = Object.keys(issue);
        var labels = [];

        labels.push({'type': 'issue', 'value': JSON.stringify(issue)});
        //Send specific issue information only
        //log ('id = ' + String(issue.id));
        labels.push({'type': 'id', 'value': String(issue.id)});

        //log ('lastViewed = ' + String(issue.fields.lastViewed));
        labels.push({'type': 'lastViewed', 'value': String(issue.fields.lastViewed)});

        //log ('Priority = ' + String(issue.fields.priority.name));
        labels.push({'type': 'priority', 'value': String(issue.fields.priority.name)});

        //log ('status = ' + String(issue.fields.status.name));
        labels.push({'type': 'status', 'value': String(issue.fields.status.name)});

        //log ('project = ' + String(issue.fields.project.name));
        labels.push({'type': 'project', 'value': String(issue.fields.project.name)});

        //log ('updated = ' + String(issue.fields.updated));
        labels.push({'type': 'updated', 'value': String(issue.fields.updated)});

        //log ('reporter name = ' + String(issue.fields.reporter.displayName));
        labels.push({'type': 'reportername', 'value': String(issue.fields.reporter.displayName)});

        //log ('reporter email =  = ' + String(issue.fields.reporter.emailAddress));
        labels.push({'type': 'reporteremail', 'value': String(issue.fields.reporter.emailAddress)});

        //log ('created = ' + String(issue.fields.created));
        labels.push({'type': 'created', 'value': String(issue.fields.created)});

        //log ('summary = ' + String(issue.fields.summary));
        labels.push({'type': 'summary', 'value': String(issue.fields.summary)});

        //log ('description = ' + String(issue.fields.description));
        labels.push({'type': 'description', 'value': String(issue.fields.description)});

        var name = issue.fields.summary;
        if (name.length === 0) {
            name = "Jira issue: "+String(issue.id);
        }
        var severity = 0;
        if (issue.fields.priority && issue.fields.priority.name && issue.fields.priority.name.length > 0 ){
            if (issue.fields.priority.name === 'Highest') {
                severity = 4;
            }
            if (issue.fields.priority.name === 'High') {
                severity = 3;
            }
            if (issue.fields.priority.name === 'Medium') {
                severity = 2;
            }
            if (issue.fields.priority.name === 'Low') {
                severity = 1;
            }
        }

        return {
            "name": name,
            "labels": labels,
            "details": issue.fields.description,
            "severity": severity
        };
    };


    // The command input arg holds the command sent from the user.
    switch (command) {
        // This is the call made when pressing the integration test button.
        case 'test-module':
            var cookies = getCookies();
            return  (typeof cookies !== undefined);
        case 'jira-get-issue':
            var cookies = getCookies();
            var result = http(
                params.url+'rest/api/2/issue/'+args.issueId,
                {
                    Headers: {'Content-Type': ['application/json']},
                    Method: 'GET',
                    Username: params.username,
                    Password: <PASSWORD>,
                    Cookies: cookies,
                },
                params.insecure
            );
            if (result.StatusCode !== 200) {
                throw 'Failed to jira-get-issue, request status code: ' + result.StatusCode + ', body: ' + result.Body;
            }
            var jRes = JSON.parse(result.Body);
            var mdAndContext = generateMDContextGetIssue(jRes);
            md = tblToMd(command, mdAndContext['md'],argToList(args.headers));
            return {Type: entryTypes.note, Contents: jRes, ContentsFormat: formats.json, HumanReadable: md, ReadableContentsFormat: formats.markdown, EntryContext: mdAndContext['context']};
        case 'jira-issue-query':
            var jRes = runQuery(args.query,args.startAt,args.maxResults);
            var issues = dq(jRes,'issues');
            var mdAndContext = generateMDContextGetIssue(issues);
            md = tblToMd(command, mdAndContext['md'], argToList(args.headers));
            return {Type: entryTypes.note, Contents: jRes, ContentsFormat: formats.json, HumanReadable: md, ReadableContentsFormat: formats.markdown, EntryContext:  mdAndContext['context']};
        case 'jira-create-issue':
            var cookies = getCookies();
            var url = params.url+'rest/api/2/issue/';
            var issue = {};
            if (args.issueJson && args.issueJson.length > 0 ){
                issue = JSON.parse(args.issueJson);
            }
            if (!issue.fields) {
                issue.fields= {};
            }
            if (!issue.fields.project) {
                issue.fields.project= {};
            }
            if (!issue.fields.issuetype) {
                issue.fields.issuetype = {};
            }
            if (args.summary && args.summary.length >0 ){
                issue.fields.summary = args.summary;
            }
            if (args.projectKey && args.projectKey.length > 0 ){
                issue.fields.project.key = args.projectKey;
            }
            if (args.projectName && args.projectName.length > 0 ){
                issue.fields.project.name = args.projectName;
            }
            if (args.issueTypeName && args.issueTypeName.length > 0 ){
                issue.fields.issuetype.name = args.issueTypeName;
            }
            if (args.issueTypeId && args.issueTypeId.length > 0 ){
                issue.fields.issuetype.id = args.issueTypeId;
            }
            if (args.description && args.description.length > 0 ){
                issue.fields.description = args.description;
            }
            if (args.labels && args.labels.length > 0 ){
                issue.fields.labels = args.labels.split(",");
            }
            if (args.priorityName && args.priorityName.length > 0 ){
                if (!issue.fields.priority) {
                    issue.fields.priority = {};
                }
                issue.fields.priority.name = args.priorityName;
            }
            if (args.dueDate && args.dueDate.length > 0 ){
                issue.fields.duedate = args.dueDate;
            }
            if (args.assignee && args.assignee.length > 0 ){
                if (!issue.fields.assignee) {
                    issue.fields.assignee = {};
                }
                issue.fields.assignee.name = args.assignee;
            }
            if (args.reporter && args.reporter.length > 0 ){
                if (!issue.fields.reporter) {
                    issue.fields.reporter = {};
                }
                issue.fields.reporter.name = args.reporter;
            }
            var result = http(
                url,
                {
                    Headers: {'Content-Type': ['application/json']},
                    Method: 'POST',
                    Username: params.username,
                    Password: <PASSWORD>,
                    Cookies: cookies,
                    Body: JSON.stringify(issue),
                },
                params.insecure
            );
            if (result.StatusCode !== 201) {
                throw 'Failed to jira-create-issue, request status code: ' + result.StatusCode + ', body: ' + result.Body;
            }
            var jRes = JSON.parse(result.Body);
            var mdAndContext = generateMdContextCreateIssue(jRes);
            var md = tblToMd(command, mdAndContext['md'], "");
            return {Type: entryTypes.note, Contents: jRes, ContentsFormat: formats.json, HumanReadable: md, ReadableContentsFormat: formats.markdown, EntryContext: mdAndContext['context']};
        case 'jira-issue-upload-file':

            var jRes = uploadFile(args.upload, args.issueId);
            var md = generateMdUplosdIssue(jRes);
            md = tblToMd(command, md, "");
            return {Type: entryTypes.note, Contents: jRes, ContentsFormat: formats.json, HumanReadable: md, ReadableContentsFormat: formats.markdown};
        case 'jira-issue-add-comment':
            var cookies = getCookies();
            var url = params.url+'rest/api/2/issue/'+ args.issueId + '/comment';
            var comment = {};
            comment.body = args.comment;
            if (args.visibility && args.visibility.length > 0 ){
                comment.visibility = {};
                comment.visibility.type = 'role';
                comment.visibility.value = args.visibility;
            }
            var result = http(
                url,
                {
                    Headers: {'Content-Type': ['application/json']},
                    Method: 'POST',
                    Username: params.username,
                    Password: <PASSWORD>,
                    Cookies: cookies,
                    Body: JSON.stringify(comment),
                },
                params.insecure
            );
            if (result.StatusCode !== 201) {
                throw 'Failed to jira-issue-add-comment, request status code: ' + result.StatusCode + ', body: ' + result.Body;
            }
            var jRes = JSON.parse(result.Body);
            var md = generateMdCommentOrLinkIssue(jRes)
            md = tblToMd(command, md, "");
            return {Type: entryTypes.note, Contents: jRes, ContentsFormat: formats.json, HumanReadable: md, ReadableContentsFormat: formats.markdown};
        case 'jira-issue-add-link':
            var cookies = getCookies();
            var url = params.url+'rest/api/2/issue/'+ args.issueId + '/remotelink';
            var link = {};
            link.object = {};
            link.object.url = args.url;
            link.object.title = args.title;
            if (args.summary && args.summary.length > 0 ){
                link.summary = args.summary;
            }
            if (args.globalId && args.globalId.length > 0 ){
                link.globalId = args.globalId;
            }
            if (args.relationship && args.relationship.length > 0 ){
                link.relationship = args.relationship;
            }
            if (args.relationship && args.relationship.length > 0 ){
                link.relationship = args.relationship;
            }
            var result = http(
                url,
                {
                    Headers: {'Content-Type': ['application/json']},
                    Method: 'POST',
                    Username: params.username,
                    Password: <PASSWORD>,
                    Cookies: cookies,
                    Body: JSON.stringify(link),
                },
                params.insecure
            );
            if (result.StatusCode !== 201) {
                throw 'Failed to jira-issue-add-comment, request status code: ' + result.StatusCode + ', body: ' + result.Body;
            }
            var jRes = JSON.parse(result.Body);
            var md = generateMdCommentOrLinkIssue(jRes)
            md = tblToMd(command, jRes, "");
            return {Type: entryTypes.note, Contents: jRes, ContentsFormat: formats.json, HumanReadable: md, ReadableContentsFormat: formats.markdown};
        case 'fetch-incidents':
            var lastRun = getLastRun();
            var idOffset = lastRun && lastRun.idOffset ? lastRun.idOffset : params.idOffset;
            var incidents = [];
            var maxResults = 50;
            var query = params.query + ' and id > ' + String(idOffset)
            if (params.fetchByCreated) {
              query = params.query + ' and created>-1m'
            }
            var res = runQuery(query,'',maxResults)
            for (var i = 0; i < res.issues.length; i++) {
                var ticket = res.issues[i];
                idOffset = Math.max(idOffset, ticket.id);
                incidents.push(createIncidentFromTicket(ticket));
            }
            setLastRun({idOffset: idOffset});
            return JSON.stringify(incidents);
        default:
    }
  type: javascript
  commands:
  - name: jira-issue-query
    arguments:
    - name: query
      required: true
      default: true
      description: JQL query string
    - name: startAt
      description: The index of the first issue to return (0-based) - format int
    - name: maxResults
      description: the maximum number of issues to return (defaults to 50). The maximum
        allowable value is dictated by the JIRA property 'jira.search.views.default.max'.
        If you specify a value that is higher than this number, your search results
        will be truncated.
    - name: headers
      description: Headers to display in Human readable format
    outputs:
    - contextPath: Ticket.Id
      description: Id of ticket
    - contextPath: Ticket.Key
      description: Key of ticket
    - contextPath: Ticket.Assignee
      description: User assigned to ticket
    - contextPath: Ticket.Creator
      description: User who created the ticket
    - contextPath: Ticket.Summary
      description: Summary of ticket
    - contextPath: Ticket.Status
      description: Status of ticket
    description: Query Jira issues
  - name: jira-get-issue
    arguments:
    - name: issueId
      required: true
      default: true
      description: Issue id
    - name: headers
      description: Headers to display in Human readable format
    description: Fetch issue from Jira
  - name: jira-create-issue
    arguments:
    - name: issueJson
      description: Issue object in json format
    - name: summary
      required: true
      description: Summary of the issue, a mandatory field
    - name: projectKey
      description: Project key to associate the issue
    - name: issueTypeName
      description: Issue type name, like - Incident
    - name: issueTypeId<commit_msg>Adding new format to jira integration<commit_after>commonfields:
  id: jira
  version: -1
name: jira
display: Jira
category: IT Services
image: data:image/png;base64,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
description: Issue tracking product, developed by Atlassian
detaileddescription: |
  For fetching incidents, please update the query param according to JQL: https://confluence.atlassian.com/jirasoftwarecloud/advanced-searching-764478330.html
  Update there the project you want to fetch from like:  "project = soc AND  status=open".
  This will fetch for first time all tickets in your system (include past) that are in open status and in project soc, after first run, it will create incident only for new tickets,
  If you wish to start in first time from a specific position, use "Issue index to start fetching incidents from" param.
  
  you can also fetch incidents by time (by issues created field) by turning on the  "Use created field to fetch incidents" field, instead of using id's.  
configuration:
- display: Jira URL, in the format https://demisto.atlassian.net/
  name: url
  defaultvalue: ""
  type: 0
  required: true
- display: Username
  name: username
  defaultvalue: ""
  type: 0
  required: true
- display: Password
  name: password
  defaultvalue: ""
  type: 4
  required: true
- display: Insecure
  name: insecure
  defaultvalue: "true"
  type: 8
  required: false
- display: Query for fetching incident in JQL
  name: query
  defaultvalue: status=open
  type: 0
  required: false
- display: Issue index to start fetching incidents from
  name: idOffset
  defaultvalue: "10000"
  type: 0
  required: false
- display: Fetch incidents
  name: isFetch
  defaultvalue: ""
  type: 8
  required: false
- display: Incident type
  name: incidentType
  defaultvalue: ""
  type: 13
  required: false
- display: Use created field to fetch incidents
  name: fetchByCreated
  defaultvalue: ""
  type: 8
  required: false  
script:
  script: |-
    // handle '/' at the end of the url
    if (params.url[params.url.length - 1] != '/') {
        params.url = params.url + '/';
    }

    var getCookies = function() {
        var result = http(
            params.url+'rest/auth/1/session',
            {
                Headers: {'Content-Type': ['application/json']},
                Method: 'POST',
                Username: params.username,
                Password: <PASSWORD>,
                Body: JSON.stringify({'username':params.username,'password':<PASSWORD>}),
            },
            params.insecure
        );
        if (result.StatusCode !== 200 && result.StatusCode !== 201) {
            throw 'Failed to create auth cookie, request status code: ' + result.StatusCode + ', check that username/password are correct';
        }
        return result.Cookies;
    };

    var addQueryParam = function(urlSuffix, paramName, value){
        if (value && value.length > 0){
            urlSuffix = urlSuffix + '&' + paramName + '=' + value;
        }
        return urlSuffix;
    };

    var uploadFile = function(entryId, issueId) {
        var cookies = getCookies();
        var res = httpMultipart(
            params.url+'rest/api/2/issue/' + issueId + '/attachments',
            entryId,
            {
                Method: 'POST',
                Cookies: cookies,
                Username: params.username,
                Password: <PASSWORD>,
                Headers: {'X-Atlassian-Token': ['no-check']},
            },
            {
            },
            params.insecure
        );
        if (res.StatusCode !== 200) {
            return 'Failed to execute request:' + res.StatusCode + ', body: ' + res.Body;
        }
        return JSON.parse(res.Body);
    };

    var runQuery = function(query, startAt, maxResults) {
        var cookies = getCookies();
        var url = params.url+'rest/api/2/search?jql='+encodeURIComponent(query);
        url = addQueryParam(url,'startAt',startAt);
        url = addQueryParam(url,'maxResults',maxResults);
        var result = http(
            url,
            {
                Headers: {'Content-Type': ['application/json']},
                Method: 'GET',
                Username: params.username,
                Password: <PASSWORD>,
                Cookies: cookies,
            },
            params.insecure
        );
        if (result.StatusCode !== 200) {
            throw 'Failed to jira-issue-query, request status code: ' + result.StatusCode + ', body: ' + result.Body;
        }
        return JSON.parse(result.Body);
    };


    var cleanNullFields = function(obj) {
        for(prop in obj){
            if(obj[prop] === null || obj[prop] === undefined || obj[prop] ==="" )
            delete obj[prop];
        }
        return obj;
    }


    var generateMDContextGetIssue = function(data) {
        var getIssueObj = {md: [] , context: {Ticket: []}};
        if(!Array.isArray(data)) {
            data = [data];
        }
        data.forEach(function (element) {
            mdObj ={};
            contextObj = {};

            var id = dq(element, 'id');
            mdObj['id'] = id;
            contextObj['Id'] = id;

            var key = dq(element, 'key');
            mdObj['key'] = key;
            contextObj['Key'] = key;

            var assignee = dq(element, 'fields.assignee.displayName') + "(" + dq(element, 'fields.assignee.emailAddress') + ")";
            mdObj['assignee'] = assignee;
            contextObj['Assignee'] = assignee;

            mdObj['reporter'] = dq(element, 'fields.reporter.displayName') + "(" + dq(element, 'fields.reporter.emailAddress') + ")";

            var creator = dq(element, 'fields.creator.displayName') + "(" + dq(element, 'fields.creator.emailAddress') + ")";
            mdObj['creator'] = creator;
            contextObj['Creator'] = creator;

            var summary = dq(element, 'fields.summary');
            mdObj['summary'] = summary;
            contextObj['Summary'] = summary;

            var status = dq(element, 'fields.status.name')
            mdObj['status'] = status;
            contextObj['Status'] = status;

            mdObj['issueType'] = dq(element, 'fields.issuetype.description');
            mdObj['priority'] = dq(element, 'fields.priority.name');
            mdObj['project'] = dq(element, 'fields.project.name');
            mdObj['labels'] = dq(element, 'fields.labels');
            mdObj['description'] = dq(element, 'fields.description');
            mdObj['duedate'] = dq(element, 'fields.duedate');
            mdObj['ticket_link'] = dq(element, 'self');
            mdObj['creted'] = dq(element, 'fields.created');
            var attachments = dq(element, 'fields.attachment');
            if(Array.isArray(attachments) && attachments.length > 0) {
                var attachmentNames = [];
                attachments.forEach(function (attach) {
                    attachmentNames.push(attach['filename']);
                });
                mdObj['attachment'] = attachmentNames.join();
            }
            getIssueObj['md'].push(mdObj);
            getIssueObj['context'].Ticket.push(contextObj);
        });
        return getIssueObj;
    }

    var generateMdContextCreateIssue = function(data) {
        var createIssueObj = {md: [] , context: {Ticket: []}};
        createIssueObj['md'].push(data);
        var id = dq(data, 'id');
        createIssueObj['context'].Ticket.push({Id: id});
        return createIssueObj;
    }


    var generateMdCommentOrLinkIssue = function(data) {
        var commentOrLinkMd = [];
        if(!Array.isArray(data)) {
            data = [data];
        }
        data.forEach(function (element) {
            mdObj ={};
            mdObj['id'] = dq(element, 'id');
            mdObj['key'] = dq(element, 'updateAuthor.key');
            mdObj['commnet'] = dq(element, 'body');
            mdObj['ticket_link'] = dq(element, 'self');
            commentOrLinkMd.push(mdObj);
        });
        return commentOrLinkMd;
    }

    var generateMdUplosdIssue = function(data) {
        var uploadMd = [];
        if(!Array.isArray(data)) {
            data = [data];
        }
        data.forEach(function (element) {
            mdObj ={};
            mdObj['id'] = dq(element, 'id');
            mdObj['key'] = dq(element, 'updateAuthor.key');
            mdObj['attachment'] = dq(element, 'fields.attachment');
            mdObj['ticket_link'] = dq(element, 'self');
            uploadMd.push(mdObj);
        });
        return uploadMd;
    }


    var createIncidentFromTicket = function(issue) {
        var keys = Object.keys(issue);
        var labels = [];

        labels.push({'type': 'issue', 'value': JSON.stringify(issue)});
        //Send specific issue information only
        //log ('id = ' + String(issue.id));
        labels.push({'type': 'id', 'value': String(issue.id)});

        //log ('lastViewed = ' + String(issue.fields.lastViewed));
        labels.push({'type': 'lastViewed', 'value': String(issue.fields.lastViewed)});

        //log ('Priority = ' + String(issue.fields.priority.name));
        labels.push({'type': 'priority', 'value': String(issue.fields.priority.name)});

        //log ('status = ' + String(issue.fields.status.name));
        labels.push({'type': 'status', 'value': String(issue.fields.status.name)});

        //log ('project = ' + String(issue.fields.project.name));
        labels.push({'type': 'project', 'value': String(issue.fields.project.name)});

        //log ('updated = ' + String(issue.fields.updated));
        labels.push({'type': 'updated', 'value': String(issue.fields.updated)});

        //log ('reporter name = ' + String(issue.fields.reporter.displayName));
        labels.push({'type': 'reportername', 'value': String(issue.fields.reporter.displayName)});

        //log ('reporter email =  = ' + String(issue.fields.reporter.emailAddress));
        labels.push({'type': 'reporteremail', 'value': String(issue.fields.reporter.emailAddress)});

        //log ('created = ' + String(issue.fields.created));
        labels.push({'type': 'created', 'value': String(issue.fields.created)});

        //log ('summary = ' + String(issue.fields.summary));
        labels.push({'type': 'summary', 'value': String(issue.fields.summary)});

        //log ('description = ' + String(issue.fields.description));
        labels.push({'type': 'description', 'value': String(issue.fields.description)});

        var name = issue.fields.summary;
        if (name.length === 0) {
            name = "Jira issue: "+String(issue.id);
        }
        var severity = 0;
        if (issue.fields.priority && issue.fields.priority.name && issue.fields.priority.name.length > 0 ){
            if (issue.fields.priority.name === 'Highest') {
                severity = 4;
            }
            if (issue.fields.priority.name === 'High') {
                severity = 3;
            }
            if (issue.fields.priority.name === 'Medium') {
                severity = 2;
            }
            if (issue.fields.priority.name === 'Low') {
                severity = 1;
            }
        }

        return {
            "name": name,
            "labels": labels,
            "details": issue.fields.description,
            "severity": severity
        };
    };


    // The command input arg holds the command sent from the user.
    switch (command) {
        // This is the call made when pressing the integration test button.
        case 'test-module':
            var cookies = getCookies();
            return  (typeof cookies !== undefined);
        case 'jira-get-issue':
            var cookies = getCookies();
            var result = http(
                params.url+'rest/api/2/issue/'+args.issueId,
                {
                    Headers: {'Content-Type': ['application/json']},
                    Method: 'GET',
                    Username: params.username,
                    Password: <PASSWORD>,
                    Cookies: cookies,
                },
                params.insecure
            );
            if (result.StatusCode !== 200) {
                throw 'Failed to jira-get-issue, request status code: ' + result.StatusCode + ', body: ' + result.Body;
            }
            var jRes = JSON.parse(result.Body);
            var mdAndContext = generateMDContextGetIssue(jRes);
            md = tblToMd(command, mdAndContext['md'],argToList(args.headers));
            return {Type: entryTypes.note, Contents: jRes, ContentsFormat: formats.json, HumanReadable: md, ReadableContentsFormat: formats.markdown, EntryContext: mdAndContext['context']};
        case 'jira-issue-query':
            var jRes = runQuery(args.query,args.startAt,args.maxResults);
            var issues = dq(jRes,'issues');
            var mdAndContext = generateMDContextGetIssue(issues);
            md = tblToMd(command, mdAndContext['md'], argToList(args.headers));
            return {Type: entryTypes.note, Contents: jRes, ContentsFormat: formats.json, HumanReadable: md, ReadableContentsFormat: formats.markdown, EntryContext:  mdAndContext['context']};
        case 'jira-create-issue':
            var cookies = getCookies();
            var url = params.url+'rest/api/2/issue/';
            var issue = {};
            if (args.issueJson && args.issueJson.length > 0 ){
                issue = JSON.parse(args.issueJson);
            }
            if (!issue.fields) {
                issue.fields= {};
            }
            if (!issue.fields.project) {
                issue.fields.project= {};
            }
            if (!issue.fields.issuetype) {
                issue.fields.issuetype = {};
            }
            if (args.summary && args.summary.length >0 ){
                issue.fields.summary = args.summary;
            }
            if (args.projectKey && args.projectKey.length > 0 ){
                issue.fields.project.key = args.projectKey;
            }
            if (args.projectName && args.projectName.length > 0 ){
                issue.fields.project.name = args.projectName;
            }
            if (args.issueTypeName && args.issueTypeName.length > 0 ){
                issue.fields.issuetype.name = args.issueTypeName;
            }
            if (args.issueTypeId && args.issueTypeId.length > 0 ){
                issue.fields.issuetype.id = args.issueTypeId;
            }
            if (args.description && args.description.length > 0 ){
                issue.fields.description = args.description;
            }
            if (args.labels && args.labels.length > 0 ){
                issue.fields.labels = args.labels.split(",");
            }
            if (args.priorityName && args.priorityName.length > 0 ){
                if (!issue.fields.priority) {
                    issue.fields.priority = {};
                }
                issue.fields.priority.name = args.priorityName;
            }
            if (args.dueDate && args.dueDate.length > 0 ){
                issue.fields.duedate = args.dueDate;
            }
            if (args.assignee && args.assignee.length > 0 ){
                if (!issue.fields.assignee) {
                    issue.fields.assignee = {};
                }
                issue.fields.assignee.name = args.assignee;
            }
            if (args.reporter && args.reporter.length > 0 ){
                if (!issue.fields.reporter) {
                    issue.fields.reporter = {};
                }
                issue.fields.reporter.name = args.reporter;
            }
            var result = http(
                url,
                {
                    Headers: {'Content-Type': ['application/json']},
                    Method: 'POST',
                    Username: params.username,
                    Password: <PASSWORD>,
                    Cookies: cookies,
                    Body: JSON.stringify(issue),
                },
                params.insecure
            );
            if (result.StatusCode !== 201) {
                throw 'Failed to jira-create-issue, request status code: ' + result.StatusCode + ', body: ' + result.Body;
            }
            var jRes = JSON.parse(result.Body);
            var mdAndContext = generateMdContextCreateIssue(jRes);
            var md = tblToMd(command, mdAndContext['md'], "");
            return {Type: entryTypes.note, Contents: jRes, ContentsFormat: formats.json, HumanReadable: md, ReadableContentsFormat: formats.markdown, EntryContext: mdAndContext['context']};
        case 'jira-issue-upload-file':

            var jRes = uploadFile(args.upload, args.issueId);
            var md = generateMdUplosdIssue(jRes);
            md = tblToMd(command, md, "");
            return {Type: entryTypes.note, Contents: jRes, ContentsFormat: formats.json, HumanReadable: md, ReadableContentsFormat: formats.markdown};
        case 'jira-issue-add-comment':
            var cookies = getCookies();
            var url = params.url+'rest/api/2/issue/'+ args.issueId + '/comment';
            var comment = {};
            comment.body = args.comment;
            if (args.visibility && args.visibility.length > 0 ){
                comment.visibility = {};
                comment.visibility.type = 'role';
                comment.visibility.value = args.visibility;
            }
            var result = http(
                url,
                {
                    Headers: {'Content-Type': ['application/json']},
                    Method: 'POST',
                    Username: params.username,
                    Password: <PASSWORD>,
                    Cookies: cookies,
                    Body: JSON.stringify(comment),
                },
                params.insecure
            );
            if (result.StatusCode !== 201) {
                throw 'Failed to jira-issue-add-comment, request status code: ' + result.StatusCode + ', body: ' + result.Body;
            }
            var jRes = JSON.parse(result.Body);
            var md = generateMdCommentOrLinkIssue(jRes)
            md = tblToMd(command, md, "");
            return {Type: entryTypes.note, Contents: jRes, ContentsFormat: formats.json, HumanReadable: md, ReadableContentsFormat: formats.markdown};
        case 'jira-issue-add-link':
            var cookies = getCookies();
            var url = params.url+'rest/api/2/issue/'+ args.issueId + '/remotelink';
            var link = {};
            link.object = {};
            link.object.url = args.url;
            link.object.title = args.title;
            if (args.summary && args.summary.length > 0 ){
                link.summary = args.summary;
            }
            if (args.globalId && args.globalId.length > 0 ){
                link.globalId = args.globalId;
            }
            if (args.relationship && args.relationship.length > 0 ){
                link.relationship = args.relationship;
            }
            if (args.relationship && args.relationship.length > 0 ){
                link.relationship = args.relationship;
            }
            var result = http(
                url,
                {
                    Headers: {'Content-Type': ['application/json']},
                    Method: 'POST',
                    Username: params.username,
                    Password: <PASSWORD>,
                    Cookies: cookies,
                    Body: JSON.stringify(link),
                },
                params.insecure
            );
            if (result.StatusCode !== 201) {
                throw 'Failed to jira-issue-add-comment, request status code: ' + result.StatusCode + ', body: ' + result.Body;
            }
            var jRes = JSON.parse(result.Body);
            var md = generateMdCommentOrLinkIssue(jRes)
            md = tblToMd(command, jRes, "");
            return {Type: entryTypes.note, Contents: jRes, ContentsFormat: formats.json, HumanReadable: md, ReadableContentsFormat: formats.markdown};
        case 'fetch-incidents':
            var lastRun = getLastRun();
            var idOffset = lastRun && lastRun.idOffset ? lastRun.idOffset : params.idOffset;
            var incidents = [];
            var maxResults = 50;
            var query = params.query + ' and id > ' + String(idOffset)
            if (params.fetchByCreated) {
              query = params.query + ' and created>-1m'
            }
            var res = runQuery(query,'',maxResults)
            for (var i = 0; i < res.issues.length; i++) {
                var ticket = res.issues[i];
                idOffset = Math.max(idOffset, ticket.id);
                incidents.push(createIncidentFromTicket(ticket));
            }
            setLastRun({idOffset: idOffset});
            return JSON.stringify(incidents);
        default:
    }
  type: javascript
  commands:
  - name: jira-issue-query
    arguments:
    - name: query
      required: true
      default: true
      description: JQL query string
    - name: startAt
      description: The index of the first issue to return (0-based) - format int
    - name: maxResults
      description: the maximum number of issues to return (defaults to 50). The maximum
        allowable value is dictated by the JIRA property 'jira.search.views.default.max'.
        If you specify a value that is higher than this number, your search results
        will be truncated.
    - name: headers
      description: Headers to display in Human readable format
    outputs:
    - contextPath: Ticket.Id
      description: Id of ticket
    - contextPath: Ticket.Key
      description: Key of ticket
    - contextPath: Ticket.Assignee
      description: User assigned to ticket
    - contextPath: Ticket.Creator
      description: User who created the ticket
    - contextPath: Ticket.Summary
      description: Summary of ticket
    - contextPath: Ticket.Status
      description: Status of ticket
    description: Query Jira issues
  - name: jira-get-issue
    arguments:
    - name: issueId
      required: true
      default: true
      description: Issue id
    - name: headers
      description: Headers to display in Human readable format
    outputs:
    - contextPath: Ticket.Id
      description: Id of ticket
    - contextPath: Ticket.Key
      description: Key of ticket
    - contextPath: Ticket.Assignee
      description: User assigned to ticket
    - contextPath: Ticket.Creator
      description: User who created the ticket
    - contextPath: Ticket.Summary
      description: Summary of ticket
    - contextPath: Ticket.Status
      description: Status of ticket
    description: Fetch issue from Jira
  - name: jira-create-issue
    arguments:
    - name: issueJson
      description: Issue object in json format
    - name: summary
      required: true
      description: Summary of the issue, a mandatory field
    - name: projectKey
      description: Project key to associate the issue
    - name: issueTypeName
      description: Issue type name, like - Incident
    - name: issueTypeId
{'fraction_non_alphanumeric': 0.09190238648602687, 'fraction_numerical': 0.05773482228898588, 'mean_word_length': 3.3478126925446703, 'pattern_counts': {'":': 8, '<': 21, '<?xml version=': 0, '>': 63, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6697899', 'n_tokens_mistral': 33006, 'n_tokens_neox': 30557, 'n_words': 2916}