Skip to content

Commit 783cde6

Browse files
Added subscription cancellation API.
1 parent a53ff7e commit 783cde6

4 files changed

Lines changed: 64 additions & 19 deletions

File tree

src/service/api/user/admin-api/routes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { DelegatedAuthFlow } from "../../middleware/authenticate.js";
55
import POST_Ban, { POST_BanValidator } from "../shared/ban.post.js";
66
import POST_Restrict, { POST_RestrictValidator } from "../shared/restrict.post.js";
77
import POST_Subscription, { POST_SubscriptionValidator } from "../shared/subscription.post.js";
8+
import POST_SubscriptionCancel, { POST_SubscriptionCancelValidator } from "../shared/subscription-cancel.post.js";
89
import POST_Access, { POST_AccessValidator } from "../shared/access.post.js";
910
import POST_Verify, { POST_VerifyValidator } from "./verify.post.js";
1011
import POST_Create, { POST_CreateValidator } from "../shared/create.post.js";
@@ -31,6 +32,7 @@ AdminApiRouter.post("/credits", ...DelegatedAuthFlow, POST_CreditsValidator, POS
3132
AdminApiRouter.post("/restrict", ...DelegatedAuthFlow, POST_RestrictValidator, POST_Restrict);
3233
AdminApiRouter.post("/verify", ...DelegatedAuthFlow, POST_VerifyValidator, POST_Verify);
3334
AdminApiRouter.post("/subscription", ...DelegatedAuthFlow, POST_SubscriptionValidator, POST_Subscription);
35+
AdminApiRouter.post("/subscription-cancel", ...DelegatedAuthFlow, POST_SubscriptionCancelValidator, POST_SubscriptionCancel);
3436
AdminApiRouter.get("/subscription-tiers", ...DelegatedAuthFlow, GET_SubscriptionTiers);
3537
AdminApiRouter.post("/create", ...DelegatedAuthFlow, POST_CreateValidator, POST_Create);
3638
AdminApiRouter.get("/list", ...DelegatedAuthFlow, GET_List);

src/service/api/user/client-api/routes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ClientAuthFlow } from "../../middleware/authenticate.js";
55
import POST_Ban, { POST_BanValidator } from "../shared/ban.post.js";
66
import POST_Restrict, { POST_RestrictValidator } from "../shared/restrict.post.js";
77
import POST_Subscription, { POST_SubscriptionValidator } from "../shared/subscription.post.js";
8+
import POST_SubscriptionCancel, { POST_SubscriptionCancelValidator } from "../shared/subscription-cancel.post.js";
89
import POST_Create, { POST_CreateValidator } from "../shared/create.post.js";
910
import POST_Credits, { POST_CreditsValidator } from "../shared/credits.post.js";
1011
import POST_Access, { POST_AccessValidator } from "../shared/access.post.js";
@@ -28,6 +29,7 @@ ClientApiRouter.post("/ban", ...ClientAuthFlow, POST_BanValidator, POST_Ban);
2829
ClientApiRouter.post("/credits", ...ClientAuthFlow, POST_CreditsValidator, POST_Credits);
2930
ClientApiRouter.post("/restrict", ...ClientAuthFlow, POST_RestrictValidator, POST_Restrict);
3031
ClientApiRouter.post("/subscription", ...ClientAuthFlow, POST_SubscriptionValidator, POST_Subscription);
32+
ClientApiRouter.post("/subscription-cancel", ...ClientAuthFlow, POST_SubscriptionCancelValidator, POST_SubscriptionCancel);
3133
ClientApiRouter.get("/block-status", ...ClientAuthFlow, GET_BlockStatusValidator, GET_BlockStatus);
3234
ClientApiRouter.post("/create", ...ClientAuthFlow, POST_CreateValidator, POST_Create);
3335
ClientApiRouter.get("/list", ...ClientAuthFlow, GET_List);
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { Logger } from "../../../../singleton/logger.js";
2+
const log = Logger.getLogger().child({ from: "user/shared/subscription-cancel.post" });
3+
4+
import { Request, Response } from "express";
5+
import moment from "moment";
6+
import { body } from "express-validator";
7+
import { isValidObjectId } from "mongoose";
8+
9+
import { errorMessages, statusCodes } from "../../../../utils/http-status.js";
10+
import { ErrorResponse, SuccessResponse } from "../../../../utils/response.js";
11+
import UserModel from "../../../../model/mongo/user.js";
12+
import { hasErrors } from "../../../../utils/api.js";
13+
import { ScopeManager } from "../../../../singleton/scope-manager.js";
14+
import { flushUserInfoFromRedis } from "../../../../model/oauth/cache.js";
15+
16+
export const POST_SubscriptionCancelValidator = [
17+
body("target").exists().isString().isLength({ max: 64 }).custom(isValidObjectId),
18+
body("cancelled").exists().isBoolean(),
19+
];
20+
21+
const POST_SubscriptionCancel = async (req: Request, res: Response): Promise<void> => {
22+
try {
23+
if (!ScopeManager.isScopeAllowedForSharedSession("<ENTITY>:profile:subscriptions:write", res)) {
24+
return;
25+
}
26+
if (hasErrors(req, res)) return;
27+
28+
const target = req.body.target;
29+
const cancelled = req.body.cancelled;
30+
31+
const query: any = {
32+
$set: {
33+
subscriptionCancelled: cancelled,
34+
},
35+
};
36+
37+
if (cancelled === true) {
38+
query.$set.subscriptionCancelledAt = moment().toDate();
39+
query.$set.isSubscribed = false;
40+
} else {
41+
query.$set.subscriptionCancelledAt = null;
42+
}
43+
44+
await UserModel.updateOne({ _id: target }, query);
45+
res.status(statusCodes.success).json(new SuccessResponse());
46+
flushUserInfoFromRedis(target);
47+
} catch (err) {
48+
log.error(err);
49+
res.status(statusCodes.internalError).json(new ErrorResponse(errorMessages.internalError));
50+
}
51+
};
52+
53+
export default POST_SubscriptionCancel;
54+

