How can I use TFS WebApi to remove a workitemlink - tfs

I am using Microsoft.TeamFoundation.WorkItemTracking.WebApi and trying to add and remove a workitemlink from an item.
I am calling
workItemTrackingHttpClient.UpdateWorkItemAsync(jsonPatchDocument, Id);
and my JsonPatchDocument looks like this.
[
{
"op": 1,
"Path": "/relations/-",
"From": null,
"Value": {
"Rel": "System.LinkTypes.Dependency-Forward",
"Url": "https://[server]/tfs/DefaultCollection/_apis/wit/workItems/[id]"
}
}
]
When I use "op": 0 to update (add) it works correctly but I cannot work out the correct form for remove.
I get an error similar to
VssServiceException
Remove does not support insert.
Microsoft.VisualStudio.Services.WebApi
-2146232832
Anyone have any ideas please.

To remove a link, the JsonPatchDocument is not like the insert, it is necessary to provide "value".
It is like:
[
{
"op": "test",
"path": "/rev",
"value": 3
},
{
"op": "remove",
"path": "/relations/0"
}
]
To remove a link, you need to point which link to be removed by using "relations/Id". The Id is started from 0.
For more induction, please refer to the official document.

Related

Using LogicApp to slice an array on indices

I'm trying to achieve something in LogicApp which I think should be quite easy to achieve, but I'm not managing it.
Say I have a variable from a previous step: 'https://sharepoint/sites/test-site/Documents/somereport.pdf'. From this string, I need to simply create two variables, the first one containing 'https://sharepoint/sites/test-site', the second one containing 'Documents/somereport.pdf'. Both to be used in subsequent steps.
To try and achieve this I try to use the following expressions:
join(slice(split(triggerBody()?['Title'], '/'), 0, 5), '/')
join(slice(split(triggerBody()?['Title'], '/'), 5), '/')
However, I get an error: 'The template language function 'slice' expects its first parameter to be of type string. The provided value is of type 'Array'..
This since the split results in an array. I've now learned that 'slice' is meant for strings, but is there any similar functionality for an array type? Or is there any other (simple) way to achieve this? This seems like it should be basic functionality but I cannot figure it out.
This can be achieved through few ways. If you are trying to use a functionality taking the result as array type then you can use something like below expression.
1. join(take(split(outputs('Compose')?['Title'][0], '/'), 5),'/')
2. join(take(skip(split(outputs('Compose')?['Title'][0], '/'),5), length(split(outputs('Compose')?['Title'][0], '/'))),'/')
However, As an alternative, below is another expression that satisfies your requirement if you are trying to use a functionality taking the result as string type.
1. slice(outputs('Compose')?['Title'][0],0,nthIndexOf(outputs('Compose')?['Title'][0],'/',5))
2. slice(outputs('Compose')?['Title'][0],add(nthIndexOf(outputs('Compose')?['Title'][0],'/',5),1),length(outputs('Compose')?['Title'][0]))
Below is my logic app
RESULTS:
Below is the code-view of my logic app
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Compose": {
"inputs": {
"Title": [
"https://sharepoint/sites/test-site/Documents/somereport.pdf"
],
"age": 30,
"name": "John"
},
"runAfter": {},
"type": "Compose"
},
"array_type_-_first_part": {
"inputs": "#join(take(split(outputs('Compose')?['Title'][0], '/'), 5),'/')",
"runAfter": {
"string_type__second_part": [
"Succeeded"
]
},
"type": "Compose"
},
"array_type_-_second_part": {
"inputs": "#join(take(skip(split(outputs('Compose')?['Title'][0], '/'),5), length(split(outputs('Compose')?['Title'][0], '/'))),'/')",
"runAfter": {
"array_type_-_first_part": [
"Succeeded"
]
},
"type": "Compose"
},
"string_type_-_first_part": {
"inputs": "#slice(outputs('Compose')?['Title'][0],0,nthIndexOf(outputs('Compose')?['Title'][0],'/',5))",
"runAfter": {
"Compose": [
"Succeeded"
]
},
"type": "Compose"
},
"string_type__second_part": {
"inputs": "#slice(outputs('Compose')?['Title'][0],add(nthIndexOf(outputs('Compose')?['Title'][0],'/',5),1),length(outputs('Compose')?['Title'][0]))",
"runAfter": {
"string_type_-_first_part": [
"Succeeded"
]
},
"type": "Compose"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {},
"triggers": {
"manual": {
"inputs": {
"schema": {}
},
"kind": "Http",
"type": "Request"
}
}
},
"parameters": {}
}

Slack API invalid_block

