This commit is contained in:
shafi54 2026-02-28 00:26:05 +05:30
parent 6bcf080593
commit 5bd0f8ded7
9 changed files with 3834 additions and 36 deletions

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,7 @@
CREATE TABLE "mf"."unlogged_user_tokens" (
"id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "mf"."unlogged_user_tokens_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
"token" varchar(500) NOT NULL,
"added_at" timestamp DEFAULT now() NOT NULL,
"last_verified" timestamp,
CONSTRAINT "unlogged_user_tokens_token_unique" UNIQUE("token")
);

File diff suppressed because it is too large Load diff

View file

@ -526,6 +526,13 @@
"when": 1771674555093, "when": 1771674555093,
"tag": "0074_outgoing_black_cat", "tag": "0074_outgoing_black_cat",
"breakpoints": true "breakpoints": true
},
{
"idx": 75,
"version": "7",
"when": 1772196660983,
"tag": "0075_cuddly_rocket_racer",
"breakpoints": true
} }
] ]
} }

View file

@ -420,6 +420,13 @@ export const notifCreds = mf.table('notif_creds', {
lastVerified: timestamp('last_verified'), lastVerified: timestamp('last_verified'),
}); });
export const unloggedUserTokens = mf.table('unlogged_user_tokens', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
token: varchar({ length: 500 }).notNull().unique(),
addedAt: timestamp('added_at').notNull().defaultNow(),
lastVerified: timestamp('last_verified'),
});
export const userNotifications = mf.table('user_notifications', { export const userNotifications = mf.table('user_notifications', {
id: integer().primaryKey().generatedAlwaysAsIdentity(), id: integer().primaryKey().generatedAlwaysAsIdentity(),
title: varchar('title', { length: 255 }).notNull(), title: varchar('title', { length: 255 }).notNull(),

View file

@ -135,4 +135,4 @@ export async function seed() {
} }
console.log("Seeding completed."); console.log("Seeding completed.");
} }

View file

@ -1,9 +1,9 @@
import { router, protectedProcedure } from '../trpc-index'; import { router, protectedProcedure, publicProcedure } from '../trpc-index';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { eq, and } from 'drizzle-orm'; import { eq, and } from 'drizzle-orm';
import { z } from 'zod'; import { z } from 'zod';
import { db } from '../../db/db_index'; import { db } from '../../db/db_index';
import { users, userDetails, userCreds, notifCreds } from '../../db/schema'; import { users, userDetails, userCreds, notifCreds, unloggedUserTokens } from '../../db/schema';
import { ApiError } from '../../lib/api-error'; import { ApiError } from '../../lib/api-error';
import { jwtSecret } from 'src/lib/env-exporter'; import { jwtSecret } from 'src/lib/env-exporter';
import { generateSignedUrlFromS3Url } from '../../lib/s3-client'; import { generateSignedUrlFromS3Url } from '../../lib/s3-client';
@ -109,37 +109,60 @@ export const userRouter = router({
}; };
}), }),
savePushToken: protectedProcedure savePushToken: publicProcedure
.input(z.object({ token: z.string() })) .input(z.object({ token: z.string() }))
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const userId = ctx.user.userId;
const { token } = input; const { token } = input;
const userId = ctx.user?.userId;
if (!userId) {
throw new ApiError('User not authenticated', 401);
}
// Check if this exact token already exists for this user if (userId) {
const existing = await db.query.notifCreds.findFirst({ // AUTHENTICATED USER
where: and( // Check if token exists in notif_creds for this user
eq(notifCreds.userId, userId), const existing = await db.query.notifCreds.findFirst({
eq(notifCreds.token, token) where: and(
), eq(notifCreds.userId, userId),
}); eq(notifCreds.token, token)
),
if (existing) {
// Update lastVerified timestamp
await db
.update(notifCreds)
.set({ lastVerified: new Date() })
.where(eq(notifCreds.id, existing.id));
} else {
// Insert new token
await db.insert(notifCreds).values({
userId,
token,
lastVerified: new Date(),
}); });
if (existing) {
// Update lastVerified timestamp
await db
.update(notifCreds)
.set({ lastVerified: new Date() })
.where(eq(notifCreds.id, existing.id));
} else {
// Insert new token into notif_creds
await db.insert(notifCreds).values({
userId,
token,
lastVerified: new Date(),
});
}
// Remove from unlogged_user_tokens if it exists
await db
.delete(unloggedUserTokens)
.where(eq(unloggedUserTokens.token, token));
} else {
// UNAUTHENTICATED USER
// Save/update in unlogged_user_tokens
const existing = await db.query.unloggedUserTokens.findFirst({
where: eq(unloggedUserTokens.token, token),
});
if (existing) {
await db
.update(unloggedUserTokens)
.set({ lastVerified: new Date() })
.where(eq(unloggedUserTokens.id, existing.id));
} else {
await db.insert(unloggedUserTokens).values({
token,
lastVerified: new Date(),
});
}
} }
return { success: true }; return { success: true };

View file

@ -102,4 +102,4 @@ const HealthTestWrapper: React.FC<HealthTestWrapperProps> = ({ children }) => {
); );
}; };
export default HealthTestWrapper; export default HealthTestWrapper;

View file

@ -8,10 +8,10 @@ import { MyButton } from "common-ui";
import { useAuth } from "@/src/contexts/AuthContext"; import { useAuth } from "@/src/contexts/AuthContext";
import { trpc } from "@/src/trpc-client"; import { trpc } from "@/src/trpc-client";
interface Props {} interface Props { }
function NotifChecker(props: Props) { function NotifChecker(props: Props) {
const {} = props; const { } = props;
const [showPermissionDialog, setShowPermissionDialog] = React.useState(false); const [showPermissionDialog, setShowPermissionDialog] = React.useState(false);
const { isAuthenticated } = useAuth(); const { isAuthenticated } = useAuth();
@ -19,8 +19,7 @@ function NotifChecker(props: Props) {
const { notifPermission, expoPushToken } = useNotification(); const { notifPermission, expoPushToken } = useNotification();
React.useEffect(() => { React.useEffect(() => {
console.log({isAuthenticated, expoPushToken, notifPermission}); if (expoPushToken && notifPermission === 'granted') {
if (isAuthenticated && expoPushToken && notifPermission === 'granted') {
savePushTokenMutation.mutate( savePushTokenMutation.mutate(
{ token: expoPushToken }, { token: expoPushToken },
{ {
@ -30,7 +29,7 @@ function NotifChecker(props: Props) {
} }
); );
} }
}, [isAuthenticated, expoPushToken, notifPermission]); }, [expoPushToken, notifPermission, isAuthenticated]);
React.useEffect(() => { React.useEffect(() => {
if (notifPermission === "denied") { if (notifPermission === "denied") {