src/service/api/user/shared/subscription.post.ts

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ export const POST_SubscriptionValidator = [
1919
body("state").exists().isBoolean(),
2020
body("expiry").optional().isISO8601(),
2121
body("tier").optional().isString().isLength({ max: 128 }),
22-
body("subscriptionIdentifier").optional().custom((value) => typeof value === "string" || typeof value === "number"),
23-
body("cancelled").optional().isBoolean(),
22+
body("subscriptionIdentifier")
23+
.optional()
24+
.custom((value) => typeof value === "string" || typeof value === "number"),
2425
];
2526

2627
const POST_Subscription = async (req: Request, res: Response): Promise<void> => {
@@ -34,8 +35,7 @@ const POST_Subscription = async (req: Request, res: Response): Promise<void> =>
3435
const tier = req.body.tier;
3536
const expiry = req.body.expiry;
3637
const subscriptionIdentifier = req.body.subscriptionIdentifier;
37-
const cancelled = req.body.cancelled;
38-
38+
3939
if (state === true && !expiry) {
4040
const errors = [
4141
{
@@ -66,23 +66,10 @@ const POST_Subscription = async (req: Request, res: Response): Promise<void> =>
6666
subscriptionTier: tier || null,
6767
},
6868
};
69-
if (typeof subscriptionIdentifier !== 'undefined') {
69+
if (typeof subscriptionIdentifier !== "undefined") {
7070
query.$set.subscriptionIdentifier = subscriptionIdentifier;
7171
}
72-
73-
// Handle subscription cancellation
74-
if (typeof cancelled !== 'undefined') {
75-
query.$set.subscriptionCancelled = cancelled;
76-
if (cancelled === true) {
77-
query.$set.subscriptionCancelledAt = moment().toDate();
78-
} else {
79-
query.$set.subscriptionCancelledAt = null;
80-
}
81-
}
82-
if (cancelled) {
83-
query.$set.isSubscribed = false;
84-
query.$set.subscriptionCancelledAt = moment().toDate();
85-
}
72+
8673
await UserModel.updateOne({ _id: target }, query);
8774
res.status(statusCodes.success).json(new SuccessResponse());
8875
flushUserInfoFromRedis(target);

0 commit comments

Comments
 (0)