Filepicker.io — How To Get An S3 URL onSuccess? - filepicker.io

How would I go about getting Filepicker.io to return an S3 URL instead of the www.filpicker.io/app/api/... default?
My files are uploading to S3 just fine (super easy, actually), but the URL that the fpfiles object contains is not my S3 URL.
I suppose I could just Frankenstein it together myself so I can insert it into my DB, but that seems messy.
Here's the code I'm using:
$('#BTN_upload').click(function(){
filepicker.setKey('MY_FILEPICKER.IO_KEY');
filepicker.pickAndStore(
//Picker Options
{ extensions: ['.png'], container: 'modal', multiple: true },
//Store Options
{location: 'S3', path: '/filepicker/', filename:'my_filename.png'},
//On Success
function(fpfiles){
console.log(JSON.stringify(fpfiles));
},
//On Error
function(fperror){
console.log(JSON.stringify(fperror));
}
);
});
BONUS QUESTION
How do I go about setting the filename as I'd like, not as Filepicker.io defaults to the uniqueid_originalFilename.png. I'd like to handle my filenames myself but there doesn't seem to be any way to override the default.
Thanks in advance for any help.

It returns the S3 key. A simple concatenation of your s3 url "https://s3.amazonaws.com/your_own_bucket/" + s3key will do it.
Regarding your other question, if you set the "path" option, that will tell filepicker where to store the file.

Related

How to Return File from SvelteKit Endpoint

