Skip to content

Commit

Permalink
resolved merge conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
Ibrahim4Grace committed Jul 22, 2024
2 parents ad67ab2 + ee30a9b commit cd25e07
Show file tree
Hide file tree
Showing 26 changed files with 555 additions and 233 deletions.
10 changes: 8 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
port=8000
PORT=8000
AUTH_SECRET=
DB_USER=
DB_HOST=
DB_PASSWORD=
DB_NAME=
DB_NAME=
NODE_ENV=development
SMTP_USER=
SMTP_PASSWORD=
SMTP_HOST=
SMTP_SERVICE=

11 changes: 11 additions & 0 deletions db/migrations/1721611425287-migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { MigrationInterface, QueryRunner } from "typeorm";

export class Migration1721611425287 implements MigrationInterface {

public async up(queryRunner: QueryRunner): Promise<void> {
}

public async down(queryRunner: QueryRunner): Promise<void> {
}

}
11 changes: 7 additions & 4 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ const config: Config = {
verbose: true,
preset: "ts-jest",
testEnvironment: "node",
globals: {
"ts-jest": {
tsconfig: "tsconfig.jest.json",
},
transform: {
"^.+\\.tsx?$": [
"ts-jest",
{
tsconfig: "tsconfig.jest.json",
},
],
},
};

Expand Down
17 changes: 14 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,29 @@
"test": "jest ",
"typeorm": "typeorm-ts-node-commonjs",
"build": "tsc",
"prod": "node dist/index.js"
"prod": "node dist/index.js",
"migrate": "typeorm-ts-node-commonjs migration:run -d src/data-source",
"migration:create": "typeorm-ts-node-commonjs migration:create db/migrations/migration",
"migration:generate": "typeorm-ts-node-commonjs migration:generate db/migrations/migration -d src/data-source",
"migration:revert": "typeorm-ts-node-commonjs migration:revert -d src/data-source"
},
"repository": {
"type": "git",
"url": "https://github.com/hngprojects/hng_boilerplate_expressjs"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/hngprojects/hng_boilerplate_expressjs/issues"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/jest": "^29.5.12",
"@types/node": "^16.18.103",
"@types/supertest": "^6.0.2",
"@types/swagger-jsdoc": "^6.0.4",
"@types/swagger-ui-express": "^4.1.6",
"ts-node": "^10.9.1",
"ts-node": "^10.9.2",
"typescript": "^5.5.3"
},
"dependencies": {
Expand Down Expand Up @@ -51,6 +61,7 @@
"swagger-ui-express": "^5.0.1",
"ts-jest": "^29.2.3",
"ts-node-dev": "^2.0.0",
"twilio": "^5.2.2",
"typeorm": "^0.3.20"
}
}
5 changes: 5 additions & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ const config = {
SMTP_PASSWORD: process.env.SMTP_PASSWORD,
SMTP_HOST: process.env.SMTP_HOST,
SMTP_SERVICE: process.env.SMTP_SERVICE,
NODE_ENV: process.env.NODE_ENV,
TWILIO_SID: process.env.TWILIO_SID,
TWILIO_AUTH_TOKEN: process.env.TWILIO_AUTH_TOKEN,
TWILIO_PHONE_NUMBER: process.env.TWILIO_PHONE_NUMBER,

};

export default config;
64 changes: 64 additions & 0 deletions src/controllers/HelpController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// src/controllers/UserController.ts
import { Request, Response } from "express";
import { HelpService } from "../services";
import { HttpError } from "../middleware";

class HelpController {
private helpService: HelpService;

constructor() {
this.helpService = new HelpService();
}

async createTopic(req: Request, res:Response):Promise<void> {
try {
const topic = await this.helpService.create(req);
res.status(201).json({
success: true,
message: 'Topic Created Successfully',
data: {
article_id: topic.id,
content: topic.content,
author: topic.author,
title: topic.title,
createdAt: topic.createdAt,
updatedAt: topic.updatedAt
},
status_code: 201
});
} catch (error) {
if (error instanceof HttpError) {
res.status(error.status).json({message: error.message});
} else {
res.status(500).json({ message: error.message || "Internal Server Error" });
}
}
}

async updateTopic(req: Request, res:Response):Promise<void> {
try {
const topic = await this.helpService.update(req);
res.status(200).json({
success: true,
message: 'Topic Updated Successfully',
data: {
article_id: topic.id,
content: topic.content,
author: topic.author,
title: topic.title,
createdAt: topic.createdAt,
updatedAt: topic.updatedAt
},
status_code: 200
});
} catch (error) {
if (error instanceof HttpError) {
res.status(error.status).json({message: error.message});
} else {
res.status(500).json({ message: error.message || "Internal Server Error" });
}
}
}
}

export default HelpController;
46 changes: 46 additions & 0 deletions src/controllers/SmsController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Request, Response } from "express";
import SmsService from "../services/sms.services";
import AppDataSource from "../data-source";
import { User } from "../models";

export const sendSms = async (req: Request, res: Response): Promise<void> => {
const { phone_number, message } = req.body;
const sender_id = req.user.id;

if (!phone_number || !message || !sender_id) {
res.status(400).json({
status: "unsuccessful",
status_code: 400,
message:
"Valid phone number, message content, and sender ID must be provided.",
});
return;
}

try {
const userRepository = AppDataSource.getRepository(User);
const sender = await userRepository.findOneBy({ id: sender_id });

if (!sender) {
res.status(404).json({
status: "unsuccessful",
status_code: 404,
message: "Sender not found.",
});
return;
}

await SmsService.sendSms(sender, phone_number, message);
res.status(200).json({
status: "success",
status_code: 200,
message: "SMS sent successfully.",
});
} catch (error) {
res.status(500).json({
status: "unsuccessful",
status_code: 500,
message: "Failed to send SMS. Please try again later.",
});
}
};
41 changes: 40 additions & 1 deletion src/controllers/TestimonialsController.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Request, Response } from "express";
import { AppDataSource } from "../data-source";
import AppDataSource from "../data-source";
import { Testimonial } from "../models/Testimonial";

export default class TestimonialsController {
Expand Down Expand Up @@ -133,4 +133,43 @@ export default class TestimonialsController {
res.status(500).send({ message: error.message });
}
}

// CODE BY TOMILLA OLUWAFEMI
public async getAllTestimonials(req: Request, res: Response) {
try {
const testimonials = await AppDataSource.getRepository(Testimonial).find();
res.status(200).json({
message: "Testimonials retrieved successfully",
status_code: 200,
data: testimonials,
});
} catch (error) {
res.status(500).send({ message: error.message });
}
}

public async deleteTestimonial(req: Request, res: Response) {
try {
const { testimonial_id } = req.params;

const testimonialToDelete = await AppDataSource.getRepository(Testimonial).findOne({
where: { id: testimonial_id },
});

if (!testimonialToDelete) {
return res
.status(404)
.send({ message: "Testimonial not found", status_code: 404 });
}

await AppDataSource.getRepository(Testimonial).remove(testimonialToDelete);

res.status(200).json({
message: "Testimonial deleted successfully",
status_code: 200,
});
} catch (error) {
res.status(500).send({ message: error.message });
}
}
}
1 change: 0 additions & 1 deletion src/controllers/productController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export class ProductController {
products: products.map((product) => ({
name: product.name,
description: product.description,
price: product.price,
category: product.category,
})),
pagination: {
Expand Down
18 changes: 11 additions & 7 deletions src/data-source.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'reflect-metadata';
import { DataSource, Tree } from 'typeorm';
import config from './config';
const isDevelopment = config.NODE_ENV === 'development';

export const AppDataSource = new DataSource({
type: 'postgres',
Expand All @@ -9,13 +10,16 @@ export const AppDataSource = new DataSource({
username: config.DB_USER,
password: config.DB_PASSWORD,
database: config.DB_NAME,
synchronize: true,
synchronize: isDevelopment,
logging: false,
entities: ['src/models/**/*.ts'],
// ssl: false,
// extra: {
// ssl: {
// rejectUnauthorized: false,
// },
// },
});

export async function initializeDataSource() {
if (!AppDataSource.isInitialized) {
await AppDataSource.initialize();
}
return AppDataSource;
}

export default AppDataSource;
46 changes: 30 additions & 16 deletions src/middleware/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import {
ServerError,
Unauthorized,
} from "./error";
import log from "../utils/logger";
import jwt from "jsonwebtoken";
import config from "../config";

export const authMiddleware = async (
req: Request,
Expand All @@ -17,30 +20,41 @@ export const authMiddleware = async (
const authHeader = req.headers.authorization;

if (!authHeader || !authHeader.startsWith("Bearer ")) {
throw new HttpError(400, "Bad Request");
return res.status(401).json({
status_code: "401",
message: "Invalid token",
});
}

const token = authHeader.split(" ")[1];
if (!token) {
throw new Unauthorized("Invalid token");
return res.status(401).json({
status_code: "401",
message: "Invalid token",
});
}

const payload = verifyToken(token);

if (!payload) {
throw new Unauthorized("Unauthroized");
}

const user = await User.findOne({
where: { email: payload["email"] as string },
jwt.verify(token, config.TOKEN_SECRET, async (err, decoded: any) => {
if (err) {
return res.status(401).json({
status_code: "401",
message: "Invalid token",
});
}
const user = await User.findOne({
where: { email: decoded["email"] as string },
});
if (!user) {
return res.status(401).json({
status_code: "401",
message: "Invalid token",
});
}
req.user = user;
next();
});

if (!user) {
throw new ResourceNotFound("User not found");
}
req.user = user;
next();
} catch (error) {
log.error(error);
throw new ServerError("INTERNAL_SERVER_ERROR");
}
};
3 changes: 0 additions & 3 deletions src/models/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ export class Product extends ExtendedBaseEntity {
@Column()
description: string;

@Column()
price: number;

@Column()
category: string;

Expand Down
3 changes: 0 additions & 3 deletions src/models/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,6 @@ export class User extends ExtendedBaseEntity {
@JoinTable()
organizations: Organization[];

@OneToMany(() => Sms, (sms) => sms.sender, { cascade: true })
sms: Sms[];

@CreateDateColumn()
createdAt: Date;

Expand Down
Loading

0 comments on commit cd25e07

Please sign in to comment.