Add Watcher - Rally Rest API - rally

How to "Add Watcher" using Rally Rest API? I am unable to locate any keywords "watch", "watcher" or reference to watcher in documentation
Edit 1:
Based on Joshua's answer
I have tried the below:
DynamicJsonObject watcherToBeAdded = new DynamicJsonObject();
DynamicJsonObject watcherResult;
watcherToBeAdded["UserUUID"] = User's UUID;
watcherToBeAdded["ArtifactUUID"] = Story's UUID;
watcherToBeAdded["zuul_key"] = rallyAPIKey;
watcherResult = restApi.Post("notifications/watch", watcherToBeAdded);
This led to method not allowed.
I have also tried:
string rallyRef = "https://rally1.rallydev.com/notifications/api/v2/watch";
DynamicJsonObject toUpdate = new DynamicJsonObject();
toUpdate["ArtifactUUID"] = StoryUUID;
toUpdate["UserUUID"] = UserUUID;
OperationResult updateResult = restApi.Update(rallyRef, toUpdate);
This is throwing the below exception:
Value cannot be null
Parameter name: key

Authentication:
All requests to must be authenticated with a valid zsessionid or Rally API Key. You can pass this in a few ways:
As a header: zuul=[ZSESSIONID]
or zuul=[RALLY_API_KEY]
As a cookie: ZSESSIONID=[ZSESSIONID]
or ZSESSIONID=[RALLY_API_KEY]
As a query parameter: zuul_key=[ZSESSIONID]
or zuul_key=[RALLY_API_KEY]
To add a "watch", you can send a request like:
Method: POST
Url: https://rally1.rallydev.com/notifications/api/v2/watch
Body:
{
UserUUID: <ObjectUUID of user to be added as watcher,
ArtifactUUID: <ObjectUUID of artifact to be watched>
}
To remove a watch, you can send a request like:
Method: DELETE
URL: https://rally1.rallydev.com/notifications/api/v2/watch?ArtifactUUID=<ObjectUUID of artifact>&UserUUID=<ObjectUUID of User to remove as watcher>

Related

Testing Coinbase API with Postman : pagination gives me error

I am testing the Coinbase API endpoints with Postman and the challenge is when I need to paginate
In order to setup Postman, I have followed the guide available here and in summary:
added variables
coinbase-api-base
coinbase-api-key
coinbase-api-secret
coinbase-api-timestamp
coinbase-api-signature
Added pre-request script in order to generate the request signature
// 1. Import crypto-js library
var CryptoJS = require("crypto-js");
// 2. Create the JSON request object var req = { timestamp: Math.floor(Date.now() / 1000), // seconds since Unix epoch method:
pm.request.method, path: pm.request.url.getPath(), body: '', // empty
for GET requests message: undefined, secret:
pm.collectionVariables.get("coinbase-api-secret"), // read value from
collection variable hmac: undefined, signature: undefined, };
// 3. Create the message to be signed req.message = req.timestamp + req.method + req.path + req.body;
// 4. Create HMAC using message and API secret req.hmac = CryptoJS.HmacSHA256(req.message, req.secret);
// 5. Obtain signature by converting HMAC to hexadecimal String req.signature = req.hmac.toString(CryptoJS.enc.Hex);
// 6. Log the request console.info("request: ", req);
// 7. Set Postman request's authentication headers for Coinbase REST API call pm.collectionVariables.set("coinbase-api-timestamp",
req.timestamp); pm.collectionVariables.set("coinbase-api-signature",
req.signature);
all worked well for a simple request such as:
GET {{coinbase-api-base}}/v2/accounts
then, if I add in the body request parameter (as explained here):
limit=50
to change the default pagination, I get an authentication error....
"errors": [
{ "id": "authentication_error",
"message": "invalid signature"
}
questions:
how can I fix it?
how the body of the request can play with the request signature...
any help suggestion is much appreciated
Thank you
Edit: the below being said, I'm not sure the base accounts API supports paging I could be wrong though, the CB docs are inconsistent to say the least. It does seem that the account history (ledger) and holds do though.
https://docs.cloud.coinbase.com/exchange/reference/exchangerestapi_getaccounts
get accounts function in Node.js API doesn't give an args param where the ledger does (see below):
getAccounts(callback) {
return this.get(['accounts'], callback);
}
Documentation for an api that does support paging, notice it gives you a query param section not available in the accounts documentation:
https://docs.cloud.coinbase.com/exchange/reference/exchangerestapi_getaccountledger
Looking at the node api, you still need to add the query string params to the body in order to sign:
calling function:
return this.get(
['accounts', accountID, 'ledger'],
{ qs: args },
callback
);
signing function:
let body = '';
if (options.body) {
body = JSON.stringify(options.body);
} else if (options.qs && Object.keys(options.qs).length !== 0) {
body = '?' + querystring.stringify(options.qs);
}
const what = timestamp + method.toUpperCase() + path + body;
const key = Buffer.from(auth.secret, 'base64');
const hmac = crypto.createHmac('sha256', key);
const signature = hmac.update(what).digest('base64');
return {
key: auth.key,
signature: signature,
timestamp: timestamp,
passphrase: auth.passphrase,
};
You can't add the limit to the body of the request, GET requests never includes any body.
You should add it as a query string parameter like (this is just an example):
GET {{coinbase-api-base}}/v2/accounts?limit=50

SwaggerUI not adding ApiKey to Header with Swashbuckle (5.x)

I am using Swashbuckle.AspNetCore 5.0.0 to generate Swagger documentation for my .Net Core WebApi project, and for the most part, everything is going fine.
I have set up some simple authentication using ApiKey, and that is working good.
Where I am having problems now is getting Swagger to add an ApiKey into the header of my requests. I followed the instructions for added the ApiKey security Definition/requirement, as mentioned in these various posts:
API key in header with swashbuckle
Empty authorization header on requests for Swashbuckle.AspNetCore
How to force Swagger/Swashbuckle to append an API key?
However, the ApiKey value is never added to the Header.
This is what I have in my startup:
c.AddSecurityDefinition("ApiKey",
new OpenApiSecurityScheme
{
Description = "ApiKey must appear in header",
Type = SecuritySchemeType.ApiKey,
Name = Constants.ApiKeyHeaderName,
In = ParameterLocation.Header
});
and
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Name = Constants.ApiKeyHeaderName,
Type = SecuritySchemeType.ApiKey,
In = ParameterLocation.Header
},
new List<string>()}
});
I was struggling myslef with this one but figured out that besides adding proper Reference, you have to also specify Scheme in definition, this is the code that is working for me correctly:
c.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme()
{
Name = "x-api-key",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Description = "Authorization by x-api-key inside request's header",
Scheme = "ApiKeyScheme"
});
var key = new OpenApiSecurityScheme()
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "ApiKey"
},
In = ParameterLocation.Header
};
var requirement = new OpenApiSecurityRequirement
{
{ key, new List<string>() }
};
c.AddSecurityRequirement(requirement);
Important tip is name in AddSecurityDefinition must be the same as Id in OpenApiReference. name can be every string.
OK, I was finally able to get this to work. I needed to add an instance of OpenApiReference to the OpenApiSecurityScheme object provided to c.AddSecurityRequirement()
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "ApiKeyAuth" }
I have to say that the documentation on this is a bit confusing. Probably not in small part due to the fact that anything posted on the internet is there forever, and so many posts that I found on this whole thing were no longer applicable due to changes in the framework :)
Now I just need to figure out how to send another header value along with the api-key, and I'll be done with this part

