Skip to content

Commit 5ced11f

Browse files
authored
Merge pull request #39 from sam28u/main
added get methods
2 parents 2baa571 + fbf0147 commit 5ced11f

File tree

5 files changed

+249
-10
lines changed

5 files changed

+249
-10
lines changed

apps/server/src/routers/auth.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import crypto from "node:crypto";
2-
import type { FastifyInstance } from "fastify";
2+
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
33
import jwt from "jsonwebtoken";
44
import { users } from "@/db/schema/user.schema";
55
import { DrizzleClient } from "../db/index";
@@ -267,6 +267,18 @@ export const authenticateUser: AuthenticationMiddleware = async (
267267
}
268268
};
269269

270+
// user authentication - added by sambhu ( to remove the code redundancy)
271+
export const attachUser = async (request: FastifyRequest, reply: FastifyReply) => {
272+
const authRequest = request as AuthenticatedRequest;
273+
const user = await DrizzleClient.query.users.findFirst({
274+
where: (u, { eq }) => eq(u.id, authRequest.userId),
275+
});
276+
if (!user) {
277+
return reply.status(404).send({ success: false, error: "User not found" });
278+
}
279+
authRequest.user = user;
280+
};
281+
270282
// Optional authentication middleware - doesn't block request if no auth
271283
export const optionalAuth: AuthenticationMiddleware = async (
272284
request,

apps/server/src/routers/posts.ts

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,100 @@
1-
import { eq } from "drizzle-orm";
2-
import type { FastifyInstance } from "fastify";
1+
import { count, eq } from "drizzle-orm";
2+
import type { FastifyInstance , FastifyRequest} from "fastify";
33
import { DrizzleClient } from "@/db/index";
44
import { posts as postsTable } from "@/db/schema/post.schema";
55
import {
66
createPostSchema,
77
postIdParamsSchema,
88
updatePostSchema,
99
} from "@/dto/posts.dto";
10-
import { authenticateUser } from "./auth";
10+
import { threadIdParamsSchema } from "@/dto/threads.dto";
11+
import { attachUser, authenticateUser } from "./auth";
1112

1213
export async function postRoutes(fastify: FastifyInstance) {
14+
15+
fastify.get(
16+
"/threads/:id/posts",
17+
{
18+
preHandler: [authenticateUser , attachUser],
19+
schema: {
20+
querystring: {
21+
type: "object",
22+
properties: {
23+
page: { type: "integer", minimum: 1, default: 1 },
24+
limit: { type: "integer", minimum: 1, maximum: 100, default: 20 },
25+
},
26+
},
27+
},
28+
},
29+
async (
30+
request: FastifyRequest<{
31+
Params: { id: string };
32+
Querystring: { page: number; limit: number };
33+
}>,
34+
reply
35+
) => {
36+
const { page, limit } = request.query;
37+
const offset = (page - 1) * limit;
38+
const params = threadIdParamsSchema.safeParse(request.params);
39+
if (!params.success)
40+
return reply
41+
.status(400)
42+
.send({ success: false, error: "Invalid thread ID" });
43+
const threadId = params.data.id;
44+
try {
45+
const [threadPosts, countResult] = await Promise.all([
46+
DrizzleClient.query.posts.findMany({
47+
where: (p, { eq }) => eq(p.threadId, threadId),
48+
orderBy: (p, { asc }) => [asc(p.createdAt)],
49+
limit: limit,
50+
offset: offset,
51+
}),
52+
DrizzleClient.select({ total: count() })
53+
.from(postsTable)
54+
.where(eq(postsTable.threadId, threadId)),
55+
]);
56+
57+
return reply.status(200).send({
58+
success: true,
59+
posts: threadPosts,
60+
pagination: {
61+
page,
62+
limit,
63+
count: countResult[0]?.total ?? 0,
64+
},
65+
});
66+
} catch (error) {
67+
fastify.log.error("Error fetching posts for thread:", error);
68+
return reply
69+
.status(500)
70+
.send({ success: false, error: "Failed to fetch posts" });
71+
}
72+
}
73+
);
74+
75+
fastify.get(
76+
"/posts/:id",
77+
{ preHandler: [authenticateUser , attachUser ], },
78+
async (request, reply) => {
79+
const params = postIdParamsSchema.safeParse(request.params);
80+
if (!params.success) {
81+
return reply.status(400).send({ success: false, error: "Invalid post id" });
82+
}
83+
try {
84+
const post = await DrizzleClient.query.posts.findFirst({
85+
where: (p, { eq }) => eq(p.id, params.data.id),
86+
});
87+
if (!post) {
88+
return reply.status(404).send({ success: false, error: "Post not found" });
89+
}
90+
return reply.status(200).send({ success: true, post });
91+
} catch (error) {
92+
fastify.log.error("Error fetching post:", error);
93+
return reply.status(500).send({ success: false, error: "Failed to fetch post" });
94+
}
95+
}
96+
);
97+
1398
// Create post
1499
fastify.post(
15100
"/posts",

apps/server/src/routers/threads.ts

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,107 @@
1-
import { eq } from "drizzle-orm";
2-
import type { FastifyInstance } from "fastify";
1+
import { count, eq } from "drizzle-orm";
2+
import type { FastifyInstance , FastifyRequest} from "fastify";
33
import {
44
createThreadSchema,
55
threadIdParamsSchema,
66
updateThreadSchema,
77
} from "@/dto/threads.dto";
88
import { DrizzleClient } from "../db/index";
99
import { threads as threadsTable } from "../db/schema/thread.schema";
10-
import { authenticateUser } from "./auth";
10+
import { attachUser, authenticateUser } from "./auth";
11+
import { topicIdParamsSchema } from "@/dto/topics.dto";
1112

1213
export async function threadRoutes(fastify: FastifyInstance) {
14+
fastify.get(
15+
"/topics/:id/threads",
16+
{
17+
preHandler: [authenticateUser , attachUser ],
18+
schema: {
19+
querystring: {
20+
type: "object",
21+
properties: {
22+
page: { type: "integer", minimum: 1, default: 1 },
23+
limit: { type: "integer", minimum: 1, maximum: 50, default: 10 },
24+
},
25+
},
26+
},
27+
},
28+
async (
29+
request: FastifyRequest<{
30+
Params: { id: string };
31+
Querystring: { page: number; limit: number };
32+
}>,
33+
reply
34+
) => {
35+
const { page, limit } = request.query;
36+
const offset = (page - 1) * limit;
37+
const params = topicIdParamsSchema.safeParse(request.params);
38+
if (!params.success)
39+
return reply
40+
.status(400)
41+
.send({ success: false, error: "Invalid topic ID" });
42+
const topicId = params.data.id;
43+
try {
44+
const [relatedThreads, countResult] = await Promise.all([
45+
DrizzleClient.query.threads.findMany({
46+
where: (t, { eq }) => eq(t.topicId, topicId),
47+
orderBy: (t, { desc }) => [desc(t.createdAt)],
48+
limit: limit,
49+
offset: offset,
50+
}),
51+
DrizzleClient.select({ total: count() })
52+
.from(threadsTable)
53+
.where(eq(threadsTable.topicId, topicId)),
54+
]);
55+
56+
return reply.status(200).send({
57+
success: true,
58+
threads: relatedThreads,
59+
pagination: {
60+
page,
61+
limit,
62+
count: countResult[0]?.total ?? 0,
63+
},
64+
});
65+
} catch (error) {
66+
fastify.log.error("Error fetching threads for topic:", error);
67+
return reply
68+
.status(500)
69+
.send({ success: false, error: "Failed to fetch threads" });
70+
}
71+
}
72+
);
73+
74+
75+
76+
fastify.get(
77+
"/threads/:id",
78+
{ preHandler: [authenticateUser , attachUser ], },
79+
async (request, reply) => {
80+
const params = threadIdParamsSchema.safeParse(request.params);
81+
if (!params.success) {
82+
return reply
83+
.status(400)
84+
.send({ success: false, error: "Invalid thread id" });
85+
}
86+
try {
87+
const thread = await DrizzleClient.query.threads.findFirst({
88+
where: (t, { eq }) => eq(t.id, params.data.id),
89+
});
90+
if (!thread) {
91+
return reply
92+
.status(404)
93+
.send({ success: false, error: "Thread not found" });
94+
}
95+
return reply.status(200).send({ success: true, thread });
96+
} catch (error) {
97+
fastify.log.error("Error fetching thread:", error);
98+
return reply
99+
.status(500)
100+
.send({ success: false, error: "Failed to fetch thread" });
101+
}
102+
}
103+
);
104+
13105
fastify.post(
14106
"/threads/new",
15107
{ preHandler: authenticateUser },

apps/server/src/routers/topics.ts

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,63 @@
1-
import { eq } from "drizzle-orm";
2-
import type { FastifyInstance } from "fastify";
1+
import { count, eq } from "drizzle-orm";
2+
import type { FastifyInstance, FastifyRequest } from "fastify";
33
import { DrizzleClient } from "@/db/index";
44
import { topics as topicsTable } from "@/db/schema/topic.schema";
55
import {
66
createTopicSchema,
77
topicIdParamsSchema,
88
updateTopicSchema,
99
} from "@/dto/topics.dto";
10-
import { authenticateUser } from "./auth";
10+
import { attachUser, authenticateUser } from "./auth";
1111

1212
export async function topicRoutes(fastify: FastifyInstance) {
13+
14+
fastify.get(
15+
"/topics",
16+
{
17+
preHandler: [authenticateUser , attachUser],
18+
schema: {
19+
querystring: {
20+
type: "object",
21+
properties: {
22+
page: { type: "integer", minimum: 1, default: 1 },
23+
limit: { type: "integer", minimum: 1, maximum: 100, default: 10 },
24+
},
25+
},
26+
},
27+
},
28+
async (
29+
request: FastifyRequest<{ Querystring: { page: number; limit: number } }>,
30+
reply
31+
) => {
32+
const { page, limit } = request.query;
33+
const offset = (page - 1) * limit;
34+
try {
35+
const [topics, countResult] = await Promise.all([
36+
DrizzleClient.query.topics.findMany({
37+
limit: limit,
38+
offset: offset,
39+
orderBy: (table, { desc }) => [desc(table.createdAt)],
40+
}),
41+
DrizzleClient.select({ total: count() }).from(topicsTable),
42+
]);
43+
return reply.status(200).send({
44+
success: true,
45+
data: topics,
46+
pagination: {
47+
page,
48+
limit,
49+
count: countResult[0]?.total ?? 0,
50+
},
51+
});
52+
} catch (error) {
53+
fastify.log.error({ err: error }, "Failed to fetch topics");
54+
return reply
55+
.status(500)
56+
.send({ success: false, error: "Failed to fetch topics" });
57+
}
58+
}
59+
);
60+
1361
fastify.post(
1462
"/topics",
1563
{ preHandler: authenticateUser },

apps/server/src/types/auth.types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import { users } from "@/db/schema/user.schema";
12
import type { FastifyReply, FastifyRequest } from "fastify";
23

34
export interface AuthenticatedRequest extends FastifyRequest {
5+
user: typeof users.$inferSelect;
46
userId: string;
57
}
68

0 commit comments

Comments
 (0)