Skip to content
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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

apburnes
Copy link
Contributor

@apburnes apburnes commented Feb 6, 2025

Changes proposed in this pull request:

security considerations

Adds api endpoints for managing file storage service

@cloud-gov-pages-operations
Copy link
Contributor

🤖 This is an automated code coverage report

Total coverage (lines): 18.23%
Coverage diff: -0.07% 📉

Copy link
Contributor

@drewbo drewbo left a 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

const { FileStorageService, Site } = require('../models');
const { isSiteOrgManager, isOrgManager, isOrgUser } = require('./utils');

const canCreateSiteStorage = async ({ id: userId }, { id: siteId }) => {
Copy link
Contributor

@drewbo drewbo Feb 7, 2025

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

const { Organization, Site } = require('../models');
const { fetchModelById } = require('../utils/queryDatabase');

const authorize = async ({ id: userId }, { id: siteId }) => {
Copy link
Contributor

@drewbo drewbo Feb 7, 2025

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({
Copy link
Contributor

@drewbo drewbo Feb 7, 2025

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)

@@ -0,0 +1,6 @@
const multer = require('multer');
Copy link
Contributor

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?

return result;
}

async deleteDirectory() {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be removed?

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],
Copy link
Contributor

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


const [base, extension] = splitFileExt(str);

if (str.length > 200) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (str.length > 200) {
if (str.length > len) {

const data = serializeFileStorageService(fss);
return res.send(data);
} catch (error) {
return res.status(error.status).send(error);
Copy link
Contributor

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

@drewbo drewbo force-pushed the feat-add-api-endoints-for-file-storage-2082 branch from 1fba65f to 84a7e3e Compare February 7, 2025 19:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants