diff --git a/docs/blog.md b/docs/blog.md new file mode 100644 index 00000000..fbef0a76 --- /dev/null +++ b/docs/blog.md @@ -0,0 +1,180 @@ +# Blog API Documentation + +This project provides an API for managing blog posts, including creating, editing, deleting, and retrieving blog posts. The API is documented using Swagger. + +## Getting Started + +### Prerequisites + +Make sure you have the following installed on your machine: + +- Node.js (>=14.x) +- Yarn (>=1.x) + +### Installation + +1. Clone the repository: + + ```bash + git clone repo + cd repo + ``` + +2. Install dependencies: + ```bash + yarn install + ``` + +### Running the Server + +To start the server, run: + +```bash +yarn start +``` + +## API Endpoints + +### Authentication + +Ensure that users are authenticated before accessing the endpoints that modify or delete resources. + +#### Login + +- **URL**: `/api/v1/auth/login` +- **Method**: `POST` +- **Request Body**: + ```json + { + "username": "user@example.com", + "password": "password123" + } + ``` +- **Responses**: + - `200 OK`: Successfully authenticated + - `401 Unauthorized`: Invalid credentials + +#### Register + +- **URL**: `/api/v1/auth/register` +- **Method**: `POST` +- **Request Body**: + ```json + { + "username": "user@example.com", + "password": "password123", + "name": "John Doe" + } + ``` +- **Responses**: + - `201 Created`: Successfully registered + - `400 Bad Request`: Invalid input + +### Create a Blog Post + +- **URL**: `/api/v1/blog/create` +- **Method**: `POST` +- **Authentication**: Required +- **Request Body**: + ```json + { + "title": "Sample Blog Post", + "content": "This is a sample blog post.", + "author": "John Doe", + "Imageurl": "http://example.com/image.jpg", + "categories": ["Tech", "Programming"], + "tags": ["Node.js", "Express"], + "likes": [], + "comments": [] + } + ``` +- **Responses**: + - `201 Created`: Blog post created successfully + - `400 Bad Request`: Invalid request body + - `401 Unauthorized`: Authentication required + - `500 Internal Server Error`: Server error + +### Get All Blog Posts with Pagination + +- **URL**: `/api/v1/blog` +- **Method**: `GET` +- **Query Parameters**: + - `page`: Page number (default: 1) + - `limit`: Number of posts per page (default: 10) + - `offset`: Number of posts to skip (default: 0) +- **Responses**: + - `200 OK`: List of blog posts + - `500 Internal Server Error`: Server error + +### Get a Single Blog Post by ID + +- **URL**: `/api/v1/blog/:id` +- **Method**: `GET` +- **Parameters**: + - `id`: Blog post ID +- **Responses**: + - `200 OK`: Blog post details + - `404 Not Found`: Blog post not found + - `500 Internal Server Error`: Server error + +### Edit a Blog Post by ID + +- **URL**: `/api/v1/blog/:id` +- **Method**: `PUT` +- **Authentication**: Required +- **Parameters**: + - `id`: Blog post ID +- **Request Body**: + ```json + { + "title": "Updated Blog Post", + "content": "This is an updated blog post.", + "author": "John Doe", + "Imageurl": "http://example.com/new-image.jpg", + "categories": ["Tech", "Programming"], + "tags": ["Node.js", "Express"] + } + ``` +- **Responses**: + - `200 OK`: Blog post updated successfully + - `400 Bad Request`: Invalid request body + - `401 Unauthorized`: Authentication required + - `404 Not Found`: Blog post not found + - `500 Internal Server Error`: Server error + +### Delete a Blog Post by ID + +- **URL**: `/api/v1/blog/:id` +- **Method**: `DELETE` +- **Authentication**: Required +- **Parameters**: + - `id`: Blog post ID +- **Responses**: + - `204 No Content`: Blog post deleted successfully + - `401 Unauthorized`: Authentication required + - `404 Not Found`: Blog post not found + - `500 Internal Server Error`: Server error + +## Project Structure + +``` +├── src +│ ├── models +│ │ └── blog.ts +│ ├── routes +│ │ └── blog.ts +│ ├── blogSwaggerConfig.ts +│ └── server.ts +├── .gitignore +├── package.json +├── tsconfig.json +└── README.md +``` + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +``` + +``` diff --git a/src/controllers/OrgController.ts b/src/controllers/OrgController.ts index bcbd52f3..7834bdd5 100644 --- a/src/controllers/OrgController.ts +++ b/src/controllers/OrgController.ts @@ -13,9 +13,10 @@ export class OrgController { * post: * summary: Create a new organisation * description: This endpoint allows a user to create a new organisation - * tags: - * - Organisation + * tags: [Organisations] * operationId: createOrganisation + * security: + * - bearerAuth: [] * requestBody: * description: Organisation payload * required: true @@ -30,8 +31,29 @@ export class OrgController { * description: * type: string * example: This is a sample organisation. + * email: + * type: string + * example: name@gmail.com + * industry: + * type: string + * example: entertainment + * type: + * type: string + * example: music + * country: + * type: string + * example: Nigeria + * state: + * type: string + * example: Oyo * required: * - name + * - description + * - email + * - industry + * - type + * - country + * - state * responses: * '201': * description: Organisation created successfully @@ -58,6 +80,27 @@ export class OrgController { * description: * type: string * example: This is a sample organisation. + * email: + * type: string + * example: abc@gmail.com + * industry: + * type: string + * example: entertainment + * type: + * type: string + * example: music + * country: + * type: string + * example: Nigeria + * state: + * type: string + * example: Oyo + * slug: + * type: string + * example: 86820688-fd94-4b58-9bdd-99a701714a77 + * owner_id: + * type: string + * example: 86820688-fd94-4b58-9bdd-99a701714a76 * createdAt: * type: string * format: date-time @@ -99,7 +142,14 @@ export class OrgController { * status_code: * type: integer * example: 500 + * components: + * securitySchemes: + * bearerAuth: + * type: http + * scheme: bearer + * bearerFormat: JWT */ + async createOrganisation(req: Request, res: Response, next: NextFunction) { try { const payload = req.body; diff --git a/src/controllers/PaymentLemonSqueezyController.ts b/src/controllers/PaymentLemonSqueezyController.ts index af402888..935ff9f9 100644 --- a/src/controllers/PaymentLemonSqueezyController.ts +++ b/src/controllers/PaymentLemonSqueezyController.ts @@ -1,9 +1,43 @@ +/** + * @swagger + * tags: + * name: Payments + * description: Payment management with LemonSqueezy + */ + import { Request, Response } from "express"; import crypto from "crypto"; import config from "../config"; import { Payment } from "../models/payment"; import AppDataSource from "../data-source"; + +/** + * @swagger + * /api/v1/payments/lemonsqueezy/initiate: + * get: + * summary: Initiates a payment using LemonSqueezy + * tags: [Payments] + * responses: + * 200: + * description: Payment initiation link + * content: + * text/html: + * schema: + * type: string + * example: Make Payments + * 500: + * description: An error occurred while processing the payment + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * example: An error occurred while processing the payment + */ + export const makePaymentLemonSqueezy = async (req: Request, res: Response) => { try { return res.send( @@ -17,6 +51,36 @@ export const makePaymentLemonSqueezy = async (req: Request, res: Response) => { } }; + +/** + * @swagger + * /api/v1/payments/lemonsqueezy/webhook: + * post: + * summary: Handles LemonSqueezy webhook notifications + * tags: [Payments] + * requestBody: + * required: true + * content: + * text/plain: + * schema: + * type: string + * responses: + * 200: + * description: Webhook received successfully + * content: + * text/plain: + * schema: + * type: string + * example: Webhook received + * 400: + * description: Webhook verification failed + * content: + * text/plain: + * schema: + * type: string + * example: Webhook verification failed + */ + export const LemonSqueezyWebhook = async (req: Request, res: Response) => { try { const secret = config.LEMONSQUEEZY_SIGNING_KEY; diff --git a/src/controllers/ProductController.ts b/src/controllers/ProductController.ts index ed4019f2..85ba1baf 100644 --- a/src/controllers/ProductController.ts +++ b/src/controllers/ProductController.ts @@ -384,6 +384,8 @@ export class ProductController { * message: * type: string * example: "Valid product ID, name, description, price, and stock must be provided." + * 401: + * description: Unauthorized * 500: * description: Server error * content: diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index 14ca51fc..9751a3a7 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -1,17 +1,69 @@ // src/controllers/UserController.ts -import { Request, Response, NextFunction } from "express"; -import { UserService } from "../services"; -import { HttpError } from "../middleware"; import { isUUID } from "class-validator"; +import { NextFunction, Request, Response } from "express"; import { validate } from "uuid"; +import { HttpError } from "../middleware"; +import { UserService } from "../services"; class UserController { private userService: UserService; + /** + * @swagger + * tags: + * name: User + * description: User related routes + */ constructor() { this.userService = new UserService(); } + /** + * @swagger + * /api/v1/users/me: + * get: + * tags: + * - User + * summary: Get User profile + * security: + * - bearerAuth: [] + * description: Api endpoint to retrieve the profile data of the currently authenticated user. This will allow users to access their own profile information. + * responses: + * 200: + * description: Fetched User profile Successfully + * content: + * application/json: + * schema: + * type: object + * properties: + * status_code: + * type: number + * example: 200 + * data: + * type: object + * properties: + * id: + * type: string + * example: 58b6 + * user_name: + * type: string + * example: yasuke + * email: + * type: string + * example: sam@gmail.com + * profile_picture: + * type: string + * example: https://avatar.com + * + * 401: + * description: Unauthorized access + * 404: + * description: Not found + * 500: + * description: Internal Server Error + * + */ + static async getProfile(req: Request, res: Response, next: NextFunction) { try { const { id } = req.user; @@ -68,6 +120,61 @@ class UserController { } } + /** + * @swagger + * /api/v1/users: + * get: + * tags: + * - User + * summary: Get all users + * security: + * - bearerAuth: [] + * responses: + * 200: + * description: Get all users + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: success + * status_code: + * type: integer + * example: 200 + * message: + * type: string + * example: Users retrieved successfully + * pagination: + * type: object + * properties: + * totalItems: + * type: integer + * example: 100 + * totalPages: + * type: integer + * example: 10 + * currentPage: + * type: integer + * example: 1 + * data: + * type: array + * items: + * type: object + * properties: + * user_name: + * type: string + * example: Lewis + * email: + * type: string + * example: lewis@gmail.com + * 401: + * description: Unauthorized + * 500: + * description: Server Error + */ + async getAllUsers(req: Request, res: Response) { try { const users = await this.userService.getAllUsers(); @@ -77,6 +184,88 @@ class UserController { } } + /** + * @swagger + * /api/v1/user/{id}: + * delete: + * tags: + * - User + * summary: Delete a user + * security: + * - bearerAuth: [] + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: string + * description: The ID of the user + * responses: + * 202: + * description: User deleted successfully + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: success + * status_code: + * type: number + * example: 202 + * message: + * type: string + * example: User deleted successfully + * 400: + * description: Bad request + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: unsuccessful + * status_code: + * type: number + * example: 400 + * message: + * type: string + * example: Valid id must be provided + * 404: + * description: Not found + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: unsuccessful + * status_code: + * type: number + * example: 404 + * message: + * type: string + * example: User not found + * 500: + * description: Server Error + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: unsuccessful + * status_code: + * type: number + * example: 500 + * message: + * type: string + * example: Failed to perform soft delete + */ async deleteUser(req: Request, res: Response) { const id = req.params.id; @@ -109,6 +298,125 @@ class UserController { } } + /** + * @swagger + * /api/v1/users/{id}: + * patch: + * tags: + * - User + * summary: Update a user + * description: API endpoint that allows authenticated super admins to update a single user's details. This endpoint ensures that only users with super admin privileges can modify user information, maintaining system security. + * security: + * - bearerAuth: [] + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: string + * description: The ID of the user to update + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * firstName: + * type: string + * example: New + * lastName: + * type: string + * email: + * type: string + * role: + * type: string + * password: + * type: string + * isVerified: + * type: boolean + * example: true + * responses: + * 200: + * description: Successfully updated the user + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: success + * status_code: + * type: number + * example: 200 + * data: + * type: object + * properties: + * id: + * type: string + * email: + * type: string + * role: + * type: string + * created_at: + * type: string + * format: date-time + * updated_at: + * type: string + * format: date-time + * 422: + * description: Validation error + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: Error + * status_code: + * type: integer + * example: 422 + * message: + * type: string + * example: "Invalid user details provided." + * 403: + * description: Access denied + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: Error + * status_code: + * type: integer + * example: 403 + * message: + * type: string + * example: "Access denied. Super admin privileges required." + * 404: + * description: User not found + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: unsuccessful + * status_code: + * type: integer + * example: 404 + * message: + * type: string + * example: "User with id '123' not found" + * 500: + * description: Server Error + */ + public async updateUserProfile(req: Request, res: Response) { try { const user = await this.userService.updateUserProfile( diff --git a/src/routes/blog.ts b/src/routes/blog.ts index ed11afa8..01715d76 100644 --- a/src/routes/blog.ts +++ b/src/routes/blog.ts @@ -7,13 +7,108 @@ import { updateBlogController } from "../controllers/updateBlogController"; const blogRouter = Router(); const blogController = new BlogController(); +/** + * @swagger + * /api/v1/blog/create: + * post: + * summary: Create a blog post + * description: Allow user to create a blog post + * requestBody: + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/BlogInput' + * responses: + * '201': + * description: Blog post created successfully + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Blog' + * '400': + * description: Bad request + * '500': + * description: Server error + */ + blogRouter.post("/create", authMiddleware, createBlogController); + +/** + * @swagger + * /api/v1/blog: + * get: + * summary: Get all blog posts with pagination + * description: Allow user to get all blog posts with pagination (page, limit, offset) + * parameters: + * - name: page + * in: query + * schema: + * type: integer + * default: 1 + * - name: limit + * in: query + * schema: + * type: integer + * default: 10 + * - name: offset + * in: query + * schema: + * type: integer + * default: 0 + * responses: + * '200': + * description: List of blog posts + * content: + * application/json: + * schema: + * type: array + * items: + * $ref: '#/components/schemas/Blog' + * '500': + * description: Server error + */ + blogRouter.get("/", blogController.listBlogs.bind(blogController)); + blogRouter.get( "/", authMiddleware, blogController.listBlogs.bind(blogController), ); + +/** + * @swagger + * /api/v1/blog/{id}: + * put: + * summary: Edit a blog post by ID + * description: Allow an author to edit a blog post by ID (requires authentication) + * parameters: + * - name: id + * in: path + * required: true + * schema: + * type: string + * requestBody: + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/BlogInput' + * responses: + * '200': + * description: Blog post updated successfully + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Blog' + * '400': + * description: Bad request + * '404': + * description: Blog post not found + * '500': + * description: Server error + */ blogRouter.put("/:id", authMiddleware, updateBlogController); blogRouter.get( "/", @@ -21,6 +116,26 @@ blogRouter.get( blogController.listBlogs.bind(blogController), ); +/** + * @swagger + * /api/v1/blog/{id}: + * delete: + * summary: Delete a blog post by ID + * description: Allow an author to delete a blog post by ID (requires authentication) + * parameters: + * - name: id + * in: path + * required: true + * schema: + * type: string + * responses: + * '204': + * description: Blog post deleted successfully + * '404': + * description: Blog post not found + * '500': + * description: Server error + */ blogRouter.delete("/:id", blogController.deleteBlogPost.bind(blogController)); export { blogRouter }; diff --git a/src/routes/user.ts b/src/routes/user.ts index 2e3e7d42..0f57c4a8 100644 --- a/src/routes/user.ts +++ b/src/routes/user.ts @@ -8,13 +8,311 @@ const upload = multerConfig.single("avatarUrl"); const userRouter = Router(); const userController = new UserController(); +/** + * @openapi + * /users: + * get: + * summary: Retrieves a list of all users + * tags: + * - User + * responses: + * '200': + * description: A list of users + * content: + * application/json: + * schema: + * type: array + * items: + * type: object + * properties: + * id: + * type: string + * example: 96cf0567-9ca6-4ce0-b9f7-e3fa816fc070 + * name: + * type: string + * example: John Doe + * email: + * type: string + * example: john.doe@example.com + * role: + * type: string + * example: user + * '500': + * description: Internal Server Error + */ userRouter.get("/", userController.getAllUsers.bind(UserController)); + +/** + * @openapi + * /users/{id}: + * delete: + * summary: Deletes a user by ID + * tags: + * - User + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: string + * format: uuid + * description: The ID of the user to delete + * security: + * - bearerAuth: [] + * responses: + * '202': + * description: User deleted successfully + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: success + * status_code: + * type: integer + * example: 202 + * message: + * type: string + * example: User deleted successfully + * '400': + * description: Valid id must be provided + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * example: unsuccessful + * status_code: + * type: integer + * example: 400 + * message: + * type: string + * example: Valid id must be provided + * '404': + * description: User not found + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: User Not Found + * '500': + * description: Internal Server Error + */ userRouter.delete( "/:id", authMiddleware, userController.deleteUser.bind(userController), ); + +/** + * @openapi + * /users/me: + * get: + * summary: Retrieves the profile data of the currently authenticated user + * tags: + * - User + * security: + * - bearerAuth: [] + * responses: + * '200': + * description: User profile details retrieved successfully + * content: + * application/json: + * schema: + * type: object + * properties: + * status_code: + * type: integer + * example: 200 + * message: + * type: string + * example: User profile details retrieved successfully + * data: + * type: object + * properties: + * id: + * type: string + * example: 96cf0567-9ca6-4ce0-b9f7-e3fa816fc070 + * name: + * type: string + * example: John Doe + * email: + * type: string + * example: john.doe@example.com + * role: + * type: string + * example: user + * profile_id: + * type: string + * example: 123e4567-e89b-12d3-a456-426614174000 + * first_name: + * type: string + * example: John + * last_name: + * type: string + * example: Doe + * phone: + * type: string + * example: +1234567890 + * avatar_url: + * type: string + * example: https://example.com/avatar.jpg + * '400': + * description: Invalid User ID Format + * content: + * application/json: + * schema: + * type: object + * properties: + * status_code: + * type: integer + * example: 400 + * error: + * type: string + * example: Unauthorized! Invalid User Id Format + * '401': + * description: Unauthorized! No ID provided + * content: + * application/json: + * schema: + * type: object + * properties: + * status_code: + * type: integer + * example: 401 + * error: + * type: string + * example: Unauthorized! No ID provided + * '404': + * description: User Not Found + * content: + * application/json: + * schema: + * type: object + * properties: + * status_code: + * type: integer + * example: 404 + * error: + * type: string + * example: User Not Found + * '500': + * description: Internal Server Error + * content: + * application/json: + * schema: + * type: object + * properties: + * status_code: + * type: integer + * example: 500 + * error: + * type: string + * example: Internal Server Error + */ userRouter.get("/me", authMiddleware, UserController.getProfile); + +/** + * @openapi + * /users/{id}: + * put: + * summary: Updates the profile of a user + * tags: + * - User + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: string + * format: uuid + * description: The ID of the user to update + * - in: formData + * name: avatarUrl + * type: file + * description: The avatar image to upload + * requestBody: + * content: + * application/json: + * schema: + * type: object + * properties: + * first_name: + * type: string + * last_name: + * type: string + * phone: + * type: string + * avatarUrl: + * type: string + * format: binary + * security: + * - bearerAuth: [] + * responses: + * '200': + * description: User profile updated successfully + * content: + * application/json: + * schema: + * type: object + * properties: + * id: + * type: string + * example: 96cf0567-9ca6-4ce0-b9f7-e3fa816fc070 + * name: + * type: string + * example: John Doe + * email: + * type: string + * example: john.doe@example.com + * role: + * type: string + * example: user + * profile: + * type: object + * properties: + * first_name: + * type: string + * example: John + * last_name: + * type: string + * example: Doe + * phone: + * type: string + * example: +1234567890 + * avatarUrl: + * type: string + * example: https://example.com/avatar.jpg + * '400': + * description: Bad request + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: Valid id must be provided + * '404': + * description: User not found + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: User Not Found + * '500': + * description: Internal Server Error + */ userRouter.put( "/:id", authMiddleware, diff --git a/src/schema/product.schema.ts b/src/schema/product.schema.ts index 80160643..ded05c53 100644 --- a/src/schema/product.schema.ts +++ b/src/schema/product.schema.ts @@ -1,4 +1,4 @@ -import { number, object, string, TypeOf } from "zod"; +import { boolean, number, object, string, TypeOf } from "zod"; /** * @openapi @@ -55,6 +55,12 @@ const payload = { }), }; +const paginationSchema = object({ + totalItems: number(), + totalPages: number(), + currentPage: number(), +}); + const params = { params: object({ productId: string({ @@ -80,7 +86,16 @@ export const getProductSchema = object({ ...params, }); +export const getAllProductSchema = object({ + success: boolean(), + message: string(), + status_code: number(), + pagination: paginationSchema, + ...payload, +}); + export type CreateProductInput = TypeOf; export type UpdateProductInput = TypeOf; export type ReadProductInput = TypeOf; export type DeleteProductInput = TypeOf; +export type GetAllProductsResponse = TypeOf; diff --git a/src/schema/user.schema.ts b/src/schema/user.schema.ts new file mode 100644 index 00000000..b5cc23c8 --- /dev/null +++ b/src/schema/user.schema.ts @@ -0,0 +1,137 @@ +import { array, number, object, string, TypeOf } from "zod"; + +/** + * @openapi + * components: + * schemas: + * User: + * type: object + * properties: + * user_name: + * type: string + * example: "Lewis" + * email: + * type: string + * example: "lewis@gmail.com" + * UserProfile: + * type: object + * properties: + * id: + * type: string + * example: "58b6" + * user_name: + * type: string + * example: "yasuke" + * email: + * type: string + * example: "sam@gmail.com" + * profile_picture: + * type: string + * example: "https://avatar.com" + * bio: + * type: string + * example: "Developer at HNG" + * GetProfileResponse: + * type: object + * properties: + * status_code: + * type: number + * example: 200 + * data: + * $ref: '#/components/schemas/UserProfile' + * GetAllUsersResponse: + * type: object + * properties: + * status: + * type: string + * example: "success" + * status_code: + * type: number + * example: 200 + * message: + * type: string + * example: "Users retrieved successfully" + * pagination: + * type: object + * properties: + * totalItems: + * type: number + * example: 100 + * totalPages: + * type: number + * example: 10 + * currentPage: + * type: number + * example: 1 + * data: + * type: array + * items: + * $ref: '#/components/schemas/User' + * DeleteUserResponse: + * type: object + * properties: + * status: + * type: string + * example: "success" + * status_code: + * type: number + * example: 202 + * message: + * type: string + * example: "User deleted successfully" + */ + +const payload = object({ + id: string(), + user_name: string(), + email: string(), + profile_picture: string(), + bio: string(), +}); + +const paginationSchema = object({ + totalItems: number(), + totalPages: number(), + currentPage: number(), +}); + +const params = { + params: object({ + id: string({ + required_error: "userId is required", + }), + }), +}; + +export const getUserProfileSchema = object({ + response: object({ + status_code: number(), + data: payload, + }), +}); + +export const getAllUsersSchema = object({ + response: object({ + status: string(), + status_code: number(), + message: string(), + pagination: paginationSchema, + data: array(payload), + }), +}); + +export const deleteUserSchema = object({ + ...params, + response: object({ + status: string(), + status_code: number(), + message: string(), + }), +}); + +export type GetUserProfileResponse = TypeOf< + typeof getUserProfileSchema +>["response"]; +export type GetAllUsersResponse = TypeOf["response"]; +export type DeleteUserInput = TypeOf; +export type DeleteUserResponse = TypeOf["response"]; diff --git a/src/services/auth.services.ts b/src/services/auth.services.ts index 809e4cfc..c4745817 100644 --- a/src/services/auth.services.ts +++ b/src/services/auth.services.ts @@ -1,15 +1,16 @@ +import bcrypt from "bcryptjs"; +import jwt from "jsonwebtoken"; +import config from "../config"; import AppDataSource from "../data-source"; -import { Profile, User } from "../models"; -import { IAuthService, IUserSignUp, IUserLogin } from "../types"; import { Conflict, HttpError } from "../middleware"; -import { hashPassword, generateNumericOTP, comparePassword } from "../utils"; +import { Profile, User } from "../models"; +import { PasswordResetToken } from "../models/password-reset-token"; +import { IAuthService, IUserLogin, IUserSignUp } from "../types"; +import { comparePassword, generateNumericOTP, hashPassword } from "../utils"; +import generateResetToken from "../utils/generate-reset-token"; import { Sendmail } from "../utils/mail"; -import jwt from "jsonwebtoken"; import { compilerOtp } from "../views/welcome"; -import config from "../config"; -import generateResetToken from "../utils/generate-reset-token"; -import { PasswordResetToken } from "../models/password-reset-token"; -import bcrypt from "bcryptjs"; + export class AuthService implements IAuthService { public async signUp(payload: IUserSignUp): Promise<{ mailSent: string; diff --git a/src/services/index.ts b/src/services/index.ts index 2da71a0e..1ac21f2d 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -8,4 +8,3 @@ export * from "./export.services"; export * from "./sendEmail.services"; export * from "./organization.services"; export * from "./payment/flutter.service"; - diff --git a/src/services/organization.services.ts b/src/services/organization.services.ts index d60b06e9..a02199e9 100644 --- a/src/services/organization.services.ts +++ b/src/services/organization.services.ts @@ -12,7 +12,7 @@ import { export class OrgService implements IOrgService { public async createOrganisation( payload: ICreateOrganisation, - userId: string + userId: string, ): Promise<{ newOrganisation: Partial; }> { @@ -39,7 +39,7 @@ export class OrgService implements IOrgService { public async removeUser( org_id: string, - user_id: string + user_id: string, ): Promise { const userRepository = AppDataSource.getRepository(User); const organizationRepository = AppDataSource.getRepository(Organization); @@ -62,7 +62,7 @@ export class OrgService implements IOrgService { // Check if the user is part of the organization const userInOrganization = organization.users.some( - (user) => user.id === user_id + (user) => user.id === user_id, ); if (!userInOrganization) { return null; @@ -70,7 +70,7 @@ export class OrgService implements IOrgService { // Remove the user from the organization organization.users = organization.users.filter( - (user) => user.id !== user_id + (user) => user.id !== user_id, ); await organizationRepository.save(organization); diff --git a/src/services/sms.services.ts b/src/services/sms.services.ts index 4c28d41e..cd1bf979 100644 --- a/src/services/sms.services.ts +++ b/src/services/sms.services.ts @@ -6,7 +6,6 @@ import { User } from "../models"; class SmsService { private twilioClient: Twilio.Twilio; - constructor() { this.twilioClient = Twilio(config.TWILIO_SID, config.TWILIO_AUTH_TOKEN); }