how to add azure devops iteration path option with python api - python

I have an Azure DevOps project with multiple iteration paths:
If I use this Azure Python API (https://github.com/microsoft/azure-devops-python-api) to create a new work item and set /fields/System.IterationPath to have a value that already exists like RTC-ADS\PI28\Sprint 28-3 it will create the work item with no issue.
But if I try to create a work item with an iteration that does not yet exist such as RTC-ADS\PI27 it will fail with an error
ERROR:root:Error creating ADS work item: TF401347: Invalid tree name given for work item -1, field 'System.IterationPath'.
I could create PI27 manually in my Azure Project settings, but is there a way I can use this Azure Python API to create a new iteration value for PI27 by making a POST request or something?
I have found documentation supporting how to do so I believe:
https://learn.microsoft.com/en-us/rest/api/azure/devops/work/iterations/post-team-iteration?view=azure-devops-rest-6.0
But is it possible to add a new iteration value using this API?
https://github.com/microsoft/azure-devops-python-api
Thanks
EDIT
I've been trying to get a POST request working to add a new iteration path:
pat = CONFIG.personal_access_token
authorization = str(base64.b64encode(bytes(':'+pat, 'ascii')), 'ascii')
headers = {
'Accept': 'application/json',
'Authorization': 'Basic '+authorization
}
response = requests.post(
url="https://dev.azure.com/ADSP-Org-A03/RTC-ADS/_apis/work/teamsettings/iterations?api-version=6.0&iteration=apple&startDate=2021-01-01&endDate=2021-01-11",
headers=headers
)
print(response.text)
But this results in an error:
{"$id":"1","innerException":null,"message":"Value cannot be null.\r\nParameter name: iteration","typeName":"System.ArgumentNullException, mscorlib","typeKey":"ArgumentNullException","errorCode":0,"eventId":0}
which i am trying to solve, is my request formatted incorrectly? I cant find a working example online for adding an iteration path to an ADS project

The first approach you've taken should be correct, but I think you're passing the request data incorrectly. It should be something like
pat = CONFIG.personal_access_token
authorization = str(base64.b64encode(bytes(':'+pat, 'ascii')), 'ascii')
iteration_id = "" # add id here
headers = {
'Accept': 'application/json',
'Authorization': 'Basic '+authorization
}
attributes = {"startDate":"2021-01-01", "endDate": "2021-01-11"}
data = {"id": iteration_id, "attributes": attributes}
let url = "https://dev.azure.com/ADSP-Org-A03/RTC-ADS/_apis/work/teamsettings/iterations?api-version=6.0"
response = requests.post(url=url, headers=headers, json=data)
print(response.text)
Alternatively, for the classification nodes approach, the data you're using is incorrect. It should be
data = {
"name":"Wk 18.02 - 18.03",
"attributes": {
"startDate":"8 january 2018 GMT",
"finishDate":"21 january 2018 GMT"
}
}

Related

Is there any way to add components to jira issue using python jira client?

I was working on a project where I have to update jira issue fields like components , epic links,etc.
I am using jira python client(https://pypi.org/project/jira/) to do this task.
ticketObj = authJira.issue('ABC-12345')
print(ticketObj.fields.components)
This is outputing below results
[]
Because components is a array
So If want to update a field in the jissue I have to do the below things
ticketObj.update(components = ['component 1'])
But this method is giving below error
JiraError HTTP 400 url: https://jira.yourdomain.com/rest/api/2/issue/1234567
text: Can not instantiate value of type [simple type, class com.atlassian.jira.rest.api.issue.FieldOperation] from JSON String; no single-String constructor/factory method (through reference chain: com.atlassian.jira.rest.v2.issue.IssueUpdateBean["update"])
response headers = {...}
response text = {"errorMessages":["Can not instantiate value of type [simple type, class com.atlassian.jira.rest.api.issue.FieldOperation] from JSON String; no single-String constructor/factory method (through reference chain: com.atlassian.jira.rest.v2.issue.IssueUpdateBean[\"update\"])"]}
I'm the author of this question, I researched everywhere and I sadly didn't find the method to add components using jira python client,so I created new method to add component which uses rest api provided by .
def addComponentToTicket(self,ticketKey:str,component:str):
payload = json.dumps({"update": {"components": [{
"add": {"name": component}
}], }})
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization":f'Bearer {self.personalAccessToken}',
"X-Atlassian-Token": "no-check",
}
response = requests.put(f'{self.REST_URL}issue/{ticketKey}',
data=payload,
headers=headers,
verify=False)
I got another cleaner method, If We want to update any fields of issue in jira we could use the Jira api method of updating by passing dictionary to update argument.
ticketObj.update(
update=
{
"components": [{
"add": {"name": component},
}],
},
)
I found following working (when updating component in existing issue)
issue.update(notify=False,update={"components": [{"add": {"name": str(NAME),}}],},)
NAME being name of the component (must exist in the project)

Adding multiple CC's using Zenpy

I am working on an automation script to push out emails based on tickets we receive from our CRM.
Is there a way for the collaborator_ids to take multiple emails? I've tried using email_ccs and email_ccs_ids with no luck. Below is what I am currently using to include one CC'd email address.
zenpy_client.tickets.update(Ticket(id=i.id, requester=User(email=roster_email, name=name), collaborator_ids=cc_email))
I've also tried: collaborator_ids=(cc_email, cc_email2)
This will work (even if there are internal notes in the ticket):
# Add CC
url = "https://{sub}.zendesk.com/api/v2/tickets/{id}"
payload = json.dumps({
"ticket": {
"email_ccs": [
{
"user_email": "new#email.com",
"action": "put"
}
]
}
})
headers = {
'Authorization': 'Basic {token}',
'Content-Type': 'application/json'
}
response = requests.request("PUT", url, headers=headers, data=payload)
print(response.text)
You could get the ticket ID from ZenPy like facetoe showed here:
ticket_audit = zenpy_client.tickets.create(Ticket(description='test', subject='test'))
print(ticket_audit.ticket.id) # Ticket ID of last created ticket

how to get access tokens from refresh token? does refresh token expire?

I'm trying to create a python script which takes a (.csv with access tokens and a file) as input and uploads that file to multiple google drives whose access tokens are in that csv
but after sometime access tokens get expired and I have to get them again...just saw there's something called refresh and it refreshes access token
Is it possible to do this from python script, please explain.
Do refresh token expire?
import json
import requests
import pandas as pd
headers = {}
para = {
"name": "update",
}
files = {
'data': ('metadata', json.dumps(para), 'application/json; charset=UTF-8'),
'file': open("./update.txt", "rb")
}
tokens = pd.read_csv('tokens.csv')
for i in tokens.token:
headers={"Authorization": i}
r = requests.post(
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart",
headers=headers,
files=files
)
print(r.text)
In order to be able to get a new access_token programmatically using a refresh_token, you must have set access_type to offline when redirecting the user to Google's OAuth 2.0 server.
If you did that, you can get a new access_token if you do the following POST request to https://oauth2.googleapis.com/token:
POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded
client_id=your_client_id&
client_secret=your_client_secret&
refresh_token=refresh_token&
grant_type=refresh_token
The corresponding response would be something like:
{
"access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
"expires_in": 3920,
"scope": "https://www.googleapis.com/auth/drive",
"token_type": "Bearer"
}
Note:
You can find code snippets for several languages in the reference I provide below, including Python, but considering you are not using the Python library, I think the HTTP/REST snippet I provided might be more useful in your situation.
Reference:
Refreshing an access token (offline access)

How can I fix a parse error when making a post request with python?

request = {
"parents": ["1zaxxxxxxxxxxxxxxxZo"],
"name": selected_name
}
headers = {
"Authorization": "Bearer "+creds.token,
"Accept": "application/json",
"Content-Type": "application/json"
}
data = {
"fileId": file_id,
"request": request,
"fields": "files(id)",
"supportsAllDrives": True,
"ignoreDefaultVisibility": True
}
response = requests.post("https://www.googleapis.com/drive/v3/files/"+file_id+"/copy", data=data, headers=headers)
response = response.json()
I am trying to make a request to copy the file_id to the parent folder listed in my request. I am new to both google drive's api and making post requests, I can't understand what I'm doing wrong. I have been working on this issue for multiple hours now, and I'm getting a error response code 400, Parse Error. From what I have gathered, it means I'm formatting my request improperly. I've been trying different things for a long time now, I can't figure out how to make it properly. If anyone could help me it would be greatly appreciated, or point me to where to look to fix this issue on my own. I've been reading the docs, maybe I've bitten off more then I can chew. Thank you.
I believe your goal and situation as follows.
You want to copy a file on Google Drive using Drive API v3 with requests of python.
You have already had the access token for copying the file using Drive API.
In order to achieve your goal, I would like to propose the following modification.
Modification points:
Please set the values of fields, supportsAllDrives and ignoreDefaultVisibility to the query parameters.
Please modify fields from files(id) to id.
Request body is as follows.
data = {
"parents": ["1zaxxxxxxxxxxxxxxxZo"],
"name": selected_name
}
Please modify data=data to data=json.dumps(data).
When above points are reflected to your script, it becomes as follows.
Modified script:
import json
import requests
file_id = "###" # Please set the source file ID.
selected_name = "###" # Please set the filename.
headers = {
"Authorization": "Bearer "+creds.token,
"Accept": "application/json",
"Content-Type": "application/json"
}
data = {
"parents": ["1zaxxxxxxxxxxxxxxxZo"], # Please set the folder ID.
"name": selected_name
}
params = {
"fields": "id",
"supportsAllDrives": True,
"ignoreDefaultVisibility": True
}
response = requests.post("https://www.googleapis.com/drive/v3/files/"+file_id+"/copy", data=json.dumps(data), params=params, headers=headers)
response = response.json()
print(response)
Result:
When above script is run, the following value is shown.
{'id': '###'}
Note:
This modified script supposes that your access token creds.token can be used for copying the file using Drive API. Please be careful this.
Reference:
Files: copy

get end user tokens for eBay restful in Python

currently I am using eBay Trading API with Python. Thanks to: https://github.com/timotheus/ebaysdk-python
I used https://github.com/luke-dixon/django-ebay-accounts to get tokens for user.
Now, I would like to use Restful API (https://developer.ebay.com/docs#Acc). I don't think I can use tokens I have already. So, I managed thanks to Getting an Ebay OAuth Token get one. But I think I missing something, because during the process I cannot include info for user (name/password), so, for example https://api.ebay.com/sell/fulfillment/v1/order?limit=10 returns:
{
"errors": [{
"errorId": 1100,
"domain": "ACCESS",
"category": "REQUEST",
"message": "Access denied",
"longMessage": "Insufficient permissions to fulfill the request."
}]
}
Any idea how can I get a token for the user?
Just snippet of code to make things more clear:
AppSettings = {
'app_id': EBAY_PRODUCTION_APPID,
'app_secret': EBAY_PRODUCTION_CERTID,
'dev_id': EBAY_PRODUCTION_DEVID,
'ruName': EBAY_PRODUCTION_RU_NAME
}
authHeaderData = AppSettings['app_id'] + ':' + AppSettings['app_secret']
encodedAuthHeader = base64.b64encode(authHeaderData.encode())
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic ".encode() + encodedAuthHeader
}
body = {
"grant_type": "client_credentials",
"redirect_uri": settings.EBAY_PRODUCTION_RU_NAME,
"scope": "https://api.ebay.com/oauth/api_scope"
}
data = urllib.parse.urlencode(body)
tokenURL = "https://api.ebay.com/identity/v1/oauth2/token"
response = requests.post(tokenURL, headers=headers, data=body)
authDict = response.json()
So the request to run I need is:
r = requests.get("https://api.ebay.com/sell/fulfillment/v1/order?limit=10",
headers={"Authorization": "{}".format(authDict['access_token']),
"Content-Type": "application/json",
"X-EBAY-C-MARKETPLACE-ID": "EBAY_UK",
"Accept": "application/json"
})
According to this, I believe you are supposed to use the following authorization header:
headers['Authorization'] = "Bearer " + USER_ACCESS_TOKEN
Where the USER_ACCESS_TOKEN is the massive token generated on this page.
It looks something like this:
'v^1.1#i^1#p^3#f^0#I^3#r^0#t^ ...
...
...
...
... bfxr8BJtphi2M/oo2xpYo2hiMWxmZt4fVzS7qe2tMXUSAAA='
The Authorization you are using is for requests that aren't linked to a specific user account (search results, meta data for items, etc.). To make requests that are for specific users (eg. orders or inventory updates), you have to get their permission via their USER_ACCESS_TOKEN.
If you need help getting the USER_ACCESS_TOKEN let me know and I'll update.
Note that I have been trying to do the same thing that you are doing for about 6 hours now, and still haven't figured it out, so I am not confident in this answer.
Hope this helps. If you do figure it out, you should post an answer so others can too (ie myself xD).
eBay definitely wins the gold metal for worst api docs in the history of api docs...
The API Explore # developer.ebay.com has description of HTTP Headers for each RestFul API. E.G. Fulfillment API - getOrdres:
HTTP Headers
Authorization:Bearer <OAUTH_token>
Accept:application/json
Content-Type:application/json
Sample code:
import requests,json
headers = {
"Authorization": "Bearer Type_Your_Token_here_or_Paste_IF_too_long",
'Accept':'application/json',
'Content-Type':'application/json'
}
EndPoint = "https://api.ebay.com/sell/fulfillment/v1/order?filter=orderfulfillmentstatus:%7BNOT_STARTED|IN_PROGRESS%7D"
response = requests.get(EndPoint,headers = headers)
https://newbedev.com/ebay-oauth-token-and-refresh-tokens has introduced eBay OAuth token much better than eBay.
By the way, "grant_type": "client_credentials" is only valid for clients who can on have one scope. https://api.ebay.com/oauth/api_scope.
A shortcut to get your code run: the refresh token is actually the token you have for standard API, which is valid for 18 months. With a refresh token, you can get token without getting the annoying "authorization code" via user consent.
In short, please use refresh token to get user access token for the restful API.
Hope the above helps.

Categories