Can't rename Google Drive files with nodeJs library - node.js

I'm unable to rename files in Google Drive in a NodeJs app. I'm using:
googleapi nodeJs library v. 20.1.0.
node v. 8.1.4
The app is handling requests for files fine, and it is able to duplicate files. However, when updating them, the new name is never applied.
I do get as a response the file resource, which would entail that the request was successful.
I'm doing this:
const google = require( 'googleapis' );
let googleService = google.drive( 'v3' );
let params = {
auth: testedAndValidOAuth,
fileId: validFileId,
uploadType: 'multipart',
name: "some name 2"
};
googleService.files.update( params, ( err, response ) => console.log(response));
For the property uploadType I've tried with and without it, with all the available options: resumable, multipart, and media. When trying media I got the following error:
Error: The API returned an error: Error: Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/drive/v3/files/xxxfileIdxxx?uploadType=media&name=some+name+2
I've tried to edit manually the link in the library and the error went away, but unfortunately the name did not change.
Looking in the library I've noticed that the name param is not mentioned:
#param {object} params Parameters for request
#param {string=} params.addParents A comma-separated list of parent IDs to add.
#param {string} params.fileId The ID of the file.
#param {boolean=} params.keepRevisionForever Whether to set the 'keepForever' field in the new head revision. This is only applicable to files with binary content in Drive.
#param {string=} params.ocrLanguage A language hint for OCR processing during image import (ISO 639-1 code).
#param {string=} params.removeParents A comma-separated list of parent IDs to remove.
#param {boolean=} params.supportsTeamDrives Whether the requesting application supports Team Drives.
#param {boolean=} params.useContentAsIndexableText Whether to use the uploaded content as indexable text.
#param {object} params.resource Media resource metadata
#param {object} params.media Media object
#param {string} params.media.mimeType Media mime-type
#param {string|object} params.media.body Media body contents
#param {object} [options] Optionally override request options, such as `url`, `method`, and `encoding`.
#param {callback} callback The callback that handles the response.
So I'm wondering, am I doing something wrong, is this intended, meaning that we can't edit file names, or is it a bug in the library?

Try setting your new name in params.media.body, eg
params.resource = {name: "newname"}
corrected as per comment

Related

How supply default values in calling a remote endpoint

I am an amateur programmer and cannot figure this out based on the documentation and examples provided.
Based on their sample capsule on https://bixbydevelopers.com/dev/docs/sample-capsules/samples/http, they directly called
var response = http.getUrl(config.get('remote.url') + '/shoes', options);
They do have documentation on what http.getUrl parameters are but no examples on how it should be formatted syntax-wise.
I also don't know what would be the point of creating an endpoints.bxb for API calls file if they don't use it and just call it manually in the .js file.
Any help is greatly appreciated!
The base method signature for http.getUrl is http.getUrl(url, options) where the url variable is a String and the options variable is a JSON object containing any or all of the following keys:
format: Output format.
query: Object containing unencoded keys and values for URL query string.
cacheTime: Cache time in milliseconds.
basicAuth: Basic Authentication; value must be an object with username and password.
You can learn more by exploring the documentation's http section here.
Regarding the http sample you referenced: It shows multiple ways to reach the same outcome. The endpoints.bxb file has the two following action-endpoints:
A local endpoint where the GET is handled by the Javascript file:
action-endpoint (FindShoe) {
accepted-inputs ()
local-endpoint (FindShoe.js)
}
A remote endpoint where the GET is defined within the endopoints.bxb file itself and doesn't require a Javascript file.
action-endpoint (FindShoeRemoteEndpoint) {
accepted-inputs ()
remote-endpoint ("{remote.url}/shoes") {
method (GET)
}
}

Sending an excel to frontend - Angular 2, Java

