Skip to content

Commit 84e5b25

Browse files
committed
Web app overhaul; Changed subscription validation;
1 parent 9b263eb commit 84e5b25

44 files changed

Lines changed: 1733 additions & 682 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ coverage
1313

1414
# Text editors configurations
1515
.vscode
16+
.cursor
1617

1718
# Env file
1819
*.env
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import { Constants } from "@medialit/models";
2+
import test, { afterEach, describe, mock } from "node:test";
3+
import assert from "node:assert";
4+
import storageValidation from "../../src/media/storage-middleware";
5+
import mediaQueries from "../../src/media/queries";
6+
import {
7+
maxStorageAllowedNotSubscribed,
8+
maxStorageAllowedSubscribed,
9+
} from "../../src/config/constants";
10+
11+
describe("storageValidation middleware", () => {
12+
afterEach(() => {
13+
mock.restoreAll();
14+
});
15+
16+
test("should allow upload when user has enough space (non-subscribed)", async () => {
17+
const req = {
18+
user: {
19+
id: "test-user-id",
20+
subscriptionStatus: Constants.SubscriptionStatus.NOT_SUBSCRIBED,
21+
},
22+
files: {
23+
file: {
24+
size: 1024 * 1024, // 1MB
25+
},
26+
},
27+
};
28+
29+
const res = {
30+
status: (code: number) => ({
31+
json: (data: any) => ({ code, data }),
32+
}),
33+
};
34+
35+
mock.method(mediaQueries, "getTotalSpace").mock.mockImplementation(
36+
async () => 4 * 1024 * 1024, // 4MB used
37+
);
38+
39+
let nextCalled = false;
40+
const next = () => {
41+
nextCalled = true;
42+
};
43+
44+
const response = await storageValidation(req, res, next);
45+
assert.strictEqual(nextCalled, true);
46+
assert.strictEqual(response, undefined);
47+
});
48+
49+
test("should allow upload when user has enough space (subscribed)", async () => {
50+
const req = {
51+
user: {
52+
id: "test-user-id",
53+
subscriptionStatus: Constants.SubscriptionStatus.SUBSCRIBED,
54+
},
55+
files: {
56+
file: {
57+
size: 1024 * 1024, // 1MB
58+
},
59+
},
60+
};
61+
62+
const res = {
63+
status: (code: number) => ({
64+
json: (data: any) => ({ code, data }),
65+
}),
66+
};
67+
68+
mock.method(mediaQueries, "getTotalSpace").mock.mockImplementation(
69+
async () => 9 * 1024 * 1024, // 9MB used
70+
);
71+
72+
let nextCalled = false;
73+
const next = () => {
74+
nextCalled = true;
75+
};
76+
77+
const response = await storageValidation(req, res, next);
78+
assert.strictEqual(nextCalled, true);
79+
assert.strictEqual(response, undefined);
80+
});
81+
82+
test("should reject upload when user exceeds storage limit (non-subscribed)", async () => {
83+
const req = {
84+
user: {
85+
id: "test-user-id",
86+
subscriptionStatus: Constants.SubscriptionStatus.NOT_SUBSCRIBED,
87+
},
88+
files: {
89+
file: {
90+
size: 1024 * 1024 * 2, // 2MB
91+
},
92+
},
93+
};
94+
95+
const res = {
96+
status: (code: number) => ({
97+
json: (data: any) => ({ code, data }),
98+
}),
99+
};
100+
101+
mock.method(mediaQueries, "getTotalSpace").mock.mockImplementation(
102+
async () => maxStorageAllowedNotSubscribed - 1024 * 1024, // 1MB remaining
103+
);
104+
105+
let nextCalled = false;
106+
const next = () => {
107+
nextCalled = true;
108+
};
109+
110+
const response = await storageValidation(req, res, next);
111+
assert.strictEqual(response.code, 400);
112+
assert.strictEqual(
113+
response.data.error,
114+
"You do not have enough storage space in your account to upload this file",
115+
);
116+
assert.strictEqual(nextCalled, false);
117+
});
118+
119+
test("should reject upload when user exceeds storage limit (subscribed)", async () => {
120+
const req = {
121+
user: {
122+
id: "test-user-id",
123+
subscriptionStatus: Constants.SubscriptionStatus.SUBSCRIBED,
124+
},
125+
files: {
126+
file: {
127+
size: 1024 * 1024 * 2, // 2MB
128+
},
129+
},
130+
};
131+
132+
const res = {
133+
status: (code: number) => ({
134+
json: (data: any) => ({ code, data }),
135+
}),
136+
};
137+
138+
mock.method(mediaQueries, "getTotalSpace").mock.mockImplementation(
139+
async () => maxStorageAllowedSubscribed - 1024 * 1024, // Remaining space is 1MB
140+
);
141+
142+
let nextCalled = false;
143+
const next = () => {
144+
nextCalled = true;
145+
};
146+
147+
const response = await storageValidation(req, res, next);
148+
assert.strictEqual(response.code, 400);
149+
assert.strictEqual(
150+
response.data.error,
151+
"You do not have enough storage space in your account to upload this file",
152+
);
153+
assert.strictEqual(nextCalled, false);
154+
});
155+
156+
test("should handle missing file in request", async () => {
157+
const req = {
158+
user: {
159+
id: "test-user-id",
160+
subscriptionStatus: Constants.SubscriptionStatus.NOT_SUBSCRIBED,
161+
},
162+
files: {},
163+
};
164+
165+
const res = {
166+
status: (code: number) => ({
167+
json: (data: any) => ({ code, data }),
168+
}),
169+
};
170+
171+
let nextCalled = false;
172+
const next = () => {
173+
nextCalled = true;
174+
};
175+
176+
const response = await storageValidation(req, res, next);
177+
assert.strictEqual(response.code, 400);
178+
assert.strictEqual(response.data.error, "No file uploaded");
179+
assert.strictEqual(nextCalled, false);
180+
});
181+
});

