···99import {
1010 Bindings, BskyEmbedWrapper, BskyRecordWrapper, EmbedData, EmbedDataType,
1111 LooseObj, Post, PostLabel, AccountStatus,
1212- PostRecordResponse, PostStatus, Repost, ScheduledContext
1212+ PostRecordResponse, PostStatus, Repost, ScheduledContext,
1313+ AllContext
1314} from '../types.d';
1415import { atpRecordURI } from '../validation/regexCases';
1516import { bulkUpdatePostedData, getChildPostsOfThread, isPostAlreadyPosted, setPostNowOffForPost } from './db/data';
···104105 return AccountStatus.UnhandledError;
105106}
106107107107-export const makeAgentForUser = async (env: Bindings, userId: string) => {
108108- const loginCreds = await getBskyUserPassForId(env, userId);
108108+export const makeAgentForUser = async (c: AllContext, userId: string) => {
109109+ const loginCreds = await getBskyUserPassForId(c, userId);
109110 if (loginCreds.valid === false) {
110111 console.error(`credentials for user ${userId} were invalid`);
111112 return null;
···116117117118 const loginResponse: AccountStatus = await loginToBsky(agent, username, password);
118119 if (loginResponse != AccountStatus.Ok) {
119119- const addViolation: boolean = await createViolationForUser(env, userId, loginResponse);
120120+ const addViolation: boolean = await createViolationForUser(c, userId, loginResponse);
120121 if (addViolation)
121122 console.error(`Unable to login to ${userId} with violation ${loginResponse}`);
122123 return null;
···124125 return agent;
125126}
126127127127-export const makePost = async (c: Context|ScheduledContext, content: Post|null, usingAgent: AtpAgent|null=null) => {
128128+export const makePost = async (c: AllContext, content: Post|null, usingAgent: AtpAgent|null=null) => {
128129 if (content === null) {
129130 console.warn("Dropping invocation of makePost, content was null");
130131 return false;
131132 }
132133133133- const env = c.env;
134134 // make a check to see if the post has already been posted onto bsky
135135 // skip over this check if we are a threaded post, as we could have had a child post that didn't make it.
136136- if (!content.isThreadRoot && await isPostAlreadyPosted(env, content.postid)) {
136136+ if (!content.isThreadRoot && await isPostAlreadyPosted(c, content.postid)) {
137137 console.log(`Dropped handling make post for post ${content.postid}, already posted.`);
138138 return true;
139139 }
140140141141- const agent: AtpAgent|null = (usingAgent === null) ? await makeAgentForUser(env, content.user) : usingAgent;
141141+ const agent: AtpAgent|null = (usingAgent === null) ? await makeAgentForUser(c, content.user) : usingAgent;
142142 if (agent === null) {
143143 console.warn(`could not make agent for post ${content.postid}`);
144144 return false;
145145 }
146146147147- const newPostRecords: PostStatus|null = await makePostRaw(env, content, agent);
147147+ const newPostRecords: PostStatus|null = await makePostRaw(c, content, agent);
148148 if (newPostRecords !== null) {
149149- await bulkUpdatePostedData(env, newPostRecords.records, newPostRecords.expected == newPostRecords.got);
149149+ await bulkUpdatePostedData(c, newPostRecords.records, newPostRecords.expected == newPostRecords.got);
150150151151 // Delete any embeds if they exist.
152152 for (const record of newPostRecords.records) {
···164164165165 // Turn off the post now flag if we failed.
166166 if (content.postNow) {
167167- c.executionCtx.waitUntil(setPostNowOffForPost(env, content.postid));
167167+ c.executionCtx.waitUntil(setPostNowOffForPost(c, content.postid));
168168 }
169169 return false;
170170}
171171172172-export const makeRepost = async (c: Context|ScheduledContext, content: Repost, usingAgent: AtpAgent|null=null) => {
173173- const env = c.env;
172172+export const makeRepost = async (c: AllContext, content: Repost, usingAgent: AtpAgent|null=null) => {
174173 let bWasSuccess = true;
175175- const agent: AtpAgent|null = (usingAgent === null) ? await makeAgentForUser(env, content.userId) : usingAgent;
174174+ const agent: AtpAgent|null = (usingAgent === null) ? await makeAgentForUser(c, content.userId) : usingAgent;
176175 if (agent === null) {
177176 console.warn(`could not make agent for repost ${content.postid}`);
178177 return false;
···196195 return bWasSuccess;
197196};
198197199199-export const makePostRaw = async (env: Bindings, content: Post, agent: AtpAgent): Promise<PostStatus|null> => {
200200- const username = await getUsernameForUserId(env, content.user);
198198+export const makePostRaw = async (c: AllContext, content: Post, agent: AtpAgent): Promise<PostStatus|null> => {
199199+ const username = await getUsernameForUserId(c, content.user);
201200 // incredibly unlikely but we'll handle it
202201 if (username === null) {
203202 console.warn(`username for post ${content.postid} was invalid`);
···294293 // embed thumbnails of any size
295294 // it will fail when you try to make the post record, saying the
296295 // post record is invalid.
297297- const imgTransform = (await env.IMAGES.input(imageBlob.stream())
296296+ const imgTransform = (await c.env.IMAGES.input(imageBlob.stream())
298297 .transform({width: 1280, height: 720, fit: "scale-down"})
299298 .output({ format: "image/jpeg", quality: 85 })).response();
300299 if (imgTransform.ok) {
···429428 }
430429431430 // Otherwise pull files from storage
432432- const file = await env.R2.get(currentEmbed.content);
431431+ const file = await c.env.R2.get(currentEmbed.content);
433432 if (!file) {
434433 console.warn(`Could not get the file ${currentEmbed.content} from R2 for post!`);
435434 return false;
···447446 }
448447 }
449448 // Give violation mediaTooBig if the file is too large.
450450- await createViolationForUser(env, postData.user, AccountStatus.MediaTooBig);
449449+ await createViolationForUser(c, postData.user, AccountStatus.MediaTooBig);
451450 console.warn(`Unable to upload ${currentEmbed.content} for post ${postData.postid} with err ${err}`);
452451 return false;
453452 }
···609608610609 // If this is a post thread root
611610 if (content.isThreadRoot) {
612612- const childPosts = await getChildPostsOfThread(env, content.postid) || [];
611611+ const childPosts = await getChildPostsOfThread(c, content.postid) || [];
613612 expected += childPosts.length;
614613 // get the thread children.
615614 for (const child of childPosts) {
+3-3
src/utils/bskyPrune.ts
···11import isEmpty from 'just-is-empty';
22import split from 'just-split';
33-import { Bindings } from '../types.d';
33+import { AllContext } from '../types.d';
44import { getPostRecords } from './bskyApi';
55import { getAllPostedPosts, getAllPostedPostsOfUser } from './db/data';
66···88// are still on the network or not. If they are not, then this prunes the posts from
99// the database. This call is quite expensive and should only be ran on a weekly
1010// cron job.
1111-export const pruneBskyPosts = async (env: Bindings, userId?: string) => {
1212- const allPostedPosts = (userId !== undefined) ? await getAllPostedPostsOfUser(env, userId) : await getAllPostedPosts(env);
1111+export const pruneBskyPosts = async (c: AllContext, userId?: string) => {
1212+ const allPostedPosts = (userId !== undefined) ? await getAllPostedPostsOfUser(c, userId) : await getAllPostedPosts(c);
1313 let removePostIds: string[] = [];
1414 let postedGroups = split(allPostedPosts, 25);
1515 while (!isEmpty(postedGroups)) {
+82-29
src/utils/db/data.ts
···11import { and, asc, desc, eq, inArray, isNotNull, lte, ne, notInArray, sql } from "drizzle-orm";
22import { BatchItem } from "drizzle-orm/batch";
33-import { drizzle, DrizzleD1Database } from "drizzle-orm/d1";
33+import { DrizzleD1Database } from "drizzle-orm/d1";
44import isEmpty from "just-is-empty";
55import { validate as uuidValid } from 'uuid';
66import { posts, repostCounts, reposts } from "../../db/app.schema";
77import { violations } from "../../db/enforcement.schema";
88import { MAX_HOLD_DAYS_BEFORE_PURGE, MAX_POSTED_LENGTH } from "../../limits";
99import {
1010+ AllContext,
1011 BatchQuery,
1111- Bindings,
1212 GetAllPostedBatch,
1313 Post,
1414 PostRecordResponse,
···1616} from "../../types.d";
1717import { createPostObject, createRepostObject, floorCurrentTime } from "../helpers";
18181919-export const getAllPostsForCurrentTime = async (env: Bindings, removeThreads: boolean = false): Promise<Post[]> => {
1919+export const getAllPostsForCurrentTime = async (c: AllContext, removeThreads: boolean = false): Promise<Post[]> => {
2020 // Get all scheduled posts for current time
2121- const db: DrizzleD1Database = drizzle(env.DB);
2121+ const db: DrizzleD1Database = c.get("db");
2222+ if (!db) {
2323+ console.error("Could not get all posts for current time, db was null");
2424+ return [];
2525+ }
2226 const currentTime: Date = floorCurrentTime();
23272428 const violationUsers = db.select({violators: violations.userId}).from(violations);
···4145 return results.map((item) => createPostObject(item));
4246};
43474444-export const getAllRepostsForGivenTime = async (env: Bindings, givenDate: Date): Promise<Repost[]> => {
4848+export const getAllRepostsForGivenTime = async (c: AllContext, givenDate: Date): Promise<Repost[]> => {
4549 // Get all scheduled posts for the given time
4646- const db: DrizzleD1Database = drizzle(env.DB);
5050+ const db: DrizzleD1Database = c.get("db");
5151+ if (!db) {
5252+ console.error("could not get all reposts for given timeframe, db was null");
5353+ return [];
5454+ }
4755 const query = db.select({uuid: reposts.uuid}).from(reposts)
4856 .where(lte(reposts.scheduledDate, givenDate));
4957 const violationsQuery = db.select({data: violations.userId}).from(violations);
···5563 return results.map((item) => createRepostObject(item));
5664};
57655858-export const getAllRepostsForCurrentTime = async (env: Bindings): Promise<Repost[]> => {
5959- return await getAllRepostsForGivenTime(env, floorCurrentTime());
6666+export const getAllRepostsForCurrentTime = async (c: AllContext): Promise<Repost[]> => {
6767+ return await getAllRepostsForGivenTime(c, floorCurrentTime());
6068};
61696262-export const deleteAllRepostsBeforeCurrentTime = async (env: Bindings) => {
6363- const db: DrizzleD1Database = drizzle(env.DB);
7070+export const deleteAllRepostsBeforeCurrentTime = async (c: AllContext) => {
7171+ const db: DrizzleD1Database = c.get("db");
7272+ if (!db) {
7373+ console.error("unable to delete all reposts before current time, db was null");
7474+ return;
7575+ }
6476 const currentTime = floorCurrentTime();
6577 const deletedPosts = await db.delete(reposts).where(lte(reposts.scheduledDate, currentTime))
6678 .returning({id: reposts.uuid, scheduleGuid: reposts.scheduleGuid});
···107119 }
108120};
109121110110-export const bulkUpdatePostedData = async (env: Bindings, records: PostRecordResponse[], allPosted: boolean) => {
111111- const db: DrizzleD1Database = drizzle(env.DB);
122122+export const bulkUpdatePostedData = async (c: AllContext, records: PostRecordResponse[], allPosted: boolean) => {
123123+ const db: DrizzleD1Database = c.get("db");
124124+ if (!db) {
125125+ console.error("unable to bulk update posted data, db was null");
126126+ return;
127127+ }
112128 let dbOperations: BatchItem<"sqlite">[] = [];
113129114130 for (let i = 0; i < records.length; ++i) {
···128144 await db.batch(dbOperations as BatchQuery);
129145}
130146131131-export const setPostNowOffForPost = async (env: Bindings, id: string) => {
147147+export const setPostNowOffForPost = async (c: AllContext, id: string) => {
148148+ const db: DrizzleD1Database = c.get("db");
132149 if (!uuidValid(id))
133150 return false;
134151135135- const db: DrizzleD1Database = drizzle(env.DB);
152152+ if (!db) {
153153+ console.warn(`cannot set off post now for post ${id}`);
154154+ return false;
155155+ }
156156+136157 const {success} = await db.update(posts).set({postNow: false}).where(eq(posts.uuid, id));
137158 if (!success)
138159 console.error(`Unable to set PostNow to off for post ${id}`);
139160};
140161141141-export const updatePostForGivenUser = async (env: Bindings, userId: string, id: string, newData: Object) => {
162162+export const updatePostForGivenUser = async (c: AllContext, userId: string, id: string, newData: Object) => {
163163+ const db: DrizzleD1Database = c.get("db");
142164 if (isEmpty(userId) || !uuidValid(id))
143165 return false;
144166145145- const db: DrizzleD1Database = drizzle(env.DB);
167167+ if (!db) {
168168+ console.error(`unable to update post ${id} for user ${userId}, db was null`);
169169+ return false;
170170+ }
171171+146172 const {success} = await db.update(posts).set(newData).where(
147173 and(eq(posts.uuid, id), eq(posts.userId, userId)));
148174 return success;
149175};
150176151151-export const getAllPostedPostsOfUser = async(env: Bindings, userId: string): Promise<GetAllPostedBatch[]> => {
177177+export const getAllPostedPostsOfUser = async(c: AllContext, userId: string): Promise<GetAllPostedBatch[]> => {
178178+ const db: DrizzleD1Database = c.get("db");
152179 if (isEmpty(userId))
153180 return [];
154181155155- const db: DrizzleD1Database = drizzle(env.DB);
182182+ if (!db) {
183183+ console.error(`unable to get all posted posts of user ${userId}, db was null`);
184184+ return [];
185185+ }
186186+156187 return await db.select({id: posts.uuid, uri: posts.uri})
157188 .from(posts)
158189 .where(and(eq(posts.userId, userId), eq(posts.posted, true)))
159190 .all();
160191};
161192162162-export const getAllPostedPosts = async (env: Bindings): Promise<GetAllPostedBatch[]> => {
163163- const db: DrizzleD1Database = drizzle(env.DB);
193193+export const getAllPostedPosts = async (c: AllContext): Promise<GetAllPostedBatch[]> => {
194194+ const db: DrizzleD1Database = c.get("db");
195195+ if (!db) {
196196+ console.error("unable to get all posted posts, db was null");
197197+ return [];
198198+ }
164199 return await db.select({id: posts.uuid, uri: posts.uri})
165200 .from(posts)
166201 .where(eq(posts.posted, true))
167202 .all();
168203};
169204170170-export const isPostAlreadyPosted = async (env: Bindings, postId: string): Promise<boolean> => {
205205+export const isPostAlreadyPosted = async (c: AllContext, postId: string): Promise<boolean> => {
206206+ const db: DrizzleD1Database = c.get("db");
171207 if (!uuidValid(postId))
172208 return true;
173209174174- const db: DrizzleD1Database = drizzle(env.DB);
210210+ if (!db) {
211211+ console.error(`unable to get database to tell if ${postId} has been posted`);
212212+ return true;
213213+ }
214214+175215 const query = await db.select({posted: posts.posted}).from(posts).where(eq(posts.uuid, postId)).all();
176216 if (isEmpty(query) || query[0].posted === null) {
177217 // if the post does not exist, return true anyways
···180220 return query[0].posted;
181221};
182222183183-export const getChildPostsOfThread = async (env: Bindings, rootId: string): Promise<Post[]|null> => {
223223+export const getChildPostsOfThread = async (c: AllContext, rootId: string): Promise<Post[]|null> => {
224224+ const db: DrizzleD1Database = c.get("db");
184225 if (!uuidValid(rootId))
185226 return null;
186227187187- const db: DrizzleD1Database = drizzle(env.DB);
228228+ if (!db) {
229229+ console.error(`unable to get child posts of root ${rootId}, db was null`);
230230+ return null;
231231+ }
232232+188233 const query = await db.select().from(posts)
189234 .where(and(isNotNull(posts.parentPost), eq(posts.rootPost, rootId)))
190235 .orderBy(asc(posts.threadOrder), desc(posts.createdAt)).all();
···204249}
205250206251// deletes multiple posted posts from a database.
207207-export const deletePosts = async (env: Bindings, postsToDelete: string[]): Promise<number> => {
252252+export const deletePosts = async (c: AllContext, postsToDelete: string[]): Promise<number> => {
208253 // Don't do anything on empty arrays.
209254 if (isEmpty(postsToDelete))
210255 return 0;
211256212212- const db: DrizzleD1Database = drizzle(env.DB);
257257+ const db: DrizzleD1Database = c.get("db");
258258+ if (!db) {
259259+ console.error(`could not delete posts ${postsToDelete}, db was null`);
260260+ return 0;
261261+ }
213262 let deleteQueries: BatchItem<"sqlite">[] = [];
214263 postsToDelete.forEach((itm) => {
215264 deleteQueries.push(db.delete(posts).where(and(eq(posts.uuid, itm), eq(posts.posted, true))));
···224273 return 0;
225274};
226275227227-export const purgePostedPosts = async (env: Bindings): Promise<number> => {
228228- const db: DrizzleD1Database = drizzle(env.DB);
276276+export const purgePostedPosts = async (c: AllContext): Promise<number> => {
277277+ const db: DrizzleD1Database = c.get("db");
278278+ if (!db) {
279279+ console.error("could not purge posted posts, got error");
280280+ return 0;
281281+ }
229282 const dateString = `datetime('now', '-${MAX_HOLD_DAYS_BEFORE_PURGE} days')`;
230283 const dbQuery = await db.select({ data: posts.uuid }).from(posts)
231284 .leftJoin(repostCounts, eq(posts.uuid, repostCounts.uuid))
···242295 if (isEmpty(postsToDelete))
243296 return 0;
244297245245- return await deletePosts(env, postsToDelete);
298298+ return await deletePosts(c, postsToDelete);
246299};
247300248301export const getPostByCID = async(db: DrizzleD1Database, userId: string, cid: string): Promise<Post|null> => {
+27-11
src/utils/db/file.ts
···11import { and, eq, inArray, lte } from "drizzle-orm";
22-import { drizzle, DrizzleD1Database } from "drizzle-orm/d1";
22+import { DrizzleD1Database } from "drizzle-orm/d1";
33import flatten from "just-flatten-it";
44import { mediaFiles, posts } from "../../db/app.schema";
55-import { Bindings, EmbedDataType, LooseObj } from "../../types.d";
55+import { AllContext, EmbedDataType, LooseObj } from "../../types.d";
66import { daysAgo } from "../helpers";
7788-export const addFileListing = async (env: Bindings, file: string, user: string|null, createDate: Date|null=null) => {
99- const db: DrizzleD1Database = drizzle(env.DB);
88+export const addFileListing = async (c: AllContext, file: string, user: string|null, createDate: Date|null=null) => {
99+ const db: DrizzleD1Database = c.get("db");
1010+ if (!db) {
1111+ console.error(`unable to create file listing for file ${file}, db was null`);
1212+ return;
1313+ }
1014 let insertData:LooseObj = {};
1115 if (createDate !== null) {
1216 insertData.createdAt = createDate;
···1822 .onConflictDoNothing({target: mediaFiles.fileName});
1923};
20242121-export const deleteFileListings = async (env: Bindings, files: string|string[]) => {
2222- const db: DrizzleD1Database = drizzle(env.DB);
2525+export const deleteFileListings = async (c: AllContext, files: string|string[]) => {
2626+ const db: DrizzleD1Database = c.get("db");
2727+ if (!db) {
2828+ console.error(`unable to delete file listings ${files}, db was null`);
2929+ return;
3030+ }
2331 let filesToDelete = [];
2432 filesToDelete.push(files);
2533 const filesToWorkOn = flatten(filesToDelete);
2634 await db.delete(mediaFiles).where(inArray(mediaFiles.fileName, filesToWorkOn));
2735};
28362929-export const getAllAbandonedMedia = async(env: Bindings) => {
3030- const db: DrizzleD1Database = drizzle(env.DB);
3131- const numDaysAgo = daysAgo(env.R2_SETTINGS.prune_days);
3737+export const getAllAbandonedMedia = async(c: AllContext): Promise<string[]> => {
3838+ const db: DrizzleD1Database = c.get("db");
3939+ if (!db) {
4040+ console.error("could not get all abandoned media, db was null");
4141+ return [];
4242+ }
4343+ const numDaysAgo = daysAgo(c.env.R2_SETTINGS.prune_days);
32443345 const results = await db.select().from(mediaFiles)
3446 .where(
···3850 return results.map((item) => item.fileName);
3951};
40524141-export const getAllMediaOfUser = async (env: Bindings, userId: string): Promise<string[]> => {
4242- const db: DrizzleD1Database = drizzle(env.DB);
5353+export const getAllMediaOfUser = async (c: AllContext, userId: string): Promise<string[]> => {
5454+ const db: DrizzleD1Database = c.get("db");
5555+ if (!db) {
5656+ console.warn(`could not get all media of user ${userId}, db was null`);
5757+ return [];
5858+ }
4359 const mediaList = await db.select({embeds: posts.embedContent}).from(posts)
4460 .where(and(eq(posts.posted, false), eq(posts.userId, userId))).all();
4561
+11-7
src/utils/db/maintain.ts
···11import { eq, getTableColumns, gt, inArray, isNull, sql } from "drizzle-orm";
22import { BatchItem } from "drizzle-orm/batch";
33-import { drizzle, DrizzleD1Database } from "drizzle-orm/d1";
33+import { DrizzleD1Database } from "drizzle-orm/d1";
44import flatten from "just-flatten-it";
55import { mediaFiles, posts, repostCounts, reposts } from "../../db/app.schema";
66import { users } from "../../db/auth.schema";
77import { MAX_POSTED_LENGTH } from "../../limits";
88-import { BatchQuery, Bindings, R2BucketObject } from "../../types.d";
88+import { AllContext, BatchQuery, Bindings, R2BucketObject } from "../../types.d";
99import { getAllFilesList } from "../r2Query";
1010import { addFileListing, getAllMediaOfUser } from "./file";
11111212/** Maintenance operations **/
1313-export const runMaintenanceUpdates = async (env: Bindings) => {
1414- const db: DrizzleD1Database = drizzle(env.DB);
1313+export const runMaintenanceUpdates = async (c: AllContext) => {
1414+ const db: DrizzleD1Database = c.get("db");
1515+ if (!db) {
1616+ console.error("unable to get database to run maintenance");
1717+ return;
1818+ }
1519 // Create a posted query that also checks for valid json and content length
1620 const postedQuery = db.select({
1721 ...getTableColumns(posts),
···4448 await db.update(posts).set({updatedAt: sql`CURRENT_TIMESTAMP`}).where(isNull(posts.updatedAt));
45494650 // populate existing media table with post data
4747- const allBucketFiles:R2BucketObject[] = await getAllFilesList(env);
5151+ const allBucketFiles:R2BucketObject[] = await getAllFilesList(c);
4852 try {
4953 for (const bucketFile of allBucketFiles) {
5050- await addFileListing(env, bucketFile.name, bucketFile.user, bucketFile.date);
5454+ await addFileListing(c, bucketFile.name, bucketFile.user, bucketFile.date);
5155 }
5256 } catch(err) {
5357 console.error(`Adding file listings got error ${err}`);
···5761 // Flag if the media file has embed data
5862 const allUsers = await db.select({id: users.id}).from(users).all();
5963 for (const user of allUsers) {
6060- const userMedia = await getAllMediaOfUser(env, user.id);
6464+ const userMedia = await getAllMediaOfUser(c, user.id);
6165 batchedQueries.push(db.update(mediaFiles).set({hasPost: true})
6266 .where(inArray(mediaFiles.fileName, flatten(userMedia))));
6367 }
+33-16
src/utils/db/userinfo.ts
···11import { eq } from "drizzle-orm";
22-import { drizzle, DrizzleD1Database } from "drizzle-orm/d1";
33-import { Context } from "hono";
22+import { DrizzleD1Database } from "drizzle-orm/d1";
43import isEmpty from "just-is-empty";
54import { users } from "../../db/auth.schema";
66-import { Bindings, BskyAPILoginCreds } from "../../types.d";
55+import { AllContext, BskyAPILoginCreds } from "../../types.d";
76import { createLoginCredsObj } from "../helpers";
8799-export const doesUserExist = async (c: Context, username: string) => {
1010- const db: DrizzleD1Database = drizzle(c.env.DB);
88+export const doesUserExist = async (c: AllContext, username: string): Promise<boolean> => {
99+ const db: DrizzleD1Database = c.get("db");
1010+ if (!db) {
1111+ console.error("Unable to check database for user existence");
1212+ return true;
1313+ }
1114 const result = await db.select().from(users)
1215 .where(eq(users.username, username))
1316 .limit(1).all();
1417 return result.length > 0;
1518};
16191717-export const doesAdminExist = async (c: Context) => {
1818- const db: DrizzleD1Database = drizzle(c.env.DB);
2020+export const doesAdminExist = async (c: AllContext) => {
2121+ const db: DrizzleD1Database = c.get("db");
2222+ if (!db) {
2323+ console.error("unable to check database for admin account");
2424+ return false;
2525+ }
2626+1927 const result = await db.select().from(users)
2028 .where(eq(users.name, "admin"))
2129 .limit(1).all();
2230 return result.length > 0;
2331};
24322525-export const getBskyUserPassForId = async (env: Bindings, userid: string): Promise<BskyAPILoginCreds> => {
2626- const db: DrizzleD1Database = drizzle(env.DB);
3333+export const getBskyUserPassForId = async (c: AllContext, userid: string): Promise<BskyAPILoginCreds> => {
3434+ const db: DrizzleD1Database = c.get("db");
3535+ if (!db)
3636+ return createLoginCredsObj(null);
3737+2738 const response = await db.select({user: users.username, pass: users.bskyAppPass, pds: users.pds})
2839 .from(users)
2940 .where(eq(users.id, userid))
3041 .limit(1).all();
3131- return createLoginCredsObj(env, response[0] || null);
4242+ return createLoginCredsObj(response[0] || null);
3243};
33443434-export const getUsernameForUserId = async (env: Bindings, userId: string): Promise<string|null> => {
3535- const db: DrizzleD1Database = drizzle(env.DB);
4545+export const getUsernameForUserId = async (c: AllContext, userId: string): Promise<string|null> => {
4646+ const db: DrizzleD1Database = c.get("db");
4747+ if (!db)
4848+ return null;
4949+3650 const result = await db.select({username: users.username}).from(users)
3751 .where(eq(users.id, userId)).limit(1);
3852 if (result !== null && result.length > 0)
···4054 return null;
4155};
42564343-export const getUsernameForUser = async (c: Context): Promise<string|null> => {
5757+export const getUsernameForUser = async (c: AllContext): Promise<string|null> => {
4458 const userId = c.get("userId");
4559 if (!userId)
4660 return null;
47614848- return await getUsernameForUserId(c.env, userId);
6262+ return await getUsernameForUserId(c, userId);
4963};
50645165// This is a super dumb query that's needed to get around better auth's forgot password system
5266// because you cannot make the call with just an username, you need to also have the email
5367// but we never update the email past the original time you first signed up, so instead
5468// we use big brain tactics to spoof the email
5555-export const getUserEmailForHandle = async (env: Bindings, userhandle: string): Promise<string|null> => {
5656- const db: DrizzleD1Database = drizzle(env.DB);
6969+export const getUserEmailForHandle = async (c: AllContext, userhandle: string): Promise<string|null> => {
7070+ const db: DrizzleD1Database = c.get("db");
7171+ if (!db)
7272+ return null;
7373+5774 const result = await db.select({email: users.email}).from(users).where(eq(users.username, userhandle)).limit(1);
5875 if (!isEmpty(result))
5976 return result[0].email;
···11import { addHours, isAfter, isEqual } from "date-fns";
22import { and, asc, desc, eq, getTableColumns, gt, gte, sql } from "drizzle-orm";
33import { BatchItem } from "drizzle-orm/batch";
44-import { drizzle, DrizzleD1Database } from "drizzle-orm/d1";
55-import { Context } from "hono";
44+import { DrizzleD1Database } from "drizzle-orm/d1";
65import has from "just-has";
76import isEmpty from "just-is-empty";
87import { v4 as uuidv4, validate as uuidValid } from 'uuid';
···1110import { MAX_POSTS_PER_THREAD, MAX_REPOST_POSTS, MAX_REPOST_RULES_PER_POST } from "../limits";
1211import {
1312 AccountStatus,
1313+ AllContext,
1414 BatchQuery,
1515 CreateObjectResponse, CreatePostQueryResponse,
1616 DeleteResponse,
···2525import { createPostObject, createRepostInfo, floorGivenTime } from "./helpers";
2626import { deleteEmbedsFromR2 } from "./r2Query";
27272828-export const getPostsForUser = async (c: Context): Promise<Post[]|null> => {
2828+export const getPostsForUser = async (c: AllContext): Promise<Post[]|null> => {
2929 try {
3030 const userId = c.get("userId");
3131- if (userId) {
3232- const db: DrizzleD1Database = drizzle(c.env.DB);
3131+ const db: DrizzleD1Database = c.get("db");
3232+ if (userId && db) {
3333 const results = await db.select({
3434 ...getTableColumns(posts),
3535 repostCount: repostCounts.count
···4949 return null;
5050};
51515252-export const updateUserData = async (c: Context, newData: any): Promise<boolean> => {
5252+export const updateUserData = async (c: AllContext, newData: any): Promise<boolean> => {
5353 const userId = c.get("userId");
5454+ const db: DrizzleD1Database = c.get("db");
5455 try {
5656+ if (!db) {
5757+ console.error("Unable to update user data, no database object");
5858+ return false;
5959+ }
5560 if (userId) {
5656- const db: DrizzleD1Database = drizzle(c.env.DB);
5761 let queriesToExecute:BatchItem<"sqlite">[] = [];
58625963 if (has(newData, "password")) {
···7377 // check if the user has violations
7478 if (await userHasViolations(db, userId)) {
7579 // they do, so clear them out
7676- await removeViolations(c.env, userId, [AccountStatus.InvalidAccount, AccountStatus.Deactivated]);
8080+ await removeViolations(c, userId, [AccountStatus.InvalidAccount, AccountStatus.Deactivated]);
7781 }
7882 }
7983···9296 return false;
9397};
94989595-export const deletePost = async (c: Context, id: string): Promise<DeleteResponse> => {
9999+export const deletePost = async (c: AllContext, id: string): Promise<DeleteResponse> => {
96100 const userId = c.get("userId");
97101 const returnObj: DeleteResponse = {success: false};
98102 if (!userId) {
99103 return returnObj;
100104 }
101105102102- const db: DrizzleD1Database = drizzle(c.env.DB);
106106+ const db: DrizzleD1Database = c.get("db");
107107+ if (!db) {
108108+ console.error(`unable to delete post ${id}, db was null`);
109109+ return returnObj;
110110+ }
111111+103112 const postObj = await getPostById(c, id);
104113 if (postObj !== null) {
105114 let queriesToExecute:BatchItem<"sqlite">[] = [];
···109118 await deleteEmbedsFromR2(c, postObj.embeds);
110119 if (await userHasViolations(db, userId)) {
111120 // Remove the media too big violation if it's been given
112112- await removeViolation(c.env, userId, AccountStatus.MediaTooBig);
121121+ await removeViolation(c, userId, AccountStatus.MediaTooBig);
113122 }
114123 }
115124···129138130139 // We'll need to delete all of the child embeds then, a costly, annoying experience.
131140 if (postObj.isThreadRoot) {
132132- const childPosts = await getChildPostsOfThread(c.env, postObj.postid);
141141+ const childPosts = await getChildPostsOfThread(c, postObj.postid);
133142 if (childPosts !== null) {
134143 for (const childPost of childPosts) {
135144 c.executionCtx.waitUntil(deleteEmbedsFromR2(c, childPost.embeds));
···155164 return returnObj;
156165};
157166158158-export const createPost = async (c: Context, body: any): Promise<CreatePostQueryResponse> => {
159159- const db: DrizzleD1Database = drizzle(c.env.DB);
160160-167167+export const createPost = async (c: AllContext, body: any): Promise<CreatePostQueryResponse> => {
168168+ const db: DrizzleD1Database = c.get("db");
161169 const userId = c.get("userId");
162170 if (!userId)
163171 return { ok: false, msg: "Your user session has expired, please login again"};
164172173173+ if (!db) {
174174+ console.error("unable to create post, db became null");
175175+ return { ok: false, msg: "An application error has occurred please refresh" };
176176+ }
177177+165178 const validation = PostSchema.safeParse(body);
166179 if (!validation.success) {
167180 return { ok: false, msg: validation.error.toString() };
···313326 return { ok: success, postNow: makePostNow, postId: postUUID, msg: success ? "success" : "fail" };
314327};
315328316316-export const createRepost = async (c: Context, body: any): Promise<CreateObjectResponse> => {
317317- const db: DrizzleD1Database = drizzle(c.env.DB);
329329+export const createRepost = async (c: AllContext, body: any): Promise<CreateObjectResponse> => {
330330+ const db: DrizzleD1Database = c.get("db");
318331319332 const userId = c.get("userId");
320333 if (!userId)
321334 return { ok: false, msg: "Your user session has expired, please login again"};
335335+336336+ if (!db) {
337337+ console.error("unable to create repost db became null");
338338+ return {ok: false, msg: "Invalid server operation occurred, please refresh"};
339339+ }
322340323341 const validation = RepostSchema.safeParse(body);
324342 if (!validation.success) {
···430448 return { ok: success, msg: success ? "success" : "fail", postId: postUUID };
431449};
432450433433-export const updatePostForUser = async (c: Context, id: string, newData: Object): Promise<boolean> => {
451451+export const updatePostForUser = async (c: AllContext, id: string, newData: Object): Promise<boolean> => {
434452 const userId = c.get("userId");
435435- return await updatePostForGivenUser(c.env, userId, id, newData);
453453+ return await updatePostForGivenUser(c, userId, id, newData);
436454};
437455438438-export const getPostById = async(c: Context, id: string): Promise<Post|null> => {
456456+export const getPostById = async(c: AllContext, id: string): Promise<Post|null> => {
439457 const userId = c.get("userId");
440458 if (!userId || !uuidValid(id))
441459 return null;
442460443443- const env = c.env;
444444- const db: DrizzleD1Database = drizzle(env.DB);
461461+ const db: DrizzleD1Database = c.get("db");
462462+ if (!db) {
463463+ console.error(`unable to get post ${id}, db was null`);
464464+ return null;
465465+ }
466466+445467 const result = await db.select().from(posts)
446468 .where(and(eq(posts.uuid, id), eq(posts.userId, userId)))
447469 .limit(1).all();
···452474};
453475454476// used for post editing, acts very similar to getPostsForUser
455455-export const getPostByIdWithReposts = async(c: Context, id: string): Promise<Post|null> => {
477477+export const getPostByIdWithReposts = async(c: AllContext, id: string): Promise<Post|null> => {
456478 const userId = c.get("userId");
457479 if (!userId || !uuidValid(id))
458480 return null;
459481460460- const env = c.env;
461461- const db: DrizzleD1Database = drizzle(env.DB);
482482+ const db: DrizzleD1Database = c.get("db");
483483+ if (!db) {
484484+ console.error(`unable to get post ${id} with reposts, db was null`);
485485+ return null;
486486+ }
487487+462488 const result = await db.select({
463489 ...getTableColumns(posts),
464490 repostCount: repostCounts.count,
+3-3
src/utils/helpers.ts
···11import { startOfHour, subDays } from "date-fns";
22+import { Context } from "hono";
23import has from "just-has";
34import isEmpty from "just-is-empty";
44-import { Bindings, BskyAPILoginCreds, Post, Repost, RepostInfo } from "../types.d";
55-import { Context } from "hono";
55+import { BskyAPILoginCreds, Post, Repost, RepostInfo } from "../types.d";
6677export function createPostObject(data: any) {
88 const postData: Post = (new Object() as Post);
···8282 return repostObj;
8383}
84848585-export function createLoginCredsObj(env: Bindings, data: any) {
8585+export function createLoginCredsObj(data: any) {
8686 const loginCreds: BskyAPILoginCreds = (new Object() as BskyAPILoginCreds);
8787 if (isEmpty(data)) {
8888 loginCreds.password = loginCreds.username = loginCreds.pds = "";
+5-5
src/utils/inviteKeys.ts
···1515 if (inviteKey === undefined)
1616 return false;
17171818- const value = await c.env.INVITE_POOL.get(inviteKey);
1818+ const value = await c.env.INVITE_POOL!.get(inviteKey);
1919 // Key does not exist
2020 if (value === null)
2121 return false;
···4141 if (inviteKey === undefined)
4242 return;
43434444- const value = await c.env.INVITE_POOL.get(inviteKey);
4444+ const value = await c.env.INVITE_POOL!.get(inviteKey);
4545 if (value === null) {
4646 console.error(`attempted to use invite key ${inviteKey} but is invalid`);
4747 return;
···6262 let newValue: number = amount - 1;
6363 // Delete any keys that fall to 0, they should be removed from the db
6464 if (newValue <= 0) {
6565- await c.env.INVITE_POOL.delete(inviteKey);
6565+ await c.env.INVITE_POOL!.delete(inviteKey);
6666 return;
6767 }
68686969 // put the new value on the stack
7070- await c.env.INVITE_POOL.put(inviteKey, newValue.toString());
7070+ await c.env.INVITE_POOL!.put(inviteKey, newValue.toString());
7171 }
7272}
7373···8080 separator: '-',
8181 capitalize: false,
8282 });
8383- c.executionCtx.waitUntil(c.env.INVITE_POOL.put(newKey, "10"));
8383+ c.executionCtx.waitUntil(c.env.INVITE_POOL!.put(newKey, "10"));
8484 return newKey;
8585}