How to pull data from CATSone API with Authentication Token?

I am completely new to coding. I am trying to build a dashboard in Klipfolio. I am using a CATSone API to pull data from CATSone to Klipfolio. However, I can only get 100 rows a time, which means I would have to pull data 2600 times.
I am now trying to build a script to get data from the API through Google Script Editor. However, since I have no experience in this, I am just trying stuff. I watched some videos, also from Ben Collins. The basis is simple, and I get what he is doing.
However, I have a problem with putting the API key.
var API_KEY = 'key'
function callCATSone(){
//Call the CATSone API for all candidate list
var response = UrlFetchApp.fetch("https://api.catsone.nl/v3/candidates");
Logger.log(response.getContentText());
// URL and params for the API
var url = 'https://api.catsone.nl/v3/candidates';
var params = {
'method': 'GET',
'muteHttpExceptions': true,
'headers': {
'Authorization': 'key ' + apikey
}
};
// call the API
var response = UrlFetchApp.fetch(url, params);
var data = response.getContentText();
var json = JSON.parse(data);
}
In the end, I would like to transfer all candidate list data to my sheets. Therefore, I call on the API with Authorization key. After that, I will manipulate the data, but that's for later. The first problem I now encounter, is this fail code:
'Verzoek voor https://api.catsone.nl/v3/candidates is mislukt. Foutcode: 401. Ingekorte serverreactie: {"message":"Invalid credentials."} (Gebruik de optie muteHttpExceptions om de volledige reactie te onderzoeken.) (regel 6, bestand 'Code')'.
I expect to get a list of all data from CATSone into my sheets.
Does anyone know how I can accomplish this?
Two changes should fix the credentials error:
Authorization header should be Authorization: 'Token ' + yourApiKey instead of 'key ', see the v3 API documentation https://docs.catsone.com/api/v3/#authentication.
API key in your case is stored in a global variable API_KEY, you should reference it exactly like that, not as an apikey (unless there is a typo in your sample or some missing code): Authorization : 'Token ' + API_KEY.
Btw, it should probably set either a Content-Type header or a contentType parameter for UrlFetchApp.fetch() method call to application/json as UrlFetchApp.fetch() request content type defaults to application/x-www-form-urlencoded.
If you plan to continue working with APIs, it would be beneficial to read this MDN article.

Extbase UriBuilder and RealUrl on Ajax Requests

