-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathpostHandler.js
More file actions
149 lines (129 loc) · 4.76 KB
/
postHandler.js
File metadata and controls
149 lines (129 loc) · 4.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import { PutCommand, UpdateCommand } from '@aws-sdk/lib-dynamodb'
import { ddb, TABLE_NAME, createResponse, billingCycles } from './utils.js'
import { getPlan, getUserSubscription } from './getHandler.js'
import { AppError } from './error.js'
const SubEvents = Object.freeze({
CREATED: 'subscription.created',
RENEWED: 'subscription.renewed',
CANCELED: 'subscription.cancelled'
})
const createSubscription = async (body)=>{
const { userId, subscriptionId, expiresAt, metadata, timestamp } = body
if( !userId || !subscriptionId || !expiresAt || !metadata || !timestamp ){
throw new AppError(400, `Missing required fields`)
}
if( !metadata.planSku ){
throw new AppError(400, `Missing metadata fields`)
}
const { planSku } = metadata
//validate user has no subscription
const subscription = await getUserSubscription(userId)
if(Object.keys(subscription).length > 0){
throw new AppError(400, 'User has an active subscription')
}
//validate requested plan is not inactive
const plan = await getPlan(planSku)
if(Object.keys(plan).length === 0){
throw new AppError(400, `Requested plan don't exist or is inactive`)
}
//create item
const newSubscription = {
pk: `user_${userId}`,
sk: `${subscriptionId}`,
type: 'sub',
planSku,
startDate: timestamp,
expiresAt,
canceledAt: '',
lastModifiedAt: new Date().toISOString(),
attributes: metadata,
status: 'ACTIVE'
}
await ddb.send(new PutCommand({
TableName: TABLE_NAME,
Item: newSubscription
}))
return newSubscription
}
const cancelSubscription = async(body)=>{
const { userId, subscriptionId, expiresAt } = body
if(!userId || !subscriptionId){
throw new AppError(400, 'Missing required fields')
}
//validate subscription exists
const subscription = await getUserSubscription(userId, subscriptionId)
if(Object.keys(subscription).length === 0){
throw new AppError(400, 'User has no active subscription')
}
//update subscription status
const now = new Date()
const expireDate = new Date(expiresAt)
const updateParams = {
TableName: TABLE_NAME,
Key: { pk: `user_${userId}`, sk: subscriptionId },
UpdateExpression: `
SET canceledAt = :canceledAt,
lastModifiedAt = :lastModifiedAt,
#st = :status
`,
ExpressionAttributeNames: {"#st" : "status"},
ExpressionAttributeValues: {
":canceledAt": now.toISOString(),
":lastModifiedAt": now.toISOString(),
":status": now < expireDate ? 'PENDING' : 'CANCELED'
},
ConditionExpression: "attribute_exists(pk) AND attribute_exists(sk)",
ReturnValues: "ALL_NEW"
}
const response = await ddb.send(new UpdateCommand(updateParams))
return response
}
const renewSubscription = async(body) =>{
const { userId, subscriptionId, expiresAt } = body
//validate subscription exists
if(!userId || !subscriptionId){
return createResponse(400, {message: 'Missing required fields'})
}
const subscription = await getUserSubscription(userId, subscriptionId, true)
if(Object.keys(subscription).length === 0){
throw new AppError(400, 'Subscription not found')
}
//update subscription status
const now = new Date().toISOString()
const updateParams = {
TableName: TABLE_NAME,
Key: { pk: `user_${userId}`, sk: subscriptionId },
UpdateExpression: `
SET lastModifiedAt = :lastModifiedAt,
expiresAt = :expiresAt,
canceledAt = :canceledAt,
#st = :status
`,
ExpressionAttributeNames: {"#st" : "status"},
ExpressionAttributeValues: {
":lastModifiedAt": now,
":expiresAt": expiresAt,
":status": 'ACTIVE',
":canceledAt": ''
},
ConditionExpression: "attribute_exists(pk) AND attribute_exists(sk)",
ReturnValues: "ALL_NEW"
}
const response = await ddb.send(new UpdateCommand(updateParams))
return response
}
export const postHandler = async({ eventType, parsedBody })=>{
switch(eventType){
case SubEvents.CREATED:
const createdResponse = await createSubscription(parsedBody)
return createdResponse
case SubEvents.CANCELED:
const canceledResponse = await cancelSubscription(parsedBody)
return canceledResponse.Attributes
case SubEvents.RENEWED:
const renewedResponse = await renewSubscription(parsedBody)
return renewedResponse.Attributes
default:
throw new AppError(400, 'Invalid post event')
}
}