apps/api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"@types/express": "^4.17.20",
5555
"@types/express-fileupload": "^1.2.2",
5656
"@types/mongoose": "^5.11.97",
57-
"@types/node": "^20.8.7",
57+
"@types/node": "^22.14.1",
5858
"@types/passport": "^1.0.7",
5959
"@types/passport-jwt": "^3.0.6",
6060
"@typescript-eslint/eslint-plugin": "^5.17.0",

apps/api/src/apikey/handlers.ts.notused

Lines changed: 0 additions & 62 deletions
This file was deleted.

apps/api/src/apikey/middleware.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
SUBSCRIPTION_NOT_VALID,
44
UNAUTHORISED,
55
} from "../config/strings";
6-
import { validateSubscription } from "../subscription/validate-subscription";
76
import { getApiKeyUsingKeyId } from "./queries";
87
import { getUser } from "../user/queries";
98
import { Apikey } from "@medialit/models";
@@ -33,12 +32,12 @@ export default async function apikey(
3332
}
3433
}
3534

36-
const isSubscriptionValid = await validateSubscription(
37-
apiKey!.userId.toString(),
38-
);
39-
if (!isSubscriptionValid) {
40-
return res.status(403).json({ error: SUBSCRIPTION_NOT_VALID });
41-
}
35+
// const isSubscriptionValid = await validateSubscription(
36+
// apiKey!.userId.toString(),
37+
// );
38+
// if (!isSubscriptionValid) {
39+
// return res.status(403).json({ error: SUBSCRIPTION_NOT_VALID });
40+
// }
4241

4342
req.user = await getUser(apiKey!.userId.toString());
4443
req.apikey = apiKey.key;

apps/api/src/apikey/routes.ts.notused

Lines changed: 0 additions & 34 deletions
This file was deleted.

apps/api/src/config/constants.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ export const maxFileUploadSizeNotSubscribed = process.env
1111
.MAX_UPLOAD_SIZE_NOT_SUBSCRIBED
1212
? +process.env.MAX_UPLOAD_SIZE_NOT_SUBSCRIBED
1313
: 52428800;
14+
export const maxStorageAllowedSubscribed = process.env
15+
.MAX_STORAGE_ALLOWED_SUBSCRIBED
16+
? +process.env.MAX_STORAGE_ALLOWED_SUBSCRIBED
17+
: 107374182400;
18+
export const maxStorageAllowedNotSubscribed = process.env
19+
.MAX_STORAGE_ALLOWED_NOT_SUBSCRIBED
20+
? +process.env.MAX_STORAGE_ALLOWED_NOT_SUBSCRIBED
21+
: 1073741824;
1422
export const PRESIGNED_URL_VALIDITY_MINUTES = 5;
1523
export const PRESIGNED_URL_LENGTH = 100;
1624
export const MEDIA_ID_LENGTH = 40;

apps/api/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ async function createAdminUser() {
8181
const user = await createUser(
8282
email,
8383
undefined,
84-
new Date(
85-
new Date().setFullYear(new Date().getFullYear() + 100),
86-
),
84+
// new Date(
85+
// new Date().setFullYear(new Date().getFullYear() + 100),
86+
// ),
8787
"subscribed",
8888
);
8989
const apikey: Apikey = await createApiKey(user.id, "App 1");

apps/api/src/media/handlers.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import Joi from "joi";
22
import {
33
maxFileUploadSizeNotSubscribed,
44
maxFileUploadSizeSubscribed,
5+
maxStorageAllowedNotSubscribed,
6+
maxStorageAllowedSubscribed,
57
} from "../config/constants";
68
import {
79
FILE_IS_REQUIRED,
@@ -13,7 +15,7 @@ import logger from "../services/log";
1315
import { Request } from "express";
1416
import mediaService from "./service";
1517
import { getMediaCount as getCount, getTotalSpace } from "./queries";
16-
import { Constants } from "@medialit/models";
18+
import { Constants, getSubscriptionStatus } from "@medialit/models";
1719

1820
function validateUploadOptions(req: Request): Joi.ValidationResult {
1921
const uploadSchema = Joi.object({
@@ -26,9 +28,7 @@ function validateUploadOptions(req: Request): Joi.ValidationResult {
2628
}
2729

2830
function getMaxFileUploadSize(req: any): number {
29-
const isSubscribed =
30-
req.user.subscriptionStatus === Constants.SubscriptionStatus.SUBSCRIBED;
31-
return isSubscribed
31+
return getSubscriptionStatus(req.user)
3232
? maxFileUploadSizeSubscribed
3333
: maxFileUploadSizeNotSubscribed;
3434
}
@@ -138,8 +138,13 @@ export async function getTotalSpaceOccupied(req: any, res: any) {
138138
const apikey = req.apikey;
139139

140140
try {
141-
const totalMediaFiles = await getTotalSpace({ userId, apikey });
142-
return res.status(200).json({ count: totalMediaFiles });
141+
const totalSpaceOccupied = await getTotalSpace({ userId, apikey });
142+
return res.status(200).json({
143+
storage: totalSpaceOccupied,
144+
maxStorage: getSubscriptionStatus(req.user)
145+
? maxStorageAllowedSubscribed
146+
: maxStorageAllowedNotSubscribed,
147+
});
143148
} catch (err: any) {
144149
return res.status(500).json(err.message);
145150
}

0 commit comments

Comments
 (0)