added playground and userroute

This commit is contained in:
2024-04-19 13:01:58 +07:00
parent a90529f258
commit a3f61b35c1
13 changed files with 1110 additions and 80 deletions

170
src/userRoute.ts Normal file
View File

@@ -0,0 +1,170 @@
import {
router,
verifiedPhone,
publicProcedure,
protectedProcedure,
} from "./trpc";
import { db } from "./db";
import { phoneToken, user } from "./schema";
import { createInsertSchema } from "drizzle-zod";
import { z } from "zod";
import { SQL, eq } from "drizzle-orm";
import { Config } from "./config";
import { TRPCError } from "@trpc/server";
const userInsertSchema = createInsertSchema(user);
type UserInsertSchema = z.infer<typeof userInsertSchema>;
export const userRoute = router({
getAllUser: publicProcedure
.input(
z.object({
offset: z.number().default(0),
limit: z.number().max(50).default(10),
group: z.number().optional(),
zone: z.number().optional(),
})
)
.query(
async ({ input }) =>
await getAllUser(input.offset, input.limit, input.group, input.zone)
),
createUser: verifiedPhone
.input(userInsertSchema.omit({ id: true, phone: true }))
.mutation(
async ({ input, ctx }) => await createUser({ ...input, phone: ctx.phone })
),
requestOtp: publicProcedure
.input(z.object({ phone: z.string().trim().min(5) }))
.mutation(async ({ input }) => await requestOtp(input.phone)),
verifyOtp: publicProcedure
.input(
z.object({
pin: z.string().trim(),
token: z.string(),
})
)
.mutation(async ({ input }) => await verifyOtp(input.token, input.pin)),
});
async function getAllUser(
offset: number,
limit: number,
group?: number,
zone?: number
) {
let users = await db.query.user.findMany({
with: {
group: true,
opinions: true,
zone: {
with: { province: true },
},
},
limit,
offset,
where: (user, { eq, and }) => {
let conditions: SQL[] = [];
if (group) {
conditions.push(eq(user.group, group));
}
if (zone) {
conditions.push(eq(user.zone, zone));
}
return and(...conditions);
},
});
return users;
}
async function createUser(newUser: UserInsertSchema) {
try {
let result = await db.insert(user).values(newUser);
return result.lastInsertRowid;
} catch (e) {
console.error(e);
throw new Error(`Unable to create new user:\n${e}`);
}
}
async function requestOtp(phone: string) {
const _phone = phone.trim();
try {
let rs = await fetch(Config.sms_api_request_endpoint, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
key: Config.sms_api_key,
secret: Config.sms_api_secret,
msisdn: _phone,
}),
}).then((res) => res.json());
if (rs.errors) {
console.error(rs);
throw new TRPCError({
message: `Unable to request OTP`,
code: "INTERNAL_SERVER_ERROR",
});
}
await db.insert(phoneToken).values({ phone: _phone, token: rs.token });
return {
status: rs.status as string,
token: rs.token as string,
refno: rs.refno as string,
};
} catch (e) {
console.error(e);
throw new TRPCError({
message: `Unable to request OTP:\n${e}`,
code: "INTERNAL_SERVER_ERROR",
});
}
}
async function verifyOtp(token: string, pin: string) {
try {
console.log(token, pin);
let pt = await db.query.phoneToken.findFirst({
where: (pt, { eq }) => eq(pt.token, token),
orderBy: (pt, { desc }) => desc(pt.createdOn),
});
if (pt === undefined) {
throw new TRPCError({
message: `Invalid token`,
code: "BAD_REQUEST",
});
}
pt;
let rs = await fetch(Config.sms_api_verify_endpoint, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
key: Config.sms_api_key,
secret: Config.sms_api_secret,
token,
pin,
}),
}).then((res) => res.json());
if (rs.errors) {
console.error(rs);
throw new TRPCError({
message: `Unable to verify OTP`,
code: "BAD_REQUEST",
});
} else {
await db.delete(phoneToken).where(eq(phoneToken.phone, pt.phone));
console.log(rs, pt.phone);
return rs;
}
} catch (e) {
console.error(e);
throw new TRPCError({
message: `Unable to verify OTP:\n${e}`,
code: "BAD_REQUEST",
});
}
}