diff --git a/src/controllers/BlogController.ts b/src/controllers/BlogController.ts new file mode 100644 index 00000000..9af1e146 --- /dev/null +++ b/src/controllers/BlogController.ts @@ -0,0 +1,34 @@ +import { Request, Response, NextFunction } from "express"; +import { BlogService } from "../services/blog.services"; + +const blogService = new BlogService(); + +const getPaginatedBlogs = async (req: Request, res: Response, next: NextFunction) => { + try { + const page = parseInt(req.query.page as string) || 1; + const pageSize = parseInt(req.query.page_size as string) || 10; + + if (page <= 0 || pageSize <= 0) { + return res.status(400).json({ error: "Invalid page or page_size parameter" }); + } + + const { count, next, previous, results } = await blogService.getPaginatedBlogPosts(page, pageSize); + + const summaries = results.map(blog => ({ + id: blog.id, + title: blog.title, + excerpt: blog.content.substring(0, 100), // Example: first 100 characters as excerpt + image_url: blog.imageUrl, + tags: blog.tags, + created_at: blog.createdAt, + })); + + res.status(200).json({ count, next, previous, results: summaries }); + } catch (error) { + next(error); + } +}; + + + +export { getPaginatedBlogs }; diff --git a/src/controllers/index.ts b/src/controllers/index.ts index d850f3d9..d484fe56 100644 --- a/src/controllers/index.ts +++ b/src/controllers/index.ts @@ -1,5 +1,6 @@ // silence is golden export * from "./AuthController"; export * from "./UserController"; +export * from "./BlogController" export * from "./HelpController"; export * from "./NotificationController"; diff --git a/src/index.ts b/src/index.ts index 6fd3cdff..a3d21796 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,14 +6,7 @@ import express, { Express, Request, Response } from "express"; import config from "./config"; import dotenv from "dotenv"; import cors from "cors"; -import { - userRouter, - authRoute, - helpRouter, - testimonialRoute, - notificationRouter, - smsRouter, -} from "./routes"; +import { userRouter, authRoute, testimonialRoute, notificationRouter, smsRouter, blogRoute } from "./routes"; import { routeNotFound, errorHandler } from "./middleware"; import { orgRouter } from "./routes/organisation"; import swaggerUi from "swagger-ui-express"; @@ -47,6 +40,7 @@ server.use("/api/v1/auth", authRoute); server.use("/api/v1/help-center", helpRouter); server.use("/api/v1/sms", smsRouter); server.use("/api/v1", testimonialRoute); +server.use("/api/v1/blogs", blogRoute); server.use("/api/v1/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec)); server.use(routeNotFound); server.use(errorHandler); diff --git a/src/middleware/index.ts b/src/middleware/index.ts index d0d8e7b7..b204764a 100644 --- a/src/middleware/index.ts +++ b/src/middleware/index.ts @@ -1,2 +1,4 @@ export * from "./error"; export * from "./auth"; +export * from "./methodNotAllowed"; + diff --git a/src/middleware/methodNotAllowed.ts b/src/middleware/methodNotAllowed.ts new file mode 100644 index 00000000..dec686cc --- /dev/null +++ b/src/middleware/methodNotAllowed.ts @@ -0,0 +1,8 @@ +// src/middleware/methodNotAllowed.ts +import { Request, Response, NextFunction } from 'express'; + +const methodNotAllowed = (req: Request, res: Response, next: NextFunction) => { + res.status(405).json({ error: 'This method is not allowed.' }); +}; + +export { methodNotAllowed }; diff --git a/src/routes/blog.ts b/src/routes/blog.ts new file mode 100644 index 00000000..85bcf9f0 --- /dev/null +++ b/src/routes/blog.ts @@ -0,0 +1,12 @@ +// src/routes/blogRoute.ts +import { Router } from "express"; +import { getPaginatedBlogs } from "../controllers/BlogController"; +import { methodNotAllowed } from "../middleware"; + +const blogRoute = Router(); + +blogRoute.post("/"); +blogRoute.get("/", getPaginatedBlogs); +blogRoute.all("/", methodNotAllowed); + +export { blogRoute }; diff --git a/src/routes/index.ts b/src/routes/index.ts index 95320446..e8bbeb02 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -3,5 +3,7 @@ export * from "./auth"; export * from "./user"; export * from "./help-center"; export * from "./testimonial"; +export * from "./notificationsettings" +export * from "./blog"; export * from "./sms"; -export * from "./notificationsettings"; + diff --git a/src/services/blog.services.ts b/src/services/blog.services.ts new file mode 100644 index 00000000..12e75a9c --- /dev/null +++ b/src/services/blog.services.ts @@ -0,0 +1,22 @@ +import { Blog } from "../models"; +import { IBlogService } from "../types"; +import AppDataSource from '../data-source'; + +export class BlogService implements IBlogService { + private blogRepository = AppDataSource.getRepository(Blog); + + async getPaginatedBlogPosts(page: number = 1, pageSize: number = 10): Promise<{ count: number, next: string | null, previous: string | null, results: BlogPost[] }> { + const [results, count] = await this.blogRepository.findAndCount({ + relations: ['author'], + skip: (page - 1) * pageSize, + take: pageSize, + order: { createdAt: "DESC" } + }); + + const next = page * pageSize < count ? `/api/v1/blogs?page=${page + 1}&page_size=${pageSize}` : null; + const previous = page > 1 ? `/api/v1/blogs?page=${page - 1}&page_size=${pageSize}` : null; + + return { count, next, previous, results }; + } + +} diff --git a/src/services/index.ts b/src/services/index.ts index 93986fe3..a99990c3 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -1,3 +1,4 @@ export * from "./auth.services"; export * from "./user.services"; -export * from "./help.services"; +export * from "./blog.services"; +export * from "./help.services"; \ No newline at end of file diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 67d1bb76..76185596 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -1,5 +1,16 @@ import { User } from "../models"; +export interface PaginatedBlogResponse { + count: number; + next: string | null; + previous: string | null; + results: Blog[]; +} + +export interface IBlogService { + getPaginatedBlogPosts(page: number, pageSize: number): Promise; +} + export interface IUserService { getUserById(id: string): Promise; getAllUsers(): Promise;