From cb6e6074fba285849217cda9e6667ccc3ad68fb7 Mon Sep 17 00:00:00 2001 From: Zimmerberger Markus Date: Wed, 5 Jul 2023 09:17:03 +0200 Subject: [PATCH] Minor enhancements --- .vscode/launch.json | 4 +- ChatGPT-generated.py | 28 +++ JIRA_Epics_from_Confluence.py | 189 ++++++++++++++++ JIRA_SubTasks_byComments.py | 114 ++++++---- Remedy_to_JIRA.py | 5 + Remedy_to_JIRA_wo_Lib.py | 414 ++++++++++++++++++++++++++++++++++ 6 files changed, 703 insertions(+), 51 deletions(-) create mode 100644 ChatGPT-generated.py create mode 100644 JIRA_Epics_from_Confluence.py create mode 100644 Remedy_to_JIRA.py create mode 100644 Remedy_to_JIRA_wo_Lib.py diff --git a/.vscode/launch.json b/.vscode/launch.json index 17e15f2..48d7f3e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,9 @@ "type": "python", "request": "launch", "program": "${file}", - "console": "integratedTerminal" + "console": "integratedTerminal", + "justMyCode": false, + "pythonArgs": ["-Xfrozen_modules=off"] } ] } \ No newline at end of file diff --git a/ChatGPT-generated.py b/ChatGPT-generated.py new file mode 100644 index 0000000..07a83e5 --- /dev/null +++ b/ChatGPT-generated.py @@ -0,0 +1,28 @@ +from jira import JIRA, Issue, exceptions +import logging + +def get_assignee(type, issue): + isBuergerfrontend = False + if type == 'Dev Backend': + return 'reu9001' + elif type == 'Dev Frontend': + for component in issue.fields.components: + isBuergerfrontend = component.name == "Bürgerfrontend" + if isBuergerfrontend: + return 'reu9001' + return 'thh9001' + elif type.startswith('Test-Anpassung'): + return 'ada9001' + +def create_subtask(issue, parent, type, subtask_sp, estimation_remark): + escaped = issue.fields.summary.replace('"', r'\"') + logging.info(f'summary ~ \"{escaped}\"') + + try: + subtask = jira_server.search_issues(f'summary ~ \"{type} {escaped}\"') + if subtask: + raise exceptions.JIRAError + except exceptions.JIRAError: + logging.info(f'Skip creating Sub-Task {type} for {issue} as it already exists') + return + diff --git a/JIRA_Epics_from_Confluence.py b/JIRA_Epics_from_Confluence.py new file mode 100644 index 0000000..f67a8aa --- /dev/null +++ b/JIRA_Epics_from_Confluence.py @@ -0,0 +1,189 @@ +# find comments with estimations out of pre-planning +# zisco 2021-09-30 19:50 + +from types import ClassMethodDescriptorType +from jira import JIRA, Issue, Comment, exceptions +from atlassian import Confluence +from bs4 import BeautifulSoup + +import re +import csv +import xlsxwriter +import logging +import requests +import pandas as pd + +def get_priority(priority): + match priority: + case "GreenMVP": + return "Highest" + case _: + return "Medium" + +def get_assignee(): + return 'raj9002' + + isBuergerfrontend = False + if type == 'Dev Backend': + #return 'rab9001' + return 'reu9001' + elif type == 'Dev Frontend': + # consider verwaltungsfrontend or bürgerfrontend + + existingComponents = [] + for component in issue.fields.components: + if component.name == "Bürgerfrontend": + isBuergerfrontend = True + + if isBuergerfrontend: + return 'reu9001' + else: + return 'thh9001' + + elif type[:14] == 'Test-Anpassung': + return 'ada9001' + +def create_epic(use_case, priority): + escaped = use_case.replace('"','\\"') + + epic = jira_server.search_issues('project = 19404 AND summary ~ \"{}\"'.format(escaped)) + if len(epic) == 0: + issue_type = 'Epic' + assignee = get_assignee() + issue_dict = { + 'project': {'id': 19404}, + 'summary': escaped, + 'description': escaped, + 'issuetype': {'name': issue_type}, + 'priority': {'name': get_priority(priority)}, + 'customfield_10019': escaped, + #'parent': {'key': parent}, + #'labels': issue.fields.labels, + #'customfield_10022' - Story Points + #'timetracking': {'originalEstimate': "{}d".format(subtask_sp)}, + 'assignee': {'name': assignee} + } + try: + new_issue = jira_server.create_issue(fields=issue_dict) + except: + print("Something") + + # consider components + #existingComponents = [] + #for component in issue.fields.components: + # existingComponents.append({"name" : component.name}) + #new_issue.update(fields={"components": existingComponents}) + #new_issue.update(priority={"name": issue.fields.priority.name}) + + logging.info('Created Epic {}'.format(new_issue)) + else: + #update + epic = jira_server.issue(epic[0]) + logging.info('Skip creating Epic {} as it already exists'.format(epic.key)) + +logging.basicConfig(filename='epic_generator.log', + filemode='a', + format='%(asctime)s - %(levelname)s: %(message)s', + level=logging.INFO, + encoding='utf-8') + +jira_host = "https://jira.wien.gv.at/" +confluence_host = "https://confluence.wien.gv.at/" + +jira_pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD" +confluence_pat = "MDI3ODU2NzkzMTAyOsPz47kjJvVdJa1bLpen3W5sB6S5" +sprint = 57 + +headers = JIRA.DEFAULT_OPTIONS["headers"].copy() +headers["Authorization"] = f"Bearer {jira_pat}" + +jira_server = JIRA(server=jira_host, options={"headers": headers}) + +s = requests.Session() +s.headers['Authorization'] = f"Bearer {confluence_pat}" +confluence = Confluence(url=confluence_host, session=s) + +page_id = 215812836 +page = confluence.get_page_by_id(page_id, expand="body.storage", status=None, version=None) +body = page["body"]["storage"]["value"] + +tables_raw = [[[cell.text for cell in row("th") + row("td")] + for row in table("tr")] + for table in BeautifulSoup(body, features="lxml")("table")] + +logging.info('Creating epics out of confluence description') +#xsp = lambda s: s or 0 + +tables_df = [pd.DataFrame(table) for table in tables_raw] +for table_df in tables_df: + for index in table_df.index: + if index >= 11 and index <= 12: + create_epic(use_case=table_df[1][index], + priority=table_df[2][index]) + +issue: Issue +for issue in issues_Jql: + logging.info('Working on {}'.format(issue)) + sp_sum = 0 + + # only Issues with empty (or 0) story-points + sp = 0 + if hasattr(issue.fields, 'customfield_10022'): + sp = xsp(issue.fields.customfield_10022) + + if sp != 0: + logging.info('Ignoring issue {} as there are Story-Points already omitted'.format(issue)) + else: + single_issue = jira_server.issue(issue.key) + comments = single_issue.fields.comment.comments + + # Find all comments made by me on this issue. + for comment in comments: + comment_lines = comment.body.splitlines() + + if len(comment_lines) == 5: + if comment_lines[0][:5] == "Dev B": + for comment_line in comment_lines: + if comment_line != "": + # pos = comment_lines[2].find('NN') + comment_line_parts = comment_line.split(':') + + # if 1. Test* != NN create a sub-task (if not existing) + if len(comment_line_parts) == 2: + if comment_line_parts[1] != u'\xa0': # empty string + if (comment_line_parts[1][-2:] != 'NN') and (comment_line_parts[1][-1:] != '-'): # NN means NotNecessary + subtask_ph = float(comment_line_parts[1]) * 0.5 + if comment_line_parts[0][:15] != "Test-Ausführung": + create_subtask(issue, + issue.key, + comment_line_parts[0], + subtask_ph) + sp_sum += subtask_ph / 0.5 + + # find corresponding sub-task + # issuelinks.inwardIssue + try: + if sp != sp_sum: + issue.update(fields={'customfield_10022': sp_sum}) + logging.info("Estimated story-points changed to Sum(Sub-Tasks story-points): {}".format(sp_sum, sp_sum)) + + except exceptions.JIRAError: + logging.error("Issue {} has no (visible) Story Points-attribute".format(issue.key)) + + finally: + logging.info('Done {}'.format(issue.key)) + + #print('{}: {}, SP: {}'.format(issue.key, issue.fields.summary, sp)) + +#print('Summe {}: {}'.format(assignee, sp_sum)) + +#print(issues_Jql) +# changelog = issues_Jql. +# count = 0 +# for history in changelog.histories: +# for item in history.items: +# if item.field == 'status': +# if item.toString == "Reopened": +# count = count + 1 +# print(count) + diff --git a/JIRA_SubTasks_byComments.py b/JIRA_SubTasks_byComments.py index bc42512..019258b 100644 --- a/JIRA_SubTasks_byComments.py +++ b/JIRA_SubTasks_byComments.py @@ -8,55 +8,60 @@ import csv import xlsxwriter import logging -def get_assignee(type): +def get_assignee(type, issue): + isBuergerfrontend = False if type == 'Dev Backend': - #return 'rab9001' return 'reu9001' elif type == 'Dev Frontend': - # consider verwaltungsfrontend or bürgerfrontend + for component in issue.fields.components: + isBuergerfrontend = component.name == "Bürgerfrontend" + if isBuergerfrontend: + return 'reu9001' return 'thh9001' - # return 'reu9001' - elif type[:14] == 'Test-Anpassung': + elif type.startswith('Test-Anpassung'): return 'ada9001' -def create_subtask(issue, parent, type, subtask_sp): - escaped = issue.fields.summary.replace('"','\\"') - print('summary ~ \"{}\"'.format(escaped)) - - subtask = jira_server.search_issues('summary ~ \"{} {}\"'.format(type, escaped)) - if len(subtask) == 0: - #right = (comment_line.find(':')+2)-len(comment_line) - #subtask_sp = float(comment_line[right:]) - - # issuetype of testcase-creation/modification should be 'Test' - # if type == 'Test-Anpassung': - issue_type = 'Sub-task' +def create_subtask(issue, parent, type, subtask_sp, estimation_remark): + escaped = issue.fields.summary.replace('"', r'\"') + logging.info(f'summary ~ \"{escaped}\"') - assignee = get_assignee(type) - issue_dict = { - 'project': {'id': 12501}, - 'summary': "[{}] {}".format(type, escaped), - 'description': issue.fields.description, - 'issuetype': {'name': issue_type}, - 'priority': {'name': issue.fields.priority.name}, - 'parent': {'key': parent}, - 'labels': issue.fields.labels, - #'customfield_10022' - Story Points - 'timetracking': {'originalEstimate': "{}d".format(subtask_sp)}, - 'assignee': {'name': assignee} - } - new_issue = jira_server.create_issue(fields=issue_dict) + try: + subtask = jira_server.search_issues(f'summary ~ \"{type} {escaped}\"') + if subtask: + raise exceptions.JIRAError + except exceptions.JIRAError: + logging.info(f'Skip creating Sub-Task {type} for {issue} as it already exists') + return - # consider components - existingComponents = [] - for component in issue.fields.components: - existingComponents.append({"name" : component.name}) - new_issue.update(fields={"components": existingComponents}) - #new_issue.update(priority={"name": issue.fields.priority.name}) + issue_type = 'Sub-task' - logging.info('Created Sub-Task {}'.format(new_issue)) - else: - logging.info('Skip creating Sub-Task {} for {} as it already exists'.format(type, issue)) + assignee = get_assignee(type, issue) + description = 's. Story' + if estimation_remark != "": + description += "\nEstimation remark: {}".format(estimation_remark) + + issue_dict = { + 'project': {'id': issue.fields.project.id}, + 'summary': "[{}] {}".format(type, escaped), + 'description': description, # issue.fields.description, + 'issuetype': {'name': issue_type}, + 'priority': {'name': issue.fields.priority.name}, + 'parent': {'key': parent}, + 'labels': issue.fields.labels, + #'customfield_10022' - Story Points + 'timetracking': {'originalEstimate': "{}d".format(subtask_sp)}, + 'assignee': {'name': assignee} + } + new_issue = jira_server.create_issue(fields=issue_dict) + + # consider components + existingComponents = [] + for component in issue.fields.components: + existingComponents.append({"name" : component.name}) + new_issue.update(fields={"components": existingComponents}) + #new_issue.update(priority={"name": issue.fields.priority.name}) + + logging.info('Created Sub-Task {}'.format(new_issue)) logging.basicConfig(filename='sub_task_generator.log', filemode='a', @@ -66,15 +71,15 @@ logging.basicConfig(filename='sub_task_generator.log', host = "https://jira.wien.gv.at/" pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD" -sprint = 46 +sprint = 4 headers = JIRA.DEFAULT_OPTIONS["headers"].copy() headers["Authorization"] = f"Bearer {pat}" jira_server = JIRA(server=host, options={"headers": headers}) # use filter or single issue -issues_Jql = jira_server.search_issues('filter=20406') #, expand='changelog') -#issues_Jql = jira_server.search_issues('key in (WRGWR-1558)') #, expand='changelog') +issues_Jql = jira_server.search_issues('filter=22140') #, expand='changelog') +#issues_Jql = jira_server.search_issues('key in (DKARB-34)') #, expand='changelog') #issues_Jql = jira_server.search_issues('labels in (Refinement11012022) AND type not in (Bug) AND status not in (Done) and ("Story Points" is EMPTY or "Story Points" = 0)') #, expand='changelog') logging.info('Creating sub-tasks out of estimation of pre-planning sprint {}'.format(sprint)) @@ -110,20 +115,29 @@ for issue in issues_Jql: # if 1. Test* != NN create a sub-task (if not existing) if len(comment_line_parts) == 2: if comment_line_parts[1] != u'\xa0': # empty string - if comment_line_parts[1][-2:] != 'NN': # NN means NotNecessary - subtask_ph = float(comment_line_parts[1]) * 0.5 + if (comment_line_parts[1][-2:] != 'NN') and (comment_line_parts[1][-1:] != '-'): # NN means NotNecessary + comment_line_sub_parts = comment_line_parts[1].split(' (') + if len(comment_line_sub_parts)>1: + subtask_ph = float(comment_line_sub_parts[0]) * 0.5 + estimation_remark = comment_line_sub_parts[1] + else: + subtask_ph = float(comment_line_parts[1]) * 0.5 + estimation_remark = "" + if comment_line_parts[0][:15] != "Test-Ausführung": create_subtask(issue, - issue.key, - comment_line_parts[0], - subtask_ph) + issue.key, + comment_line_parts[0], + subtask_ph, + estimation_remark) sp_sum += subtask_ph / 0.5 # find corresponding sub-task # issuelinks.inwardIssue try: - issue.update(fields={'customfield_10022': sp_sum}) - logging.info("Estimated story-points changed to Sum(Sub-Tasks story-points): {}".format(sp_sum, sp_sum)) + if sp != sp_sum: + issue.update(fields={'customfield_10022': sp_sum}) + logging.info("Estimated story-points changed to Sum(Sub-Tasks story-points): {}".format(sp_sum, sp_sum)) except exceptions.JIRAError: logging.error("Issue {} has no (visible) Story Points-attribute".format(issue.key)) diff --git a/Remedy_to_JIRA.py b/Remedy_to_JIRA.py new file mode 100644 index 0000000..fe25366 --- /dev/null +++ b/Remedy_to_JIRA.py @@ -0,0 +1,5 @@ +from remedy_py.RemedyAPIClient import RemedyClient + +client = RemedyClient("smartitm01-prod.wienkav.at/", "zim9003", "3S1punk08_111$", port=None, verify=False) + +print(client) \ No newline at end of file diff --git a/Remedy_to_JIRA_wo_Lib.py b/Remedy_to_JIRA_wo_Lib.py new file mode 100644 index 0000000..969dea4 --- /dev/null +++ b/Remedy_to_JIRA_wo_Lib.py @@ -0,0 +1,414 @@ +#!/usr/bin/env python +# coding=utf-8 +# Created by: Brent Goodman +# Date: April 07, 2018 +# Comments: Uses the Python Requests library to do REST API calls to v9 ARSystem Enviornments +# Alot of the information is hard-coded, but easy to see how to accomodate other values +# etc. All the functions have been tested and work in my new enviornment. All the code +# makes use of the "AP-Sample:Restaurant" form for testing. The 'params=' has some +# catches that need to be watched out for. I have documented comments through out. +# Very limited error checking has been implemented in this version of the code. +# Note that C# is my goto language. I only use python for development work on +# micro-controllers, so the code I provide may not be the most clean/effecive way +# of doing things, but it does get the results needed. + +import json +import requests +import datetime +import time + +requests.packages.urllib3.disable_warnings() + +# Method: GET, POST, PUT, DELET +# URL: http://<>/api +# Authentication: Basic HTTP, OAuth, none +# Custom Headers: Content-Type: application/json +# Request Body: + +# Response Status Codes: 200 OK, 201 Created, 500 Internal Error + +# Way to find fields that can contain data +# select * from field where schemaid = (select schemaid from arschema where name ='Your Form Name') and foption <=3 order by fieldid; + +# Setup the server name to be used by all the URL's +bg_ServerName = "smartitm01-prod.wienkav.at/smartit/app" +bg_UserID = "zim9003" +bg_Password = "3S1punk08_111$" + + +def doLogin(): + myToken = "" + bgReturnVal = -1 + + url = 'https://' + bg_ServerName + '/api/jwt/login' + + payload = {'username': bg_UserID, 'password': bg_Password} + headers = {'content-type': 'application/x-www-form-urlencoded'} + + r = requests.post(url, data=payload, headers=headers, verify=False) + + if r.status_code == 200: + myToken = r.text + bgReturnVal = 1 + else: + print("Failure...") + print("Status Code: " + str(r.status_code)) + bgReturnVal = -1 + + myToken = r.text + return(bgReturnVal, myToken) + +def doLogout(bg_Token): + bgTokenType = 'AR-JWT' + myURL = 'https://' + bg_ServerName + '/api/jwt/logout' + myHeaders = {'Authorization': bgTokenType + ' ' + bg_Token} + myR = requests.post(myURL, headers=myHeaders, verify=False) + print("") + print("Logged out with a status of: {}".format(myR.status_code)) + +# Pull all data back from form +def doPullData(bg_FormName, bg_Token): + bgTokenType = 'AR-JWT' + myURL = 'https://' + bg_ServerName + '/api/arsys/v1/entry/' + bg_FormName + myHeaders = {'Authorization': bgTokenType + ' ' + bg_Token} + + # Pull back all data in the form + myR = requests.get(url = myURL, headers = myHeaders, verify=False) + + print("URL Used:") + print(myR.url) + print("") + + if(myR.status_code != 200): + print('Status code:', myR.status_code) + print('Headers:', myR.headers) + print('Error Response:', myR.json()) + return(-1) + + bgData = myR.json() + + # bgData contains a dictionay of two items: + # entries + # _links + + # Copy the dictionary 'entries' into variable + avar = bgData['entries'] + + # len(avar) will tell us the number of returned records + + # Loop the number of records returned + for x in range(len(avar)): + # Grab the dictionary of 'values' + myVals = avar[x]['values'] + # Print out the key/value pair + for keys,values in myVals.items(): + print('{} => {}'.format(keys,values)) + print("") + + return(len(avar)) + +# Pull all records back from form, but limited field list +def doPullData_LimitedFields(bg_FormName, bg_Token): + bgTokenType = 'AR-JWT' + myURL = 'https://' + bg_ServerName + '/api/arsys/v1/entry/' + bg_FormName + myHeaders = {'Authorization': bgTokenType + ' ' + bg_Token} + + # Setup the list of fields only to return + # *** BMC REST API unable to handle this and I consider it a defect on their side + # Their documentation is incorrect + #fieldList_params = {'fields': "values(Restaurant,Status)"} + + # Note that BMC documentation is wrong on this. The REST API on their + # end is not able to decode the FIELDS, LIMIT, or SORT. + # These must be appeneded to the URL. Only the Query can be urlencoded + # and put into the 'params=' variable + # *** Looks like everything inside of the ( ) needs to be encoded if any non + # URL safe characters are used. Still not able to push this into the 'params=' + # variable as the "values()" also gets encoded. The brackes must not be encoded + # Javascript/Java may handle the pramameters a little differently. + bgFields = "Restaurant,Status" + bgTmp = myURL + "?fields=values(" + bgFields + ")" + + # Setup the qualfication. This automatically gets encoded via the 'params=' variable + bgQuery = "'Restaurant' LIKE \"Test%\" AND 'Status' = \"Proposed\"" + + # Setup the search parameter to pass + search_params = {'q': bgQuery} + + # Pull back all data in the form (The 'params=' will automcatially encode its contents) + #myR = requests.get(url = myURL, headers = myHeaders, params=fieldList_params, verify=False) + #myR = requests.get(url = myURL, headers = myHeaders, verify=False) + + # Using a modified version of the URL + Fields restriction + myR = requests.get(url = bgTmp, headers = myHeaders, params=search_params, verify=False) + + print("URL Used:") + print(myR.url) + print("") + + if(myR.status_code != 200): + print('Status code:', myR.status_code) + print('Headers:', myR.headers) + print('Error Response:', myR.json()) + return(-1) + + bgData = myR.json() + + #print(bgData) + # bgData contains a dictionay of two items: + # entries + # _links + + # Copy the dictionary 'entries' into variable + avar = bgData['entries'] + + # len(avar) will tell us the number of returned records + + # Loop the number of records returned + for x in range(len(avar)): + # Grab the dictionary of 'values' + myVals = avar[x]['values'] + # Print out the key/value pair + for keys,values in myVals.items(): + print('{} => {}'.format(keys,values)) + print("") + + return(len(avar)) + +def doPullSearchData(bg_FormName, bg_Token): + bgTokenType = 'AR-JWT' + myHeaders = {'Authorization': bgTokenType + ' ' + bg_Token} + myURL = 'https://' + bg_ServerName + '/api/arsys/v1/entry/' + bg_FormName + + # Enter in your search criteria as you would in the Mid-tier advanced search + # Dont forget to escape out your quotes... + #bgQuery = "'Restaurant' = \"Test Snack Hut\"" + #bgQuery = "'Restaurant' LIKE \"Test%\"" + bgQuery = "'Restaurant' LIKE \"Test%\" AND 'Status' = \"Proposed\"" + + # Setup the search parameter to pass + search_params = {'q': bgQuery} + + myR = requests.get(url=myURL, headers=myHeaders, verify=False, params=search_params) + + print("URL Used:") + print(myR.url) + print("") + + if(myR.status_code != 200): + print('Status code:', myR.status_code) + print('Headers:', myR.headers) + print('Error Response:', myR.json()) + return(-1) + + bgData = myR.json() + + # Copy the dictionary 'entries' into variable + avar = bgData['entries'] + + # len(avar) will tell us the number of returned records + + # Loop the number of records returned + for x in range(len(avar)): + # Grab the dictionary of 'values' + myVals = avar[x]['values'] + # Print out the key/value pair + for keys,values in myVals.items(): + print('{} => {}'.format(keys,values)) + print("") + + return(len(avar)) + +# Pull all data back from form +def doPullSingleRequestIDData(bg_FormName, bg_RequestID, bg_Token): + bgTokenType = 'AR-JWT' + myURL = 'https://' + bg_ServerName + '/api/arsys/v1/entry/' + bg_FormName + '/' + bg_RequestID + myHeaders = {'Authorization': bgTokenType + ' ' + bg_Token} + + # Pull back all data in the form + myR = requests.get(url = myURL, headers = myHeaders, verify=False) + + print("URL Used:") + print(myR.url) + print("") + + if(myR.status_code != 200): + print('Status code:', myR.status_code) + print('Headers:', myR.headers) + print('Error Response:', myR.json()) + return(-1) + + bgData = myR.json() + + # bgData contains a dictionay of two items: + # entries + # _links + + #print(bgData) + + # Copy the dictionary 'entries' into variable + avar = bgData['values'] + + # Print out the key/value pair + for keys,values in avar.items(): + print('{} => {}'.format(keys,values)) + + return(len(avar)) + + +# Create a record in form +def doCreateRecord(bg_FormName, bg_Token): + bgTokenType = 'AR-JWT' + myURL = 'https://' + bg_ServerName + '/api/arsys/v1/entry/' + bg_FormName + myHeaders = {'Authorization': bgTokenType + ' ' + bg_Token, 'Content-Type': 'application/json'} + + # Setting the data= like this will not work. Must be in the raw JSON format + #payload = {'Restaurant':'Test Cheese House','Status':'Active','Average Cost/Person':12.99,'Assigned To':'Bob'} + + # Format of the data= information must use the following template: + # { + # "values":{ + # "Restaurant":"Test MacEnCheese", <-- Start of the fields list to set + # "Status":"Active", + # "Average Cost/Person":2.99, + # "Assigned To":"Bob" <-- End of the fields list to set + # } + # } + payload = '{ \"values\":{\"Restaurant\":\"Test Pizza World\",\"Status\":\"Active\",\"Average Cost/Person\":2.99,\"Assigned To\":\"Bob\"} }' + + # Pull back all data in the form + myR = requests.post(url = myURL, data=payload, headers = myHeaders, verify=False) + + if(myR.status_code != 201): + print('Status code:', myR.status_code) + print('Headers:', myR.headers) + print('Error Response:', myR.json()) + return(-1) + + print("URL to new record:") + print(myR.headers['location']) + print("") + + return(1) + +# Modify an Entry +def doModifySingleRequestIDData(bg_FormName, bg_RequestID, bg_Token): + bgTokenType = 'AR-JWT' + myURL = 'https://' + bg_ServerName + '/api/arsys/v1/entry/' + bg_FormName + '/' + bg_RequestID + myHeaders = {'Authorization': bgTokenType + ' ' + bg_Token, 'Content-Type':'application/json'} + + payload = '{ \"values\":{\"Status\":\"Inactive\",\"Average Cost/Person\":3.99,\"Assigned To\":\"Rick\"} }' + # Pull back all data in the form + myR = requests.put(url = myURL, headers = myHeaders, data=payload, verify=False) + + print("URL Used:") + print(myR.url) + print("") + print("Status of Update: {}".format(myR.status_code)) + + # 204 = sucessful updateTime + # 412 = unmodified (same data was pushed) + if(myR.status_code != 204): + if(myR.status_code != 412): + # 403 = Forbidden + # 404 = Form does not exist + print('Status code:', myR.status_code) + print("") + print('Headers:', myR.headers) + print("") + print('Error Response:', myR.json()) + return(-1) + + + +def getFormDefinition(bg_FormName, bg_Token): + bgTokenType = 'AR-JWT' + myURL = 'https://' + bg_ServerName + '/api/arsys/v1/entry/' + bg_FormName + myHeaders = {'Authorization': bgTokenType + ' ' + bg_Token} + + myR = requests.options(url = myURL, headers = myHeaders, verify=False) + + print("URL Used:") + print(myR.url) + print("") + print("Status of call: {}".format(myR.status_code)) + + bgData = myR.json() + + # Print the raw data returned + #print(bgData) + + # Drill down and only pull out the field information + avar = bgData['properties']['values']['properties'] + + # Print the new raw data + #print(avar) + + print("") + print("-----Key Value pairs-----") + print("") + + # Loop through all the fields returned + for key in sorted(avar.keys()): + print("Key: {}".format(key)) + + # Pull out a field to look at + tmp = avar[key] + + # Print out the 'type' keys data. Exists for all fields + print("Type: {}".format(tmp['type'])) + + # If the key exists, print it out + if 'maxLength' in tmp: + print("Length: {}".format(tmp['maxLength'])) + + if 'format' in tmp: + print("Format: {}".format(tmp['format'])) + + if 'required' in tmp: + print("Required: {}".format(tmp['required'])) + + print("") + + print("") + print("-----------------------") + print("") + + +def main(): + # Login and get token + bgReturnVal, bgToken = doLogin() + + # Only continue if we logged in successfully + if bgReturnVal == 1: + + # Pull all records + #bgResult = doPullData("AP-Sample:Restaurant", bgToken) + #if(bgResult == -1): + # print("An error occured...") + #else: + # print("Found {} record(s) in our last query".format(bgResult)) + + # Pull all records back, but only certain fields + #bgResult = doPullData_LimitedFields("AP-Sample:Restaurant", bgToken) + + # Pull records based on hard coded query + #bgResult = doPullSearchData("AP-Sample:Restaurant", bgToken) + + # Pull record back based on its RequestID. This is a standard format + #doPullSingleRequestIDData("AP-Sample:Restaurant", "000000000000105", bgToken) + + # Create a new recodrs in the form (hard coded values used) + #bgResult = doCreateRecord("AP-Sample:Restaurant", bgToken) + + # Modify the record based on its RequestID. This is a standard format + #doModifySingleRequestIDData("AP-Sample:Restaurant", "000000000000105", bgToken) + + # Get definitions of all the fields on form + getFormDefinition("AP-Sample:Restaurant", bgToken) + + + # Logout + doLogout(bgToken) + +main()