Skip to content

Instantly share code, notes, and snippets.

@TrevorPage
Last active April 4, 2018 17:00
Show Gist options
  • Save TrevorPage/eeed5022e03978d9d003898ffe00f7db to your computer and use it in GitHub Desktop.
Save TrevorPage/eeed5022e03978d9d003898ffe00f7db to your computer and use it in GitHub Desktop.
loopback-component-storage example
// ------------------------------------------------------------------------
// Disable the built-in methods for create and update.
Dashasset.disableRemoteMethodByName('replaceOrCreate'); // Disable the standard PUT / endpoint
Dashasset.disableRemoteMethodByName('replaceById'); // Disable the standard PUT /{id} endpoint, I think
Dashasset.disableRemoteMethodByName('create'); // Disable the standard POST endpoint
/**
* Defines the endpoint at /{id} using PUT for create or update (upsert) of dashboard assets.
*
* The {id} must be a valid ObjectID in 24-character hex string representation.
*
* A multipart HTTP request is expected with these files and fields:
* - asset (field): Mandatory JSON representation of the asset in the field value.
* - [THUMBNAIL_IMAGE_FIELDNAME] (file): Mandatory thumbnail image of the asset.
* - [FULL_IMAGE_FIELDNAME] (file): Optional full-version image, used only for image assets.
*
* The main reason for this endpoint in substitution of the basic built-in PUT/POST handlers (which are disabled)
* is because every dashboard asset upsert needs to be accompanied with an image thumbnail and (optionally) a
* full size image which are transferred to AWS using loopback-component-storage.
*
* The client must provide a valid ObjectID in the path whether it's an update or create operation. The URL {id}
* takes precedence over any id property in the asset (an id property in the submitted asset will be overwritten by the
* URL {id}. It is up to the client to generate ObjectIDs for new assets it submits. ID injection is disabled in LoopBack
* for this model. There are two reasons why the client is relied on to provide the ObjectIDs.
* Primarily, it allows the client to form relations between its own newly-created assets (such as a dashboard using a gauge)
* even prior to those assets being created at the server.
* Secondly, providing the id in the URL path allows the id to be known prior to parsing the multipart stream, which allows
* us to check asset ownership and build image filenames using that id dring AWS upload. Extracting the id from the asset
* itself isn't an option, becuase loopback-component-storage delivers the file metas and plain text fields only after
* performing the uploads, which is understandably so because of the streamed nature of the request processing.
*
*/
Dashasset.upsertWithImages = function (id, ctx, accessToken, cb) {
if(!ObjectID.isValid(id)) {
// Invalid objectId
var err = new Error('Invalid ObjectId');
err.statusCode = 400;
return cb(err);
}
if (accessToken == null) {
// No access token or access token invalid. ACL shouldn't have allowed us this far.
var err = new Error('Not Authorized (no valid access token)');
err.statusCode = 401;
return cb(err);
}
var userId = accessToken.userId;
ctx.req.params.container = 'XXXXXX_aws_bucket_name_here_XXXXXX';
var options = {};
options.acl = 'public-read';
options.getFilename = function(fileInfo) {
var name = fileInfo.field + '-' + id;
return name;
}
Dashasset
.findById(id)
.then(asset => {
if(asset) {
// An asset with this ID already exists, so it's an update operation. Check the ownership.
// Rather than asynchronously querying the owner relation object, just compare the user ObjectId.
if (asset.publisherId != userId.toString()) {
var err = new Error('Asset not owned by this user');
err.statusCode = 401;
return cb(err);
}
}
AppUser
.findById(userId)
.then(user => {
Dashasset.app.models.bucketimage
.upload(ctx.req, ctx.result, options,(error, fileObj) => {
if (error) {
return cb(error);
}
// Successfully uploaded to AWS.
var asset;
if (fileObj.fields["asset"]) {
asset = JSON.parse(fileObj.fields["asset"]);
}
else {
var err = new Error('Asset missing');
err.statusCode = 400;
return cb(err);
}
asset.publisherId = userId;
asset.author = user.username;
asset.date = new Date();
if (fileObj.files[FULL_IMAGE_FIELDNAME]) {
asset.fullUrl = fileObj.files[FULL_IMAGE_FIELDNAME][0].providerResponse.location;
}
if (fileObj.files[THUMBNAIL_IMAGE_FIELDNAME]) {
asset.thumbUrl = fileObj.files[THUMBNAIL_IMAGE_FIELDNAME][0].providerResponse.location;
}
asset.id = id;
Dashasset
.upsert(asset)
.then(asset => {
cb(null, asset);
}).catch(error => {
cb(error);
});
});
});
}).catch(error => {
cb(error);
});
};
Dashasset.remoteMethod(
'upsertWithImages',
{
description: 'Uploads a file',
accepts: [
{ arg: 'id', type: 'any', description: 'Model id', required: true},
{ arg: 'ctx', type: 'object', http: { source:'context' } },
{ arg: 'accessToken', type: 'object',
http: function(ctx) {
return ctx.req.accessToken;
}
}
],
returns: {
arg: 'dashasset', type: 'object', root: true
},
http: {verb: 'put', path: '/:id'}
}
);
// ------------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment