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);
}