-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat add api endoints for file storage 2082 #4715
Conversation
🤖 This is an automated code coverage reportTotal coverage (lines): 18.3% |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, well thought-out feature with tests to boot. I added a few notes on some small changes that I think could clean up the code a little bit but overall looks great. I didn't focus too much on models since I had already seen most of that.
Haven't checked on dev yet but I'll see if I can mess with the functionality today
api/authorizers/file-storage.js
Outdated
const { FileStorageService, Site } = require('../models'); | ||
const { isSiteOrgManager, isOrgManager, isOrgUser } = require('./utils'); | ||
|
||
const canCreateSiteStorage = async ({ id: userId }, { id: siteId }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of canCreateSiteStorage
, canAdminCreateSiteFileStorage
, isFileStorageManager
, and isFileStorageUser
have function signatures that are nice for tests but when used in controllers require constructing an object, just to destructure it immediately. I think a "more ergonomic" signature would be fn({ userId, siteId })
or fn(userId, siteId)
. Some of these functions also return a single-property object which is immediately destructured, it might be easier to just return the property directly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We had this fn({ id: userId }, { id: siteId })
convention with other authorizers so I kept it but it did give me a bit of a bad taste. I like the fn(userId, siteId)
so I will update them to that new signature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a few authorizers that are returning the model instance we pass in the function argument. I will leave those as is and not update them to the new signature.
api/authorizers/utils.js
Outdated
const { Organization, Site } = require('../models'); | ||
const { fetchModelById } = require('../utils/queryDatabase'); | ||
|
||
const authorize = async ({ id: userId }, { id: siteId }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment in this file regarding function signatures and return values
const { SiteFileStorageSerivce } = require('../services/file-storage'); | ||
const badRequest = require('../responses/badRequest'); | ||
|
||
module.exports = wrapHandlers({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we need to create the service/client in each method (to ensure we have s3 credentials), there's a decent chunk of repeated code throughout the controller:
const siteStorageService = new SiteFileStorageSerivce(fileStorageService, user.id);
const client = await siteStorageService.createClient();
const results = await client.<some method> ...
For now it might be nice to wrap this in a helper function to DRY the code a bit. In the future, we could potentially optimize this more by caching the S3 credentials to avoid needing to fetch them on each request. (but for now it feels like premature optimization)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For DRY, this seems like a bit premature for how often we use the class but there could be two options to optimize.
Create a private method that checks if the credentials have been fetched for all methods and then either fetches or uses the instance credentials when a method is called.
const client = new SiteFileStorageSerivce(fileStorageService, user.id);
const results = await client.<some method>
Or we create a functions that instantiate the class, create the client and then pass its args to the method.
async function createFile(fileStorageService, userId, key, name, blob) {
const siteStorageService = new SiteFileStorageSerivce(fileStorageService, userId);
const client = await siteStorageService.createClient();
return client.createFile(key, name, blob)
}
Our S3 services rotate credentials so we would have to build some type of credentials session to share between instances and identify the refresh schedule. That adds additional work beyond any possible gains and UX improvements at this point in development. Tracking this going forward would be worth while to track and make that decision at a later date.
@@ -0,0 +1,6 @@ | |||
const multer = require('multer'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any concerns with using this package because of age?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went with multer because it was specifically called out in the middleware docs but we can test it against formidable since that package has a more recent update cadence.
api/services/file-storage/index.js
Outdated
return result; | ||
} | ||
|
||
async deleteDirectory() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be removed?
api/utils/index.js
Outdated
const limit = toInt(params.limit) || 25; | ||
const page = toInt(params.page) || 1; | ||
const offset = limit * (page - 1); | ||
|
||
const pQuery = { | ||
limit, | ||
offset, | ||
order: [['createdAt', 'DESC']], | ||
order: [order], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might have already been incorrect but api/admin/controllers/domain.js
uses the paginate function twice with order
supplied in the query
; I'd check that this doesn't create two separate sorts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take a look
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is just overwriting the preset order
if the order
is added in the query params. I'm going to move the order into the query
params.
const data = serializeFileStorageService(fss); | ||
return res.send(data); | ||
} catch (error) { | ||
return res.status(error.status).send(error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One issue with this pattern is that unhandled errors won't be logged anywhere, it will first show that it doesn't have an associated status:
TypeError: Invalid status code: undefined. Status code must be an intege
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
1fba65f
to
84a7e3e
Compare
84a7e3e
to
c550bc2
Compare
🤖 This is an automated code coverage reportTotal coverage (lines): 18.3% |
a84c028
to
ebc2984
Compare
ea73f7a
to
1b126fc
Compare
Signed-off-by: Andrew Burnes <[email protected]>
1b126fc
to
2a7a687
Compare
Changes proposed in this pull request:
security considerations
Adds api endpoints for managing file storage service