157 lines
4.4 KiB
TypeScript
157 lines
4.4 KiB
TypeScript
import config from "./config.ts";
|
|
import { getUserByEmail } from "./utils/firebase.ts";
|
|
import { insertObject, newPostgres, updateObject } from "./utils/postgres.ts";
|
|
import { getAllActiveSubscriptions, getAllCustomers } from "./utils/stripe.ts";
|
|
import { Client as DiscordClient, IntentsBitField } from "discord.js";
|
|
|
|
let lastSubs = "";
|
|
let currentSubs = "";
|
|
|
|
const postgres2 = newPostgres();
|
|
|
|
// set up the Discord admin bot
|
|
const discordBot = new DiscordClient({
|
|
intents: [IntentsBitField.Flags.Guilds, IntentsBitField.Flags.GuildMembers],
|
|
});
|
|
if (config.DISCORD_ADMIN_BOT_TOKEN) {
|
|
discordBot.login(config.DISCORD_ADMIN_BOT_TOKEN);
|
|
// discordBot.once('ready', () => {
|
|
// console.log(`Discord Bot "${discordBot?.user?.username}" ready`);
|
|
// });
|
|
}
|
|
if (process.env.NODE_ENV === "development") {
|
|
setTimeout(syncSubscribers, 1000);
|
|
}
|
|
|
|
setInterval(syncSubscribers, 60 * 1000);
|
|
|
|
async function syncSubscribers() {
|
|
if (!config.STRIPE_SECRET_KEY || !config.FIREBASE_ADMIN_SDK_CONFIG) {
|
|
return;
|
|
}
|
|
console.time("syncSubscribers");
|
|
// Fetch subs, customers from stripe
|
|
const [subs, customers] = await Promise.all([
|
|
getAllActiveSubscriptions(),
|
|
getAllCustomers(),
|
|
]);
|
|
|
|
const emailMap = new Map();
|
|
customers.forEach((cust) => {
|
|
emailMap.set(cust.id, cust.email);
|
|
});
|
|
|
|
console.log("%s subs in Stripe", subs.length);
|
|
|
|
const uidMap = new Map();
|
|
for (let i = 0; i < subs.length; i += 50) {
|
|
// Batch customers and fetch firebase data
|
|
const batch = subs.slice(i, i + 50);
|
|
const fbUsers = await Promise.all(
|
|
batch
|
|
.map((sub) =>
|
|
emailMap.get(sub.customer)
|
|
? getUserByEmail(emailMap.get(sub.customer))
|
|
: null,
|
|
)
|
|
.filter(Boolean),
|
|
);
|
|
fbUsers.forEach((user) => {
|
|
uidMap.set(user?.email, user?.uid);
|
|
});
|
|
}
|
|
|
|
let noUID = 0;
|
|
// Create sub objects
|
|
let result = subs
|
|
.map((sub) => {
|
|
let uid = uidMap.get(emailMap.get(sub.customer));
|
|
if (!uid) {
|
|
uid = emailMap.get(sub.customer);
|
|
noUID += 1;
|
|
}
|
|
return {
|
|
customerId: sub.customer,
|
|
email: emailMap.get(sub.customer),
|
|
status: sub.status,
|
|
uid,
|
|
};
|
|
})
|
|
.filter((sub) => sub.uid);
|
|
console.log("%s subs to insert", result.length);
|
|
console.log("%s subs do not have UID, using email", noUID);
|
|
|
|
const newResult = result.filter(
|
|
(sub, index) =>
|
|
index === result.findIndex((other) => sub.uid === other.uid),
|
|
);
|
|
console.log("%s deduped subs to insert", newResult.length);
|
|
if (result.length !== newResult.length) {
|
|
// Log the difference
|
|
console.log(result.filter((x) => !newResult.includes(x)));
|
|
}
|
|
result = newResult;
|
|
|
|
currentSubs = result
|
|
.map((sub) => sub.uid)
|
|
.sort()
|
|
.join();
|
|
|
|
// Upsert to DB
|
|
// console.log(result);
|
|
if (currentSubs !== lastSubs) {
|
|
try {
|
|
await postgres2?.query("BEGIN TRANSACTION");
|
|
await postgres2?.query("DELETE FROM subscriber");
|
|
await postgres2?.query('UPDATE room SET "isSubRoom" = false');
|
|
for (let row of result) {
|
|
await insertObject(postgres2, "subscriber", row);
|
|
await updateObject(
|
|
postgres2,
|
|
"room",
|
|
{ isSubRoom: true },
|
|
{ owner: row.uid },
|
|
);
|
|
}
|
|
await postgres2?.query("COMMIT");
|
|
lastSubs = currentSubs;
|
|
} catch (e) {
|
|
console.error(e);
|
|
await postgres2?.query("ROLLBACK");
|
|
}
|
|
}
|
|
if (
|
|
discordBot.isReady() &&
|
|
config.DISCORD_ADMIN_BOT_SERVER_ID &&
|
|
config.DISCORD_ADMIN_BOT_SUB_ROLE_ID
|
|
) {
|
|
console.log("setting discord roles");
|
|
// Update the sub status of users in Discord
|
|
// Join the current subs with linked accounts
|
|
const guild = discordBot.guilds.cache.get(
|
|
config.DISCORD_ADMIN_BOT_SERVER_ID,
|
|
);
|
|
const role = guild?.roles.cache.get(config.DISCORD_ADMIN_BOT_SUB_ROLE_ID);
|
|
const toUpdate = (
|
|
await postgres2.query(
|
|
`SELECT la.accountid from subscriber JOIN link_account la ON subscriber.uid = la.uid WHERE la.kind = 'discord'`,
|
|
)
|
|
).rows;
|
|
console.log("%s users to set sub role", toUpdate.length);
|
|
for (let row of toUpdate) {
|
|
try {
|
|
const user = await guild?.members.fetch(row.accountid);
|
|
if (user && role) {
|
|
console.log("assigning role %s to user %s", role, user.id);
|
|
|
|
await user.roles.add(role);
|
|
}
|
|
} catch (e: any) {
|
|
console.log(e.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
console.timeEnd("syncSubscribers");
|
|
}
|