I'm building a simple slack bot and I am playing with the checkboxes element.
When I return the following from my API in a JSON response to a slash-command I get an error failed with the error "invalid_blocks", however, when I put this in the block-kit-builder it works perfectly (including "sending to slack" button)
Any ideas why this is failing when I run my slash command - and is it possible to see more detailed error messages from slack?
{
"blocks": [
{
"elements": [
{
"style": "primary",
"text": {
"emoji": true,
"text": "Create new TODO list",
"type": "plain_text"
},
"type": "button",
"value": "value"
},
{
"style": "primary",
"text": {
"emoji": true,
"text": "Help",
"type": "plain_text"
},
"type": "button",
"value": "value"
}
],
"type": "actions"
},
{
"text": {
"text": "Today",
"type": "mrkdwn"
},
"type": "section"
},
{
"elements": [
{
"initial_options": [
{
"text": {
"text": "Get Into the garden",
"type": "mrkdwn"
},
"value": "foo"
}
],
"options": [
{
"text": {
"text": "Get Into the garden",
"type": "mrkdwn"
},
"value": "foo"
}
],
"type": "checkboxes"
},
{
"style": "primary",
"text": {
"emoji": true,
"text": "Add new Task",
"type": "plain_text"
},
"type": "button",
"value": "value"
}
],
"type": "actions"
}
],
"type": "home"
}
I am using the Slack Web API. I was getting the similar error. After a lot of looking around, here's how I solved it.
import json
blocks = [{...}]
payload = {
"blocks": json.dumps(blocks)
}
You will then send this payload.
in the api, the "blocks" parameter need to be string type. Did you convert it to string or you use it as a JSON ?
https://api.slack.com/methods/chat.postMessage
In the Block Kit Builder, the data is a JSON with a blocks key.
In the Slack API, the blocks param is only the list of JSON objects.
blocks = [
{
"text": {
"text": "Its the list of your blocks",
"type": "mrkdwn"
},
"type": "section"
}
]
text = 'Alternative data in text'
client.chat_postMessage(channel=channel_id, blocks=blocks, text=text)
Another cause of this problem seems to be too many blocks being returned. I can't find any documentation about this whatsoever, but personal experience seems to indicate about 20 blocks is the maximum.
An alternative is to return fewer blocks, with paging actions -- paging works well with the "replace" message so that the content being paged through does not result in many separate messages.
It appears that not all valid elements in block kit tool can be posted as a message, despite the fact that message preview works fine in the Block Tool.
In my case, the code failed when I included an input block and passed when i removed it. The input block was generated by the Block Kit tool.
{
"type": "input",
"element": {
"type": "plain_text_input",
"action_id": "plain_text_input-action"
},
"label": {
"type": "plain_text",
"text": "Feedback",
"emoji": true
}
}
The error was
{'ok': False, 'error': 'invalid_blocks'}
Also, although the documentation for python says you need to urlEncode the JSON-based array, there is no example, and it is incorrect. https://api.slack.com/methods/chat.postMessage
You can see on line 29 in the SDK test code below that blocks= takes a regular list of dicts not a string.
https://github.com/slackapi/python-slack-sdk/blob/c9dc6aa0907a72c16cf36aa15e7e80031a9fdce2/integration_tests/samples/basic_usage/sending_a_message.py

Graph Pagination in Logic Apps

I'm trying to fetch all users from a specific group via an HTTP connector, a registered app, and Microsoft Graph.
The registered app has Directory.Read.All permissions.
My idea is that I'm calling the nextLink as long as it's there while appending all of the fetched users' userPrincipalName to an array eventually filling the array with all users of the group.
My Logic App looks like this:
Unfortunately, I'm just 1 reputation short of posting images, please forgive. The 3 links should provide an overview of the structure of my app.
First, nextLink is initialized to the first Graph API endpoint. This variable is set to the current nextLink through each iteration of the until loop.
Second, For the purpose of this exercise, I only get the top 5. I know there are only 9 users:
Lastly, I call the union method on the "users" array that I initialized earlier and the "value" array from the HTTP get method, to get one single array consisting of all users:
The issue is that the HTTP action always returns the same top 5 users. I've checked that the nextLink provided in the first HTTP GET call to Graph, is correct by copying it from the Runs history and pasting it into Microsoft Graph Explorer and there the next 4 users are correctly returned.
I also made sure that, for each iteration in the until loop, I call the Graph API with the nextLink from the previous iteration as expected.
The nextLink returned inside of the Logic App is exactly the same when I test it in Graph Explorer, but the same nextLink returns 2 different results when called from Graph Explorer and inside my Logic App.
Why is the result always the same top 5 users and not the next 4 users as expected?
If not sure about the reason why you will get this issue, but based on your requirement, I did a sample below:
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Initialize_variable": {
"inputs": {
"variables": [
{
"name": "GetGroupUrl",
"type": "string",
"value": "https://graph.microsoft.com/v1.0/groups/<your group id>/members?$select=userPrincipalName&$top=5"
}
]
},
"runAfter": {},
"type": "InitializeVariable"
},
"Initialize_variable_2": {
"inputs": {
"variables": [
{
"name": "users",
"type": "array"
}
]
},
"runAfter": {
"Initialize_variable": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Until": {
"actions": {
"Compose": {
"inputs": "#union(variables('users'),body('HTTP')['value'])",
"runAfter": {
"HTTP": [
"Succeeded"
]
},
"type": "Compose"
},
"HTTP": {
"inputs": {
"authentication": {
"audience": "https://graph.microsoft.com",
"clientId": "<app id>",
"secret": "<app secret>",
"tenant": "<your secret>",
"type": "ActiveDirectoryOAuth"
},
"method": "GET",
"uri": "#variables('GetGroupUrl')"
},
"runAfter": {},
"type": "Http"
},
"Set_variable": {
"inputs": {
"name": "GetGroupUrl",
"value": "#{if(equals(body('HTTP')?['#odata.nextLink'], null),null,body('HTTP')['#odata.nextLink'])}"
},
"runAfter": {
"Compose": [
"Succeeded"
]
},
"type": "SetVariable"
}
},
"expression": "#equals(variables('GetGroupUrl'), '')",
"limit": {
"count": 60,
"timeout": "PT1H"
},
"runAfter": {
"Initialize_variable_2": [
"Succeeded"
]
},
"type": "Until"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"manual": {
"inputs": {
"method": "GET",
"schema": {
"properties": {
"text": {
"type": "string"
}
},
"type": "object"
}
},
"kind": "Http",
"type": "Request"
}
}
},
"parameters": {}
}
You can just replace the params with your own and paste it into your logic app code view and test it .
It works for me, as you can see , each request results are different :
Hope it helps .
This issue solved by OP self, this issue is due to queries in request URL , copy OP's comment as an answer :
After fiddling a bit more around with what each of you providing I
found a solution. It seems that when the query arguments are passed to
the HTTP GET outside of the endpoint itself (meaning in the "queries"
field inside of the block) it seems to keep overriding the nextLink.
When writing the endpoint URL out entirely with the odata parameters,
it works as intended.