I'm developing a TYPO3 plugin, which outputs a list of records in VueJS.
Therefor I created a controller action which returns requested records as json.
Every record has a property "uri", which holds the uri to its detail page. I generate this uri with the Extbase uriBuilder.
The first records are loaded directly within my list action, where I assign this set of records to the VueJs application directly in the frontend (v-bind:items="my_json_objects").
The next set of records will be loaded on demand by calling my API which returns the same type of records.
Problem: The uri built by uriBuilder returns a rewritten url only in the first case, when objects assigned directly to VueJS. For all items loaded by ajax calls, uribuilder returns the non-rewritten url.
Both actions calls the same method to build the uri:
$item['uri'] = $this->buildShowUri($item);
The method to build the uri:
return $this->uriBuilder
->reset()
->setTargetPageUid(56) // currently static, for testing
->setCreateAbsoluteUri(true)
->uriFor(
'show',
[
'item' => $item,
]
);
Is there a way to trigger url rewriting in this way? Do I need to register the uri somewhere to realurl?
Any hints much appreciated.
How stupid. The uribuilder works, but I forgot to enable realurl in the page type which delivers the json output.
json = PAGE
json {
config {
linkVars = L(0-4)
**tx_realurl_enable = 1**
sys_language_mode = strict
disableAllHeaderCode = 1
debug = 0
no_cache = 1
additionalHeaders {
10 {
header = Content-Type: application/json
replace = 1
}
}
}
typeNum = 129912
10 = USER
10 {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
extensionName = MyExt
pluginName = Plug
vendorName = Myself
controller = Events
action = apiList
switchableControllerActions {
Event {
1 = apiList
}
}
}
}

Error setting contentDetails for live event - Youtube Live API v3

I've been using php to create yt live events successfully for a while. Since I've tried to disable embedding I've received the following error:
["Error calling POST https:\/\/www.googleapis.com\/youtube\/v3\/liveBroadcasts?part=snippet%2Cstatus: (400) contentDetails"]
The code is as follows:
$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->refreshToken($tokens[0]['google_oauth_refresh_token']);
// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);
// Check to ensure that the access token was successfully acquired.
if ($client->getAccessToken()) {
// die();
// Create an object for the liveBroadcast resource's snippet. Specify values
// for the snippet's title, scheduled start time, and scheduled end time.
$broadcastSnippet = new Google_Service_YouTube_LiveBroadcastSnippet();
$broadcastSnippet->setTitle($_POST['title']);
$broadcastSnippet->setDescription($_POST['description']);
$broadcastSnippet->setScheduledStartTime(date('c', strtotime($_POST['start_date']))); //'2034-01-30T00:00:00.000Z');
$broadcastSnippet->setScheduledEndTime(date('c', strtotime($_POST['start_time']))); // '2034-01-31T00:00:00.000Z');
$contentDetails = new Google_Service_YouTube_LiveBroadcastContentDetails();
$contentDetails->setEnableEmbed(false);
// debug($contentDetails);
// Create an object for the liveBroadcast resource's status, and set the
// broadcast's status to "private".
$status = new Google_Service_YouTube_LiveBroadcastStatus();
// $status->setPrivacyStatus('public');
$status->setPrivacyStatus('private');
// $status->setPrivacyStatus('unlisted');
// Create the API request that inserts the liveBroadcast resource.
$broadcastInsert = new Google_Service_YouTube_LiveBroadcast();
$broadcastInsert->setContentDetails($contentDetails);
$broadcastInsert->setSnippet($broadcastSnippet);
$broadcastInsert->setStatus($status);
$broadcastInsert->setKind('youtube#liveBroadcast');
// Execute the request and return an object that contains information
// about the new broadcast.
$broadcastsResponse = $youtube->liveBroadcasts->insert('snippet,status', $broadcastInsert, array());
// Create an object for the liveStream resource's snippet. Specify a value
// for the snippet's title.
$streamSnippet = new Google_Service_YouTube_LiveStreamSnippet();
$streamSnippet->setTitle('Transcoder - '.$_POST['title']);
// Create an object for content distribution network details for the live
// stream and specify the stream's format and ingestion type.
$cdn = new Google_Service_YouTube_CdnSettings();
$cdn->setFormat("720p");
$cdn->setIngestionType('rtmp');
// Create the API request that inserts the liveStream resource.
$streamInsert = new Google_Service_YouTube_LiveStream();
$streamInsert->setSnippet($streamSnippet);
$streamInsert->setCdn($cdn);
$streamInsert->setKind('youtube#liveStream');
// Execute the request and return an object that contains information
// about the new stream.
$streamsResponse = $youtube->liveStreams->insert('snippet,cdn',
$streamInsert, array());
// debug($streamsResponse);
// Bind the broadcast to the live stream.
$bindBroadcastResponse = $youtube->liveBroadcasts->bind(
$broadcastsResponse['id'],'id,contentDetails',
array(
'streamId' => $streamsResponse['id'],
));
In this line:
$broadcastsResponse = $youtube->liveBroadcasts->insert('snippet,status', $broadcastInsert, array());
It should be:
$broadcastsResponse = $youtube->liveBroadcasts->insert('snippet,status,contentDetails', $broadcastInsert, array());
You are setting contentDetails's embedded property but not including it in the request.
If you read the error, that's what it was complaining.