I am trying to serve a PDF file that my SvelteKit app generates and allow a user to download it from an endpoint.
My project structure looks like this:
---------------------
/src/routes/downloads
---------------------
[file].ts
ABC.pdf
XYZ.pdf
My [file].ts endpoint looks like this:
import fs from 'fs'
// ----- GET -----
export async function get({ params }){
//console.log(params.file) -> ABC
var pdf = fs.readFileSync('./src/routes/downloads/'+params.file+'.pdf')
return{
status:200,
headers: {
"Content-type" : "application/pdf",
"Content-Disposition": "attachment; filename="+params.file+".pdf"
},
body: pdf
}
}
So then when I hit http://localhost:3000/downloads/ABC, the PDF file named ABC.pdf downloads.
But my readFileSync path isn't something that's going to work on production. As far as I know, there is no /src/routes folder.
How do I serve my file from a http://localhost:3000 url? Everything I've tried yields a 404 and it can't find the file. I'm also open to a different way of handling this scenario. This is just my best guess of how to do this in SvelteKit.
The recommended way to do this, for adapter-node, is to place your application data in a new folder under your project's root directory (ie. alongside /src and /static). You can then read files with a relative path: fs.readFile('./my-app-data/foo.txt').
For deployment, you just have to make sure to execute node build from the project root, as this guarantees that you have the same working directory during both development and production.
The static folder works, but it is not meant to carry application data—files in this folder represent new routes that are served directly to users, so this is not desirable if your generated files must be protected in any way. Even if they're meant to be public files, it still blurs what is supposed to be production and source data: should a new deploy overwrite all the files in static? If you're not careful, a naming clash could mean overwriting production data.
You can use import.meta.glob for this.
export async function get({ params }){
const file = `./${params.file}.pdf`;
const pdfs = import.meta.glob(('./*.pdf', { as: 'raw' });
const pdf = pdfs[file];
return {
status:200,
headers: {
"Content-type" : "application/pdf",
"Content-Disposition": "attachment; filename="+params.file+".pdf"
},
body: pdf
}
}
The import.meta.glob in combination with the as: 'raw' option will effectively embed the contents of each file in your resulting code. (this is purely server side so no worries about shipping to much to the client)
Note that this of course means that only files present during build can be served this way.
As #Stephane suggest, put your files under statics folder. This way you can serve directly through a reverse proxy, like Nginx

Azure Media Services - Download Transient Error

I have a lot of audios in my database whose URLs are like:
https://mystorage.blob.core.windows.net/mycontainer/uploaded%2F735fe9dc-e568-4920-a3ed-67230ce01991%2F5998d1f8-1795-4776-a19c-f1bc4a0d4786%2F2020-08-13T13%3A09%3A13.0996703Z?sv=2020-02-10&se=2022-01-05T16%3A58%3A50Z&sr=b&sp=r&sig=hQBPyOE92%2F67MqU%2Fe5V2NsqGzgPxogVeXQT%2BOlvbayw%3D
I am using these URLs as my JobInput, and submitting a encoding job, because I want to migrate the audios distribution to a streaming approach.
However, every time I use this kind of URL, it fails with DownloadTransientError, and a message something like while trying to download the input files, the files were not acessible.
If I manually upload a file to the blob storage with a simpler URL (https://mystorage.blob.core.windows.net/mycontainer/my-audio.wav), and use it as the JobInput, it works seamlessly. I suspect it has something to do with the special characters on the bigger URL, but I am not sure. What could be the problem?
Here is the part of the code that submits the job:
var jobInput = new JobInputHttp(new[]
{
audio.AudioUrl.ToString()
});
JobOutput[] jobOutput =
{
new JobOutputAsset(outputAssetName),
};
var job = await client.Jobs.CreateAsync(
resourceGroupName: _azureMediaServicesSettings.ResourceGroup,
accountName: _azureMediaServicesSettings.AccountName,
transformName: TransformName,
jobName: jobName,
new Job
{
Input = jobInput,
Outputs = jobOutput
});
You need to include the file name in the URL you're providing. I'll use your URL as an example, but unescape it as well so that it is more clear. The URL should be something like https://mystorage.blob.core.windows.net/mycontainer/uploaded/735fe9dc-e568-4920-a3ed-67230ce01991/5998d1f8-1795-4776-a19c-f1bc4a0d4786/2020-08-13T13:09:13.0996703Z/my-audio.wav?sv=2020-02-10&se=2022-01-05T16:58:50Z&sr=b&sp=r&sig=hQBPyOE92/67MqU/e5V2NsqGzgPxogVeXQT+Olvbayw=
Just include the actual blob name of the input video or audio file with the associated file extension.

Filepicker.io Javascript API Remove

Trying to use the remove function after the pick function and file is not being removed. (from here https://www.filepicker.com/documentation/file_ingestion/javascript_api/remove?v=v2)
selectFileMedium: function () {
filepicker.pick({
cropRatio: 24/13,
mimetype: 'image/*',
imageDim: [1440, 780]
}, function (Blob) {
InnerThis.uploadMediumImage(Blob.url, Blob.filename);
filepicker.remove(Blob);
});
}
Am I doing this correct?
Blob object return url property which is unificated url of uploaded file eg:
https://www.filepicker.io/api/file/AQgF2U68SNmJDpDXlOdg
However since v2 dialog version there is crop UI avaliable. If user crop file as a response it return the uploaded file url with appended Rest convert parameters:
https://www.filepicker.io/api/file/AQgF2U68SNmJDpDXlOdg/convert?crop=100,200,200,300
filepicker.remove dose not deal with it. Some temporary workaround would be to strip url from '/convert' part just before remove it. However it should be solved on library side.

Ember js RESTAdapter PUT request adds .json to the end

I've been trying to learn Ember and I have a question.
In my store I'am getting data from .json like below. I have tried without buildUrl function but cant load the json file, then found this solution on SO.
CocktailApp.Store = DS.Store.extend({
revision: 12,
adapter: DS.RESTAdapter.extend({
bulkCommit: false,
url: "http://localhost:8888",
buildURL: function(record, suffix) {
var s = this._super(record, suffix);
return s + ".json";
}
})
});
Now comes my question: When I commit the chances (by pressing add to favs or remove from favs) RESTAdapter adds ".json" at the end of to PUT request. See the below code and screenshot
CocktailApp.CocktailController = Ember.ObjectController.extend({
addToFav: function () {
this.set('fav',true);
this.get('store').commit();
},
removeFromFav: function () {
this.set('fav',false);
this.get('store').commit();
}
});
I think thats why my PUT request can not be handled. But If I remove the builtURL function no json loaded at all. How can I resolve this problem?
Thanks
If the API endpoint url does not require .json at the end of it, then remove that line from your buildURL function. My guess is that the example code you got was consuming a ruby on rails api, or something similar.
remember, when you send a GET, PUT, POST, or DELETE to a url, that url needs to actually be a real endpoint. You can't just add extraneous stuff to it and have it still work.

Angular JS: Full example of GET/POST/DELETE/PUT client for a REST/CRUD backend?

I've implemented a REST/CRUD backend by following this article as an example: http://coenraets.org/blog/2012/10/creating-a-rest-api-using-node-js-express-and-mongodb/ . I have MongoDB running locally, I'm not using MongoLabs.
I've followed the Google tutorial that uses ngResource and a Factory pattern and I have query (GET all items), get an item (GET), create an item (POST), and delete an item (DELETE) working. I'm having difficulty implementing PUT the way the backend API wants it -- a PUT to a URL that includes the id (.../foo/) and also includes the updated data.
I have this bit of code to define my services:
angular.module('realmenServices', ['ngResource']).
factory('RealMen', function($resource){
return $resource('http://localhost\\:3000/realmen/:entryId', {}, {
query: {method:'GET', params:{entryId:''}, isArray:true},
post: {method:'POST'},
update: {method:'PUT'},
remove: {method:'DELETE'}
});
I call the method from this controller code:
$scope.change = function() {
RealMen.update({entryId: $scope.entryId}, function() {
$location.path('/');
});
}
but when I call the update function, the URL does not include the ID value: it's only "/realmen", not "/realmen/ID".
I've tried various solutions involving adding a "RealMen.prototype.update", but still cannot get the entryId to show up on the URL. (It also looks like I'll have to build the JSON holding just the DB field values myself -- the POST operation does it for me automatically when creating a new entry, but there doesn't seem to be a data structure that only contains the field values when I'm viewing/editing a single entry).
Is there an example client app that uses all four verbs in the expected RESTful way?
I've also seen references to Restangular and another solution that overrides $save so that it can issue either a POST or PUT (http://kirkbushell.me/angular-js-using-ng-resource-in-a-more-restful-manner/). This technology seems to be changing so rapidly that there doesn't seem to be a good reference solution that folks can use as an example.
I'm the creator of Restangular.
You can take a look at this CRUD example to see how you can PUT/POST/GET elements without all that URL configuration and $resource configuration that you need to do. Besides it, you can then use nested resources without any configuration :).
Check out this plunkr example:
http://plnkr.co/edit/d6yDka?p=preview
You could also see the README and check the documentation here https://github.com/mgonto/restangular
If you need some feature that's not there, just create an issue. I usually add features asked within a week, as I also use this library for all my AngularJS projects :)
Hope it helps!
Because your update uses PUT method, {entryId: $scope.entryId} is considered as data, to tell angular generate from the PUT data, you need to add params: {entryId: '#entryId'} when you define your update, which means
return $resource('http://localhost\\:3000/realmen/:entryId', {}, {
query: {method:'GET', params:{entryId:''}, isArray:true},
post: {method:'POST'},
update: {method:'PUT', params: {entryId: '#entryId'}},
remove: {method:'DELETE'}
});
Fix: Was missing a closing curly brace on the update line.
You can implement this way
$resource('http://localhost\\:3000/realmen/:entryId', {entryId: '#entryId'}, {
UPDATE: {method: 'PUT', url: 'http://localhost\\:3000/realmen/:entryId' },
ACTION: {method: 'PUT', url: 'http://localhost\\:3000/realmen/:entryId/action' }
})
RealMen.query() //GET /realmen/
RealMen.save({entryId: 1},{post data}) // POST /realmen/1
RealMen.delete({entryId: 1}) //DELETE /realmen/1
//any optional method
RealMen.UPDATE({entryId:1}, {post data}) // PUT /realmen/1
//query string
RealMen.query({name:'john'}) //GET /realmen?name=john
Documentation:
https://docs.angularjs.org/api/ngResource/service/$resource
Hope it helps