how to create a confluence page using rest api with a label

I checked the documentation and I saw how to update an existing page to add the labels.
What I need is to create a new confluence page with a specific label that is added during this creation.
With get I saw that for a existing page, labels are stored into the metadatas:
"metadata": {
"labels": {
"results": [
{
"prefix": "global",
"name": "labelName1",
"id": "2195459"
},
{
"prefix": "global",
"name": "labelName2",
"id": "2195460"
}
],
"start": 0,
"limit": 200,
"size": 2,
"_links": {
"self": "http://localhost:8090/rest/api/content/2129921/label"
}
},...
Can anyone tell me if it is possible to create a page with a label and if yes, how?
Thanks
According to the documentation (https://docs.atlassian.com/confluence/REST/latest/#content/{id}/label-addLabels), you can add the following to your json for creating the page:
"metadata": {
"labels": [
{
"prefix": "global",
"name": "label1"
},
{
"prefix": "global",
"name": "label2"
}
]
},
I have not, however, been successful at getting this implementation to work yet. It seems to be ignored when I invoke the post to the endpoint (/rest/api/content).
I did some tests and found out that if you add below json node just after body node a curl will create the page with label2 successfully.
,"metadata": {"labels": [{"prefix": "global","name": "label2"}]}

How do I retrieve issues of specific status with JQL

Entering a url, or running with curl, like:
https://<myurl>/rest/api/2/search?jql=project=<myproject>&status=closed&fields=id,key,status,project&maxResults=5
returns me 5 items in my project but with all statuses. For some reason I can't query for a specific status.
The output (part of it) is:
{
"expand": "schema,names",
"startAt": 0,
"maxResults": 5,
"total": 727,
"issues": [
{
"expand": "editmeta,renderedFields,transitions,changelog,operations",
"id": "79577",
"self": "https://<myurl>/rest/api/2/issue/79577",
"key": "<myproject>-774",
"fields": {
"project": {
"self": "https://<myurl>/rest/api/2/project/<myproject>",
"id": "14421",
"key": "<myproject>",
"name": "<myproject>",
"avatarUrls": {
(...)
}
},
"status": {
"self": "<myurl>/rest/api/2/status/1",
"description": "The issue is open and ready for the assignee to start work on it.",
"iconUrl": "https://<myurl>/images/icons/statuses/open.png",
"name": "Open",
"id": "1"
}
}
},(...)
]
}
How to query for a given status? Many thanks.
Use URL encoding on the attributes.
Perhaps use an online tool like this to URL encode your JQL from this:
project = PROJECTKEY AND status = Closed
to get this:
/rest/api/2/search?jql=project%20%3D%20PROJECTKEY%20AND%20status%20%3D%20Closed&fields=id,key,status,project&maxResults=5
The resulting JSON will be all closed issues.
Run the query you want in the Issue Navigator. Use the link to the left of the Share button that resembles a chain link to find the URL for the query, e.g.
http://jira.example.com/issues/?jql=project%20%3D%20MDOAR%20and%20status%20%3D%20Closed
Use that URL with curl

Resources