UiPath / orchestrator-nodejs

MIT License
8 stars 7 forks source link

TypeError: Cannot read property 'shift' of undefined #7

Closed kwoxer closed 3 years ago

kwoxer commented 3 years ago

As said in the description:

In that case, you will need to use a different method of authentication (please see the tool in tools/platform) The minimum configuration for platform access is as follows

So I did it exactly as it said: https://github.com/UiPath/orchestrator-nodejs/tree/master/tools/platform

Usage

Simply run the index:

node index.js

A browser will open and ask you to login, or will directly reach a redirection page displaying OK.

Copy the code at the end of the URL in the address bar, and paste it back in the tool.

A list of accounts and the associated Service Instances will be displayed.

In order to consume the Orchestrator API from using this module, you will need the refresh token, the account logical name (between brackets), and the service instance logical name (between brackets).

But in the end this was my result. Is it broken?

image

qbrandon commented 3 years ago

I need to update the instructions as they are no longer up to date. Two things that are important right now:

  1. the tools/platform code is no longer relevant now that we allow users to generate a refresh token (user key) directly from the cloud portal interface. Please refer here on how to: https://docs.uipath.com/orchestrator/v0/reference/consuming-cloud-api
  2. We have since then improved the implementation and the clientId must be set for the authentication to work, so please configure it along with the refreshToken in your Orchestrator instantiation options.
kwoxer commented 3 years ago

Good to know it's not working anymore. Can you show the JavaScript code for the node.js code that is doing the GETcall. I just know how to do that on client-side but not on server-side for security reasons.

qbrandon commented 3 years ago

Let me start from the beginning: In order to use this use the Orchestrator API with this module, we need to create an instance with authentication information. On premise, it would be username/password/tenant, but for Automation Cloud, we rely on OAuth, and therefore need a Client ID, User Key, Account and Service logical name. In other words, pass options to the constructor that would look like this:

var Orchestrator = require('uipath-orchestrator');
var orchestrator = new Orchestrator({
    clientId: 'qwertyuiopasdfghjkllzxcvbnmQWERT', // Client ID
    refreshToken: 'qwertyuiopasdfghjkllzxcvbnmQWERTYUIOPASDFGHJK', // User Key
    serviceInstanceLogicalName: 'myInstanceLogicalName', // Tenant Name
    path: 'myAccountLogicalName/myInstanceLogicalName' // Account Logical Name/Tenant Name
});

The refresh token (User Key here) does not expire, so it needs to be kept safe, and we do not expect users to typically generate more than 1 or 2 (that is to say, we do not expect code to grab the refresh token, this is something that we expect users to generate manually) When we first introduced this type of authentication to our Cloud platform, we did not have a UI to get these tokens (User key, Client ID) so I created the helper script in tools/platform to allow developers to grab a refresh token (that is the part that no longer works). However, we now have a UI to generate the User Key and Client ID as described in the docs, so no need for the tool/platform script anymore. Simply grab a User Key / Client ID tuple from your cloud.uipath.com account, and you can instantiate the class as described above. Then the sample code should work just fine:

var apiPath = '/odata/Users';
var apiQuery = {};
orchestrator.get(apiPath, apiQuery, function (err, data) {
    if (err) {
        console.error('Error: ' + err);
    }
    console.log('Data: ' + util.inspect(data));
});

Can you show the JavaScript code for the node.js code that is doing the GET call. I am uncertain which GET call you are referring to.

kwoxer commented 3 years ago

Gonna test that when we moved from on-prem to Cloud. Thanks.

kwoxer commented 3 years ago

Hey today we migrated from on-prem to Cloud. So I was able to test.

But when I do your example I get this one:

Error: Error: Unexpected status code: 302

But when I type invalid login data I get:

Error: Error: Unexpected status code: 401

So the auth is correct I would say? But why I get the error code 302 back instead?

On the old on-prem server I used the same code btw and there it worked well.

kwoxer commented 3 years ago

This is the Orch object. Maybe I did something wrong?

grafik

kwoxer commented 3 years ago

Ahh ok found it, lol, but not really senseful to me actually.

So changing path: 'XXX' to path: 'XXX/MainTenant' worked.

For what reason the logical name is twice in the config?

kwoxer commented 3 years ago

Ok next question. Everything works fine. The auth is working and several endpoints.

But in my case I have trouble with these both for example:

Here I get the error message:

{
  message: 'An organization unit is required for this action.',
  errorCode: 1101,
  resourceIds: null
}

So the question is. Do I use it correctly? And how to add the X-UIPATH-OrganizationUnitId to the request?

I can also create a new issue if you want.

qbrandon commented 3 years ago

As mentioned in the README, you may use the orchestrator.switchOrganizationUnitId(1234); method

kwoxer commented 3 years ago

Good to know. But how to get the proper Id?

I tried the Ids from odata/Folders. Both not working.

Because I now get:

Error: Error: Unexpected status code: 409
{
  message: "Couldn't find the specified unattended user/robot in the current folder.",
  errorCode: 1671,
  resourceIds: null
}

or

Error: Error: Unexpected status code: 404
{
  message: "The job's associated process could not be found",
  errorCode: 1002,
  resourceIds: null
}

Not sure if the OrganizationUnitIdor the robot id is incorrect.

kwoxer commented 3 years ago

Ahh ok I think I know why. This is our code to get back the robots:

/**
 * Get all robots
 */
var orchestrator = require('./authenticate');
var resultArray = {};

module.exports = function(resourceObject) {
  var apiPath = '/odata/Robots';
  var apiQuery = {};

  orchestrator.get(apiPath, apiQuery, function (err, data) {
    if (err) {
      console.error('Error: ' + err);
    }
    console.log(data['value']);
  });
}

and the console.log(data['value']); is in both cases [].

That means that there is no robot for the folder. Ok makes sense. Because we are using the modern folders.

So how to run a process without saying a specific robot id should run it?

kwoxer commented 3 years ago

Ahh and then the message in Postman also makes sense:

{
    "message": "robotDto must not be null",
    "errorCode": 0,
    "resourceIds": null
}

Because our Robot Cloud datatable is empty as we use the Modern folders instead of the Default folders.

So the question is still how to give the request to start a Modern folders job on a folder?

kwoxer commented 3 years ago

Ok I finally found out how. But this is nowhere documented. So the question is, is this a proper way to do it or just a dirty workaround?

{ 
    "startInfo": { 
        "ReleaseKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "Strategy": "RobotCount",
        "RobotIds": [],
        "NoOfRobots": 1,
        "Source": "Manual"
    }
}
qbrandon commented 3 years ago

Hi, glad to see you are finding ways to get things to work on your environment. The Orchestrator API is fairly complex and the mapping of entities to roles/permissions not always obvious. To add to this, there are many APIs that will require different payload interfaces depending on the user of classic or modern folders. So reading the documentation or swagger might not always be enough to get you exactly what you need. I have found that most operations you will ever get to implement using the API are typically available from the Orchestrator Web UI. That means that the easiest way to figure out which API is best and how it works is simply to open the developer tools in your favorite browser, and inspect the HTTP requests that are sent to Orchestrator. You will see the endpoint, the syntax for queries, and the structure of the payload for POST/PUT requests. If you manually start a job from the Orchestrator interface, you will see precisely the payload you mentioned above being sent to Orchestrator, and that can save you quite a bit of head scratching when discovering new APIs.

kwoxer commented 3 years ago

Ok perfect, then I gonna use the Inspector in the future. Thanks for response.