@@ -2,14 +2,22 @@ import {
22 UpdateItemCommand ,
33 type DynamoDBClient ,
44} from "@aws-sdk/client-dynamodb" ;
5+ import { Redis , ValidLoggers } from "api/types.js" ;
56import { genericConfig } from "common/config.js" ;
7+ import { createLock , IoredisAdapter } from "redlock-universal" ;
8+ import { createStripeCustomer } from "./stripe.js" ;
9+ import { InternalServerError } from "common/errors/index.js" ;
10+ import { unmarshall } from "@aws-sdk/util-dynamodb" ;
611
712export interface SyncFullProfileInputs {
813 uinHash : string ;
914 netId : string ;
1015 firstName : string ;
1116 lastName : string ;
1217 dynamoClient : DynamoDBClient ;
18+ redisClient : Redis ;
19+ stripeApiKey : string ;
20+ logger : ValidLoggers ;
1321}
1422
1523export async function syncFullProfile ( {
@@ -18,29 +26,85 @@ export async function syncFullProfile({
1826 firstName,
1927 lastName,
2028 dynamoClient,
29+ redisClient,
30+ stripeApiKey,
31+ logger,
2132} : SyncFullProfileInputs ) {
22- return dynamoClient . send (
23- new UpdateItemCommand ( {
24- TableName : genericConfig . UserInfoTable ,
25- Key : {
26- id : { S : `${ netId } @illinois.edu` } ,
27- } ,
28- UpdateExpression :
29- "SET #uinHash = :uinHash, #netId = :netId, #updatedAt = :updatedAt, #firstName = :firstName, #lastName = :lastName" ,
30- ExpressionAttributeNames : {
31- "#uinHash" : "uinHash" ,
32- "#netId" : "netId" ,
33- "#updatedAt" : "updatedAt" ,
34- "#firstName" : "firstName" ,
35- "#lastName" : "lastName" ,
36- } ,
37- ExpressionAttributeValues : {
38- ":uinHash" : { S : uinHash } ,
39- ":netId" : { S : netId } ,
40- ":firstName" : { S : firstName } ,
41- ":lastName" : { S : lastName } ,
42- ":updatedAt" : { S : new Date ( ) . toISOString ( ) } ,
43- } ,
44- } ) ,
45- ) ;
33+ const lock = createLock ( {
34+ adapter : new IoredisAdapter ( redisClient ) ,
35+ key : `userSync:${ netId } ` ,
36+ retryAttempts : 5 ,
37+ retryDelay : 300 ,
38+ } ) ;
39+
40+ return await lock . using ( async ( signal ) => {
41+ const userId = `${ netId } @illinois.edu` ;
42+ const updateResult = await dynamoClient . send (
43+ new UpdateItemCommand ( {
44+ TableName : genericConfig . UserInfoTable ,
45+ Key : {
46+ id : { S : userId } ,
47+ } ,
48+ UpdateExpression :
49+ "SET #uinHash = :uinHash, #netId = :netId, #updatedAt = :updatedAt, #firstName = :firstName, #lastName = :lastName" ,
50+ ExpressionAttributeNames : {
51+ "#uinHash" : "uinHash" ,
52+ "#netId" : "netId" ,
53+ "#updatedAt" : "updatedAt" ,
54+ "#firstName" : "firstName" ,
55+ "#lastName" : "lastName" ,
56+ } ,
57+ ExpressionAttributeValues : {
58+ ":uinHash" : { S : uinHash } ,
59+ ":netId" : { S : netId } ,
60+ ":firstName" : { S : firstName } ,
61+ ":lastName" : { S : lastName } ,
62+ ":updatedAt" : { S : new Date ( ) . toISOString ( ) } ,
63+ } ,
64+ ReturnValues : "ALL_NEW" ,
65+ } ) ,
66+ ) ;
67+
68+ const stripeCustomerId = updateResult . Attributes ?. stripeCustomerId ?. S ;
69+
70+ if ( ! stripeCustomerId ) {
71+ if ( signal . aborted ) {
72+ throw new InternalServerError ( {
73+ message :
74+ "Checked on lock before creating Stripe customer, we've lost the lock!" ,
75+ } ) ;
76+ }
77+ const newStripeCustomerId = await createStripeCustomer ( {
78+ email : userId ,
79+ name : `${ firstName } ${ lastName } ` ,
80+ stripeApiKey,
81+ } ) ;
82+ logger . info ( `Created new Stripe customer for ${ userId } .` ) ;
83+ const newInfo = await dynamoClient . send (
84+ new UpdateItemCommand ( {
85+ TableName : genericConfig . UserInfoTable ,
86+ Key : {
87+ id : { S : userId } ,
88+ } ,
89+ UpdateExpression : "SET #stripeCustomerId = :stripeCustomerId" ,
90+ ExpressionAttributeNames : {
91+ "#stripeCustomerId" : "stripeCustomerId" ,
92+ } ,
93+ ExpressionAttributeValues : {
94+ ":stripeCustomerId" : { S : newStripeCustomerId } ,
95+ } ,
96+ ReturnValues : "ALL_NEW" ,
97+ } ) ,
98+ ) ;
99+ return newInfo && newInfo . Attributes
100+ ? unmarshall ( newInfo . Attributes )
101+ : updateResult && updateResult . Attributes
102+ ? unmarshall ( updateResult . Attributes )
103+ : undefined ;
104+ }
105+
106+ return updateResult && updateResult . Attributes
107+ ? unmarshall ( updateResult . Attributes )
108+ : undefined ;
109+ } ) ;
46110}
0 commit comments