Skip to content

Commit 16648dd

Browse files
authored
Merge pull request #68 from GeneralMagicio/thank-you-cast-release
Thank you cast release
2 parents 17f7847 + 2cb4574 commit 16648dd

File tree

4 files changed

+144
-3
lines changed

4 files changed

+144
-3
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE "FarcasterConnection" ADD COLUMN "thankYouCastSent" BOOLEAN DEFAULT FALSE;

prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ model FarcasterConnection {
180180
createdAt DateTime @default(now()) @map("created_at")
181181
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
182182
user User @relation(fields: [userId], references: [id])
183+
thankYouCastSent Boolean @default(false)
183184
}
184185

185186
model WorldIdConnection {

src/cronJobs.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { schedule } from 'node-cron';
2-
import { sendDailyCasts } from './neynar/utils';
2+
import {
3+
sendDailyDelegationCasts,
4+
sendDailyThankYouCast,
5+
} from './neynar/utils';
36

47
const sendCastsCronJobTime = '21 1 22 * * *'; // at 22:01 Tehran time every day
58

@@ -12,7 +15,8 @@ const sendCastsCronJob = () => {
1215
sendCastsCronJobTime,
1316
async () => {
1417
try {
15-
await sendDailyCasts();
18+
await sendDailyDelegationCasts();
19+
await sendDailyThankYouCast();
1620
} catch (e) {
1721
console.error('sendCastsCronJob error', e);
1822
}

src/neynar/utils.ts

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,141 @@ import { PrismaClient } from '@prisma/client';
22
import { FarcasterMetadata } from 'src/flow/types';
33
import neynarClient from './neynarClient';
44

5+
const findMaxiUsers = async () => {
6+
const prisma = new PrismaClient({
7+
datasources: {
8+
db: {
9+
url: process.env.POSTGRES_PRISMA_URL,
10+
},
11+
},
12+
});
13+
14+
await prisma.$connect();
15+
16+
const collectionCategories = await prisma.project.findMany({
17+
where: {
18+
type: 'collection',
19+
},
20+
select: {
21+
id: true,
22+
},
23+
});
24+
const collectionCategoryIds = collectionCategories.map(
25+
(category) => category.id,
26+
);
27+
28+
const farcasterConnections = await prisma.farcasterConnection.findMany({
29+
where: {
30+
thankYouCastSent: false,
31+
},
32+
select: {
33+
userId: true,
34+
},
35+
});
36+
37+
const userIdsWithFarcaster = farcasterConnections.map(
38+
(connection) => connection.userId,
39+
);
40+
41+
// Find users who have delegated or attested to all categories (Collection + Budget)
42+
const maxiUsers = await prisma.user.findMany({
43+
where: {
44+
id: { in: userIdsWithFarcaster },
45+
// Check that the user has attested or delegated to the Budget category
46+
OR: [
47+
{
48+
budgetAttestations: {
49+
some: {},
50+
},
51+
},
52+
{
53+
budgetDelegation: {
54+
isNot: null,
55+
},
56+
},
57+
],
58+
// Ensure the user has attested or delegated to all Collection categories
59+
AND: [
60+
{
61+
AND: collectionCategoryIds.map((categoryId) => ({
62+
OR: [
63+
{
64+
attestations: {
65+
some: {
66+
collectionId: categoryId,
67+
},
68+
},
69+
},
70+
{
71+
delegations: {
72+
some: {
73+
collectionId: categoryId,
74+
},
75+
},
76+
},
77+
],
78+
})),
79+
},
80+
],
81+
},
82+
select: {
83+
farcasterConnection: {
84+
select: {
85+
userId: true,
86+
metadata: true,
87+
},
88+
},
89+
},
90+
});
91+
return maxiUsers.map((user) => user.farcasterConnection);
92+
};
93+
94+
const sendThankYouCast = async (username: string) => {
95+
if (!farcasterSignerUUID) {
96+
throw new Error(
97+
'Make sure you set FARCASTER_SIGNER_UUID in your .env file',
98+
);
99+
}
100+
await neynarClient.publishCast(
101+
farcasterSignerUUID,
102+
`@${username}! Thank you for playing with Pairwise!
103+
104+
YOU ROCK!`,
105+
);
106+
console.log(`The Thanks you Cast successfully sent to @${username}`);
107+
};
108+
109+
const updateThankYouCastSent = async (userId?: number) => {
110+
if (!userId) return;
111+
const prisma = new PrismaClient({
112+
datasources: {
113+
db: {
114+
url: process.env.POSTGRES_PRISMA_URL,
115+
},
116+
},
117+
});
118+
await prisma.farcasterConnection.update({
119+
where: { userId },
120+
data: { thankYouCastSent: true },
121+
});
122+
await prisma.$disconnect();
123+
};
124+
125+
export const sendDailyThankYouCast = async () => {
126+
const maxiUsers = await findMaxiUsers();
127+
if (!maxiUsers || maxiUsers.length === 0) return;
128+
for (const user of maxiUsers) {
129+
try {
130+
await sendThankYouCast(
131+
(user?.metadata?.valueOf() as FarcasterMetadata)['username'],
132+
);
133+
await updateThankYouCastSent(user?.userId);
134+
} catch (e) {
135+
console.error('Error sending Thank you cast for user ID: ', user?.userId);
136+
}
137+
}
138+
};
139+
5140
/**
6141
* Returns an array of `{fid, username, totalDelegates}` mapping in which `totalDelegates` is
7142
* the number of times that another user has delegated to this specific username/fid
@@ -77,7 +212,7 @@ export const getDelegations = async (start: number, end?: number) => {
77212
return result;
78213
};
79214

80-
export const sendDailyCasts = async () => {
215+
export const sendDailyDelegationCasts = async () => {
81216
const endTimestamp = new Date();
82217
endTimestamp.setMinutes(0, 0, 0); // set to xx:00:00
83218
const delegations = await getDelegations(

0 commit comments

Comments
 (0)