Skip to content

Commit a25d77d

Browse files
committed
store sponsorship amounts in database
1 parent 15baa58 commit a25d77d

8 files changed

Lines changed: 278 additions & 17 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "bot-rs"
3-
version = "0.4.3"
3+
version = "0.5.0"
44
edition = "2024"
55

66
[dependencies]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE `sent_sponsorships` ADD `github_id` integer;--> statement-breakpoint
2+
ALTER TABLE `sent_sponsorships` ADD `amount` integer;
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
{
2+
"version": "6",
3+
"dialect": "sqlite",
4+
"id": "fc00cffa-02d0-4cad-9be0-da814701df23",
5+
"prevId": "f76c90c7-2782-4335-9d53-3bea7c2a769a",
6+
"tables": {
7+
"github_messages": {
8+
"name": "github_messages",
9+
"columns": {
10+
"id": {
11+
"name": "id",
12+
"type": "integer",
13+
"primaryKey": true,
14+
"notNull": true,
15+
"autoincrement": false
16+
},
17+
"repository_id": {
18+
"name": "repository_id",
19+
"type": "integer",
20+
"primaryKey": false,
21+
"notNull": true,
22+
"autoincrement": false
23+
},
24+
"message_id": {
25+
"name": "message_id",
26+
"type": "integer",
27+
"primaryKey": false,
28+
"notNull": true,
29+
"autoincrement": false
30+
},
31+
"commits": {
32+
"name": "commits",
33+
"type": "text",
34+
"primaryKey": false,
35+
"notNull": true,
36+
"autoincrement": false
37+
},
38+
"branch": {
39+
"name": "branch",
40+
"type": "text",
41+
"primaryKey": false,
42+
"notNull": true,
43+
"autoincrement": false,
44+
"default": "''"
45+
},
46+
"workflow_sha": {
47+
"name": "workflow_sha",
48+
"type": "text",
49+
"primaryKey": false,
50+
"notNull": true,
51+
"autoincrement": false
52+
},
53+
"workflow_status": {
54+
"name": "workflow_status",
55+
"type": "text",
56+
"primaryKey": false,
57+
"notNull": true,
58+
"autoincrement": false
59+
},
60+
"created": {
61+
"name": "created",
62+
"type": "integer",
63+
"primaryKey": false,
64+
"notNull": true,
65+
"autoincrement": false,
66+
"default": "(strftime('%s','now'))"
67+
}
68+
},
69+
"indexes": {
70+
"github_messages_repository_id_idx": {
71+
"name": "github_messages_repository_id_idx",
72+
"columns": [
73+
"repository_id"
74+
],
75+
"isUnique": false
76+
}
77+
},
78+
"foreignKeys": {},
79+
"compositePrimaryKeys": {},
80+
"uniqueConstraints": {},
81+
"checkConstraints": {}
82+
},
83+
"sent_sponsorships": {
84+
"name": "sent_sponsorships",
85+
"columns": {
86+
"id": {
87+
"name": "id",
88+
"type": "text",
89+
"primaryKey": true,
90+
"notNull": true,
91+
"autoincrement": false
92+
},
93+
"github_id": {
94+
"name": "github_id",
95+
"type": "integer",
96+
"primaryKey": false,
97+
"notNull": false,
98+
"autoincrement": false
99+
},
100+
"amount": {
101+
"name": "amount",
102+
"type": "integer",
103+
"primaryKey": false,
104+
"notNull": false,
105+
"autoincrement": false
106+
},
107+
"created": {
108+
"name": "created",
109+
"type": "integer",
110+
"primaryKey": false,
111+
"notNull": true,
112+
"autoincrement": false,
113+
"default": "(strftime('%s','now'))"
114+
}
115+
},
116+
"indexes": {
117+
"sent_sponsorships_created_idx": {
118+
"name": "sent_sponsorships_created_idx",
119+
"columns": [
120+
"created"
121+
],
122+
"isUnique": false
123+
}
124+
},
125+
"foreignKeys": {},
126+
"compositePrimaryKeys": {},
127+
"uniqueConstraints": {},
128+
"checkConstraints": {}
129+
},
130+
"text_messages": {
131+
"name": "text_messages",
132+
"columns": {
133+
"id": {
134+
"name": "id",
135+
"type": "integer",
136+
"primaryKey": true,
137+
"notNull": true,
138+
"autoincrement": false
139+
},
140+
"channel_id": {
141+
"name": "channel_id",
142+
"type": "integer",
143+
"primaryKey": false,
144+
"notNull": true,
145+
"autoincrement": false
146+
},
147+
"message_id": {
148+
"name": "message_id",
149+
"type": "integer",
150+
"primaryKey": false,
151+
"notNull": false,
152+
"autoincrement": false
153+
},
154+
"title": {
155+
"name": "title",
156+
"type": "text",
157+
"primaryKey": false,
158+
"notNull": true,
159+
"autoincrement": false
160+
},
161+
"content": {
162+
"name": "content",
163+
"type": "text",
164+
"primaryKey": false,
165+
"notNull": true,
166+
"autoincrement": false
167+
},
168+
"roles": {
169+
"name": "roles",
170+
"type": "text",
171+
"primaryKey": false,
172+
"notNull": true,
173+
"autoincrement": false
174+
},
175+
"created": {
176+
"name": "created",
177+
"type": "integer",
178+
"primaryKey": false,
179+
"notNull": true,
180+
"autoincrement": false,
181+
"default": "(strftime('%s','now'))"
182+
}
183+
},
184+
"indexes": {
185+
"text_messages_message_id_idx": {
186+
"name": "text_messages_message_id_idx",
187+
"columns": [
188+
"message_id"
189+
],
190+
"isUnique": true,
191+
"where": "\"text_messages\".\"message_id\" is not null"
192+
}
193+
},
194+
"foreignKeys": {},
195+
"compositePrimaryKeys": {},
196+
"uniqueConstraints": {},
197+
"checkConstraints": {}
198+
}
199+
},
200+
"views": {},
201+
"enums": {},
202+
"_meta": {
203+
"schemas": {},
204+
"tables": {},
205+
"columns": {}
206+
},
207+
"internal": {
208+
"indexes": {}
209+
}
210+
}

database/migrations/meta/_journal.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@
2222
"when": 1782768933179,
2323
"tag": "0002_chief_dracula",
2424
"breakpoints": true
25+
},
26+
{
27+
"idx": 3,
28+
"version": "6",
29+
"when": 1782769373763,
30+
"tag": "0003_brown_talkback",
31+
"breakpoints": true
2532
}
2633
]
2734
}

database/src/schema.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ export const textMessages = sqliteTable('text_messages', {
3535

3636
export const sentSponsorships = sqliteTable('sent_sponsorships', {
3737
id: text('id').primaryKey().notNull(),
38+
39+
githubId: integer('github_id'),
40+
amount: integer('amount'),
41+
3842
created: integer('created', { mode: 'timestamp' }).default(sql`(strftime('%s','now'))`).notNull(),
3943
}, (sentSponsorships) => [
4044
index('sent_sponsorships_created_idx').on(sentSponsorships.created)

src/models/sent_sponsorship.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@ use sqlx::{FromRow, Row, sqlite::SqliteRow};
33
#[derive(Debug)]
44
pub struct SentSponsorship {
55
pub id: String,
6+
pub github_id: Option<i64>,
7+
pub amount: Option<i64>,
68
pub created: Option<chrono::DateTime<chrono::Utc>>,
79
}
810

911
impl FromRow<'_, SqliteRow> for SentSponsorship {
1012
fn from_row(row: &SqliteRow) -> sqlx::Result<Self> {
1113
Ok(Self {
1214
id: row.try_get("id")?,
15+
github_id: row.try_get("github_id")?,
16+
amount: row.try_get("amount")?,
1317
created: row
1418
.try_get::<Option<i64>, _>("created")?
1519
.and_then(|c| chrono::DateTime::<chrono::Utc>::from_timestamp(c, 0)),
@@ -33,15 +37,37 @@ pub async fn find_sent_sponsorship(
3337
pub async fn insert_sent_sponsorship(
3438
pool: &sqlx::SqlitePool,
3539
id: &str,
40+
github_id: Option<i64>,
41+
amount: Option<i64>,
3642
created: Option<chrono::DateTime<chrono::Utc>>,
3743
) -> Result<(), anyhow::Error> {
38-
sqlx::query("INSERT INTO sent_sponsorships (id, created) VALUES (?, ?)")
44+
sqlx::query(
45+
"INSERT INTO sent_sponsorships (id, github_id, amount, created) VALUES (?, ?, ?, ?)",
46+
)
47+
.bind(id)
48+
.bind(github_id)
49+
.bind(amount)
50+
.bind(
51+
created
52+
.map(|c| c.timestamp())
53+
.unwrap_or_else(|| chrono::Utc::now().timestamp()),
54+
)
55+
.execute(pool)
56+
.await?;
57+
58+
Ok(())
59+
}
60+
61+
pub async fn backfill_sent_sponsorship(
62+
pool: &sqlx::SqlitePool,
63+
id: &str,
64+
github_id: Option<i64>,
65+
amount: Option<i64>,
66+
) -> Result<(), anyhow::Error> {
67+
sqlx::query("UPDATE sent_sponsorships SET github_id = ?, amount = ? WHERE id = ?")
68+
.bind(github_id)
69+
.bind(amount)
3970
.bind(id)
40-
.bind(
41-
created
42-
.map(|c| c.timestamp())
43-
.unwrap_or_else(|| chrono::Utc::now().timestamp()),
44-
)
4571
.execute(pool)
4672
.await?;
4773

src/sponsors.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use serenity::all::{
88
#[derive(Deserialize, Serialize)]
99
#[serde(rename_all = "camelCase")]
1010
pub struct GitHubSponsor {
11+
pub database_id: Option<i64>,
1112
pub login: String,
1213
pub name: Option<String>,
1314
pub avatar_url: String,
@@ -80,12 +81,14 @@ fn graphql_query(env: &crate::env::Env, after: Option<&str>) -> String {
8081
}}
8182
sponsor {{
8283
... on User {{
84+
databaseId
8385
login
8486
avatarUrl
8587
name
8688
url
8789
}}
8890
... on Organization {{
91+
databaseId
8992
login
9093
avatarUrl
9194
name
@@ -156,10 +159,26 @@ pub fn spawn_sponsor_updates_task(state: crate::routes::State) {
156159
let sponsors = collect_sponsors(&state.env).await?;
157160

158161
for sponsor in sponsors {
162+
let amount_in_cents = sponsor
163+
.sponsors_tier
164+
.as_ref()
165+
.map(|t| t.monthly_price_in_cents as i64);
166+
let monthly_price_in_dollars = amount_in_cents.unwrap_or(0) as f64 / 100.0;
167+
159168
if let Ok(sponsorship) =
160169
crate::models::find_sent_sponsorship(state.database.read(), &sponsor.id)
161170
.await
162171
{
172+
if sponsorship.github_id.is_none() && sponsorship.amount.is_none() {
173+
crate::models::backfill_sent_sponsorship(
174+
state.database.write(),
175+
&sponsor.id,
176+
sponsor.sponsor.database_id,
177+
amount_in_cents,
178+
)
179+
.await?;
180+
}
181+
163182
tracing::debug!(
164183
"sponsorship {} already sent (from: {:?})",
165184
sponsorship.id,
@@ -168,15 +187,6 @@ pub fn spawn_sponsor_updates_task(state: crate::routes::State) {
168187
continue;
169188
}
170189

171-
let monthly_price_in_dollars = sponsor
172-
.sponsors_tier
173-
.unwrap_or(GitHubSponsorsTier {
174-
monthly_price_in_cents: 0,
175-
})
176-
.monthly_price_in_cents
177-
as f64
178-
/ 100.0;
179-
180190
tracing::info!(
181191
"new sponsor: {} ({}), tier: ${:.2}",
182192
sponsor.sponsor.login,
@@ -245,6 +255,8 @@ pub fn spawn_sponsor_updates_task(state: crate::routes::State) {
245255
crate::models::insert_sent_sponsorship(
246256
state.database.write(),
247257
&sponsor.id,
258+
sponsor.sponsor.database_id,
259+
amount_in_cents,
248260
Some(sponsor.timestamp),
249261
)
250262
.await?;

0 commit comments

Comments
 (0)