Last active
April 4, 2018 17:00
-
-
Save TrevorPage/eeed5022e03978d9d003898ffe00f7db to your computer and use it in GitHub Desktop.
loopback-component-storage example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ------------------------------------------------------------------------ | |
// 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