I have a Java API endpoint that returns an excel (I am using content-disposition=Content-Disposition","attachment; filename=Audit.Report.xlsx).
I have another Angular-Node JS application that needs to consume this API and when the user clicks on a link, it should pull the excel and display a pop-up asking them the location to save the document. I am at a loss as to how I can do this. I tried doing the following on the server side though,
Server Code:
getAuditReport = function ( req, resp ) {
var numberOfMonths = req.query.numberOfMonths;
console.log('In first method ' + numberOfMonths);
var auditReportPromise = this.getAuditReportXlPromise ( numberOfMonths );
auditReportPromise.then ( function ( data ) {
resp.headers('Content-Disposition: attachment; filename="audit.report_'+ new Date() + '".xls"');
resp.ContentType = "application/vnd.ms-excel";
resp.status ( 200 ).send ( data );
} ).catch ( function ( err ) {
resp.status ( 500 ).send ( err );
} );
}
The getAuditReportXlPromise method returns a promise to invoke the get method of the Java API. On invoking this API via a browser, I get the excel content on the browser rather than a prompt requesting me to save the document somewhere.
Can someone suggest what's wrong here, and what I need to do on the client side for the click functionality to work.
Update 1:
Following is the code from the HTML
<a id='10051' href="{{url}}" target=_blank class="ok-white-text">
Download Report
</a>
Based on the duration the user selects, I'm building the URL - this is getting built correctly.
If your API provides the file using GET then you should be able to download the file in a simple way by just setting a link to that API (i.e. an anchor containing the link like Download).
In this scenario the browser will take over the download process (i.e. locating the folder to download to, if configured to do so).
If you want to process the file on client side, then you need to transfer it in a binary mode as suggested by multiple answer for this question.
To answer how I did manage to get around this,
Client Side:
In the component, I did the following - wrote a method on clicking the button that contains a window.open to the url - something like,
window.open("<path to the java api>", '_blank');
The link like I mentioned above was a java api that was already generating the excel file.

CSRF in grails, withForm{}.invalidToken{} not working fine

As I've to use csrf in my grails application, I'm doing it by encapsulating my action logic under withForm{...}.invalidToken{....}, also I'm adding an attribute as: g:formRemote useToken="true" under g:formRemote tag in gsp.
The problem is, I'm always getting inside the invalidToken{...} block on submit and hence my form is not getting saved.
How should I make it working properly?
Example:
def action = {
withForm{
......
}.invalidToken{
println "Invalid Token code"
}
}
gsp ex:
<g:formRemote useToken="true" ...>
...
...
</g:formRemote>
useToken is not supported with formRemote. Please take a look on https://github.com/grails/grails-core/blob/2.5.x/grails-plugin-gsp/src/main/groovy/org/codehaus/groovy/grails/plugins/web/taglib/JavascriptTagLib.groovy#L349
The supported attributes for formRemote are:
* #attr name REQUIRED The form name
* #attr url REQUIRED The url to submit to as either a map (containing values for the controller, action, id, and params) or a URL string
* #attr action The action to execute as a fallback, defaults to the url if non specified
* #attr update Either a map containing the elements to update for 'success' or 'failure' states, or a string with the element to update in which cause failure events would be ignored
* #attr before The javascript function to call before the remote function call
* #attr after The javascript function to call after the remote function call
* #attr asynchronous Whether to do the call asynchronously or not (defaults to true)
* #attr method The method to use the execute the call (defaults to "post")
With that said. You can keep using the withForm in your controller and implement the form submission using jQuery or other JS library and send the token. Please take a look at this question: Grails - Is there a recommended way of dealing with CSRF attacks in AJAX forms?
Also I would recommend you to move on from tags like formRemote. I'm assuming you're using at least Grails 2.x. In case you want to migrate to Grails 3.x in the future, the Ajax-related tags are deprecated.
Hope this helps.

Podio file attached to item cannot be downloaded

I have an issue trying to download files attached to Podio items:
podio.request('get', '/file/{file_id}/raw').then(console.log);
The above program displays:
{}
This is a JSON stringified empty object (instead of raw file content).
Details:
The above file can be accessed with its URL when logged in
The above code is run after proper authentication
It actually works when using a file_id from an image field of the item, but not from a file attachment (pdf files in my case).
When using API endpoint /item/app/{app_id}/filter to get a list of items, the property file_count is set, but not files. I have to request /item/{item_id} individually to get the files property included in the response, not sure why.
Question: Do you know what is the issue, and how I can download raw attached files?
EDIT: aditionnal info
If I request a single file metadata using the folowing command:
podio.request('get', '/file/1234').then(console.log);
I get a file JSON object which includes many fields, but not the file content :
{
...
link: 'https://files.podio.com/1234',
file_id: 1234,
...
}
As stated in my comment to #stengaard, if I try to request the API for the above link, here is the response :
{ [PodioNotFoundError: [object Object]]
message:
{ error_parameters: {},
error_detail: null,
error_propagate: false,
request:
{ url: 'http://api.podio.com/1234',
query_string: '',
method: 'GET' },
error_description: 'No matching operation could be found. The path \'/1234\' was not found..',
error: 'not_found' },
status: 404,
url: 'https://api.podio.com:443/1234',
name: 'PodioNotFoundError' }
To use the GET /file/{file_id}/raw endpoint you need an API key with elevated trust levels.
Instead use GET /file/{file_id} endpoint. That contains a link attribute (a URL) you should follow to get the file content.
The link attribute will look like: https://files.podio.com/{file_id}. To fetch the file do https://files.podio.com/{file_id}?oauth_token={oauth_token}. Where the OAuth token is the same as the one used to GET /file/{file_id}. If you know the file ID (e.g. from a GET /item/{item_id} you can skip the GET /file/{file_id} and contact files.podio.com directly. (Note: You can also set the Authorization: OAuth2 {oauth_token} header in your HTTP request if you don't like passing the auth token in a URL paramter.)
For an example on how to use it see https://github.com/podio/podio-js/blob/master/lib/general.js#L11
Typically in the JS client, if you use podio as your Podio API object, the OAuth token would be located there:
podio.authObject.accessToken
So to get the raw content of the file in nodejs:
var url = 'https://files.podio.com/'+file_id+'?oauth_token='+podio.authObject.accessToken;
request(url, function (err, fileContent) {
// use fileContent here, write to a file, etc...
});
It seems your request has an error.
please try the below method and get raw file content from its response.
podio.request('get', '/file/{file_id}').then(console.log);
FYI, we couldn't get the files by filtering the items. we need to request /item/{item_id} individually to get the files property as you said.

Typo3 Extbase: get domain in CommandController

I'm trying to access the base url of my site inside a command action like this:
namespace Vendor\TxTest\Command;
class TestCommandController extends \TYPO3\CMS\Extbase\Mvc\Controller\CommandController
{
/**
* logger
*
* #var \TYPO3\CMS\Core\Log\LogManager
*/
protected $logger;
/**
* Class constructor
*/
public function __construct()
{
$this->logger = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance( 'TYPO3\\CMS\\Core\\Log\\LogManager' )->getLogger( __CLASS__ );
}
/**
* Test command
*/
public function testCommand()
{
$homeUrl = \TYPO3\CMS\Core\Utility\GeneralUtility::locationHeaderUrl( '/' );
$this->logger->info( 'url: ' . $homeUrl );
$this->logger->info( "\n\r\n\r" );
}
}
When I run the command from the Scheduler backend module, the domain looks ok, but when it runs automatically, the result is:
Mon, 10 Mar 2014 ... component="Vendor.TxNews.Command.TestCommandController": url: http:///
What is the correct way to get the domain in this context?
PHP knows the domain from the server-call. If your site is on a specific server, you might have several urls pointing to this server. Your PHP does not know by itself which domain he has. Only from the request that the user is doing PHP is getting this information in the $_SERVER-var that Typo3/Extbase can read. I assume your script is running on different servers if you want to get the url? Can you put a configuration on the server that is different for each server?
One approach to do this would be to store the url from a user-call and read this in your Background-Module.
to put it clear: If you run the scheduler automatically and therefore trigger PHP in CLI mode, there is no request URL / it is empty, as like the name already suggests u run in command line interface mode.
Typoscript has the baseURL settable and switchable, but even there the domain of the call is undefined, which is perfectly right.

Resources