73 batch sms messaging #85
3 changed files with 46 additions and 8 deletions
20
src/lib/server/twilio/index.ts
Normal file
20
src/lib/server/twilio/index.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import type { TwilioConfig } from '@prisma/client';
|
||||||
|
import { decrypt, encrypt } from '../crypto';
|
||||||
|
|
||||||
|
type TwilioCore = Pick<TwilioConfig, 'accountSID' | 'authToken' | 'phoneNumber'>;
|
||||||
|
|
||||||
|
export function encryptTwilioConfig({ accountSID, authToken, phoneNumber }: TwilioCore) {
|
||||||
|
return {
|
||||||
|
accountSID: encrypt(accountSID),
|
||||||
|
authToken: encrypt(authToken),
|
||||||
|
phoneNumber: encrypt(phoneNumber),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decryptTwilioConfig({ accountSID, authToken, phoneNumber }: TwilioCore) {
|
||||||
|
return {
|
||||||
|
accountSID: decrypt(accountSID),
|
||||||
|
authToken: decrypt(authToken),
|
||||||
|
phoneNumber: decrypt(phoneNumber),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { PhoneRegex } from '$lib/regex';
|
import { PhoneRegex } from '$lib/regex';
|
||||||
import { logger } from '$lib/server/logger';
|
import { logger } from '$lib/server/logger';
|
||||||
import { prisma } from '$lib/server/prisma';
|
import { prisma } from '$lib/server/prisma';
|
||||||
|
import { encryptTwilioConfig, decryptTwilioConfig } from '$lib/server/twilio';
|
||||||
import { fail, type Actions } from '@sveltejs/kit';
|
import { fail, type Actions } from '@sveltejs/kit';
|
||||||
import zod from 'zod';
|
import zod from 'zod';
|
||||||
|
|
||||||
|
|
@ -20,8 +21,16 @@ export const load = async (event) => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!configs) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
configs: configs,
|
configs: {
|
||||||
|
...(configs.twilioConfig && {
|
||||||
|
twilioConfig: decryptTwilioConfig(configs.twilioConfig),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Nah, the page handles this. If the config is missing it displays a message Nah, the page handles this. If the config is missing it displays a message
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -65,28 +74,32 @@ export const actions = {
|
||||||
create: {
|
create: {
|
||||||
tenantId: tenantId,
|
tenantId: tenantId,
|
||||||
twilioConfig: {
|
twilioConfig: {
|
||||||
create: {
|
create: encryptTwilioConfig({
|
||||||
accountSID: accountSID,
|
accountSID: accountSID,
|
||||||
authToken: authToken,
|
authToken: authToken,
|
||||||
phoneNumber: phoneNumber,
|
phoneNumber: phoneNumber,
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
tenantId: tenantId,
|
tenantId: tenantId,
|
||||||
twilioConfig: {
|
twilioConfig: {
|
||||||
update: {
|
update: encryptTwilioConfig({
|
||||||
accountSID: accountSID,
|
accountSID: accountSID,
|
||||||
authToken: authToken,
|
authToken: authToken,
|
||||||
phoneNumber: phoneNumber,
|
phoneNumber: phoneNumber,
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
select: { twilioConfig: true },
|
select: { twilioConfig: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
configs: configs,
|
configs: {
|
||||||
|
...(configs.twilioConfig && {
|
||||||
|
twilioConfig: decryptTwilioConfig(configs.twilioConfig),
|
||||||
|
}),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
} satisfies Actions;
|
} satisfies Actions;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import type { Recipient } from '$lib/components/SMS';
|
import type { Recipient } from '$lib/components/SMS';
|
||||||
import { logger } from '$lib/server/logger';
|
import { logger } from '$lib/server/logger';
|
||||||
import { prisma } from '$lib/server/prisma/index.js';
|
import { prisma } from '$lib/server/prisma/index.js';
|
||||||
|
import { decryptTwilioConfig } from '$lib/server/twilio/index.js';
|
||||||
import { fail, type Actions } from '@sveltejs/kit';
|
import { fail, type Actions } from '@sveltejs/kit';
|
||||||
import twilio from 'twilio';
|
import twilio from 'twilio';
|
||||||
import zod from 'zod';
|
import zod from 'zod';
|
||||||
|
|
@ -24,6 +25,8 @@ export const load = async (event) => {
|
||||||
const { success, error: validationError } = zod
|
const { success, error: validationError } = zod
|
||||||
.object({
|
.object({
|
||||||
accountSID: zod.string(),
|
accountSID: zod.string(),
|
||||||
|
authToken: zod.string(),
|
||||||
|
phoneNumber: zod.string(),
|
||||||
})
|
})
|
||||||
.safeParse(configs?.twilioConfig);
|
.safeParse(configs?.twilioConfig);
|
||||||
|
|
||||||
|
|
@ -84,14 +87,16 @@ export const actions = {
|
||||||
return fail(307, { error: 'no_twilio_config' });
|
return fail(307, { error: 'no_twilio_config' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = twilio(config.accountSID, config.authToken);
|
const decryptedConfig = decryptTwilioConfig(config);
|
||||||
|
|
||||||
|
const client = twilio(decryptedConfig.accountSID, decryptedConfig.authToken);
|
||||||
|
|
||||||
for (const recipient of recipients) {
|
for (const recipient of recipients) {
|
||||||
try {
|
try {
|
||||||
const result = await client.messages.create({
|
const result = await client.messages.create({
|
||||||
to: recipient.phone,
|
to: recipient.phone,
|
||||||
body: message,
|
body: message,
|
||||||
from: config.phoneNumber,
|
from: decryptedConfig.phoneNumber,
|
||||||
});
|
});
|
||||||
logger.debug(result);
|
logger.debug(result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue
Should return something; maybe an error page redirect