diff --git a/src/__test__/cart.test.ts b/src/__test__/cart.test.ts index 40321f1..3307260 100644 --- a/src/__test__/cart.test.ts +++ b/src/__test__/cart.test.ts @@ -1,4 +1,3 @@ - import request from 'supertest'; import jwt from 'jsonwebtoken'; import { app, server } from '../index'; @@ -38,7 +37,8 @@ let returnedCartItem2Id: string; const jwtSecretKey = process.env.JWT_SECRET || ''; -if (!process.env.TEST_USER_EMAIL || !process.env.TEST_USER_PASS) throw new Error('TEST_USER_PASS or TEST_USER_EMAIL not set in .env'); +if (!process.env.TEST_USER_EMAIL || !process.env.TEST_USER_PASS) + throw new Error('TEST_USER_PASS or TEST_USER_EMAIL not set in .env'); const sampleAdmin: UserInterface = { id: sampleAdminId, @@ -53,7 +53,6 @@ const sampleAdmin: UserInterface = { role: 'ADMIN', }; - const getAccessToken = (id: string, email: string) => { return jwt.sign( { @@ -232,7 +231,6 @@ afterAll(async () => { }); describe('Cart| Order management for guest/buyer', () => { - describe('Adding product to cart on guest/buyer', () => { it('should add product to cart as authenticated buyer', async () => { const response = await request(app) @@ -315,13 +313,10 @@ describe('Cart| Order management for guest/buyer', () => { }); it('should return 400 for incorrect Id syntax (IDs not in uuid form), when add product to cart', async () => { - const response = await request(app) - .post(`/cart`) - .set('Cookie', [`cartId=dfgdsf`]) - .send({ - productId: product1Id, - quantity: 3, - }); + const response = await request(app).post(`/cart`).set('Cookie', [`cartId=dfgdsf`]).send({ + productId: product1Id, + quantity: 3, + }); expect(response.status).toBe(400); }); @@ -412,11 +407,8 @@ describe('Cart| Order management for guest/buyer', () => { expect(response.body.data.cart).toBeDefined; }); - it('should return 400 for incorrect Id syntax (IDs not in uuid form), when getting cart', async () => { - const response = await request(app) - .get(`/cart`) - .set('Cookie', [`cartId=dfgdsf`]); + const response = await request(app).get(`/cart`).set('Cookie', [`cartId=dfgdsf`]); expect(response.status).toBe(400); }); @@ -497,7 +489,6 @@ describe('Cart| Order management for guest/buyer', () => { productId = response.body.data.orders[0]?.orderItems[0]?.product?.id; }); - it('should get single order', async () => { const response = await request(app) .get(`/product/client/orders/${orderId}`) @@ -507,7 +498,7 @@ describe('Cart| Order management for guest/buyer', () => { expect(response.body.data.order).toBeDefined(); }); - it('should not return data for single order, if order doesn\'t exist', async () => { + it("should not return data for single order, if order doesn't exist", async () => { const response = await request(app) .get(`/product/client/orders/${uuid()}`) .set('Authorization', `Bearer ${getAccessToken(buyer1Id, sampleBuyer1.email)}`); @@ -541,9 +532,7 @@ describe('Cart| Order management for guest/buyer', () => { }); it('should return 400 when user is not AUTHORIZED', async () => { - const response = await request(app) - .get('/product/orders/history') - .set('Authorization', `Bearer ''`); + const response = await request(app).get('/product/orders/history').set('Authorization', `Bearer ''`); expect(response.status).toBe(403); }); }); @@ -557,7 +546,7 @@ describe('Cart| Order management for guest/buyer', () => { expect(response.status).toBe(200); }); - it('should return 404, if order doesn\'t exist', async () => { + it("should return 404, if order doesn't exist", async () => { const response = await request(app) .put(`/product/client/orders/${uuid()}`) .send({ orderStatus: 'completed' }) @@ -583,18 +572,17 @@ describe('Cart| Order management for guest/buyer', () => { feedbackId = response.body.data.id; }); - it('should create second feedback to the ordered product', async () => { const response = await request(app) .post(`/feedback/${productId}/new`) .send({ orderId, comment: 'Murigalike this product looks so fantastic' }) .set('Authorization', `Bearer ${getAccessToken(buyer1Id, sampleBuyer1.email)}`); expect(response.status).toBe(201); - feedback2Id = response.body.data.id + feedback2Id = response.body.data.id; }); it('should updated existing feedback successfully', async () => { const response = await request(app) - .put(`/feedback/update/${feedbackId}`,) + .put(`/feedback/update/${feedbackId}`) .send({ orderId, comment: 'Well this product looks so lovely' }) .set('Authorization', `Bearer ${getAccessToken(buyer1Id, sampleBuyer1.email)}`); expect(response.status).toBe(200); @@ -609,7 +597,6 @@ describe('Cart| Order management for guest/buyer', () => { }); describe('Feedback API', () => { - describe('Add feedback to the product with order', () => { it('should create new feedback for the ordered product', async () => { const response = await request(app) @@ -725,7 +712,7 @@ describe('Cart| Order management for guest/buyer', () => { expect(response.body.data.message).toBe('Feedback successfully removed'); }); - it('should return 404, if feedback doesn\'t exist', async () => { + it("should return 404, if feedback doesn't exist", async () => { const response = await request(app) .delete(`/feedback/admin/delete/${uuid()}`) .set('Authorization', `Bearer ${getAccessToken(sampleAdminId, sampleAdmin.email)}`); @@ -733,7 +720,7 @@ describe('Cart| Order management for guest/buyer', () => { expect(response.status).toBe(404); }); - it('should return 500, for incorrect feedback id syntax (invalid uuid) doesn\'t exist', async () => { + it("should return 500, for incorrect feedback id syntax (invalid uuid) doesn't exist", async () => { const response = await request(app) .delete(`/feedback/admin/delete/invalid-uuid`) .set('Authorization', `Bearer ${getAccessToken(sampleAdminId, sampleAdmin.email)}`); @@ -742,7 +729,6 @@ describe('Cart| Order management for guest/buyer', () => { }); }); }); - }); describe('Deleting product from cart', () => { @@ -850,7 +836,7 @@ describe('Cart| Order management for guest/buyer', () => { expect(response.body.data.cart).toBeDefined; }); - it('should return empty cart for guest user, if he/she doesn\'t have cart', async () => { + it("should return empty cart for guest user, if he/she doesn't have cart", async () => { const response = await request(app) .delete('/cart') .set('Cookie', [`cartId=${sampleCartId}`]); @@ -861,10 +847,9 @@ describe('Cart| Order management for guest/buyer', () => { }); it('should return 400, for incorrect cart id syntax (invalid uuid) for guest user', async () => { - const response = await request(app).delete(`/cart`) - .set('Cookie', [`cartId=invalid-uuid`]); + const response = await request(app).delete(`/cart`).set('Cookie', [`cartId=invalid-uuid`]); expect(response.status).toBe(400); }); }); -}); \ No newline at end of file +}); diff --git a/src/__test__/transactions.test.ts b/src/__test__/transactions.test.ts new file mode 100644 index 0000000..0b3a1fa --- /dev/null +++ b/src/__test__/transactions.test.ts @@ -0,0 +1,99 @@ +import request from 'supertest'; +import { app, server } from '../index'; // Adjust the path to your Express app +import Stripe from 'stripe'; +import jwt from 'jsonwebtoken'; +import { User, UserInterface } from '../entities/User'; +import { dbConnection } from '../startups/dbConnection'; +import { v4 as uuid } from 'uuid'; +import { cleanDatabase } from './test-assets/DatabaseCleanup'; + +jest.mock('stripe', () => { + const stripeInstance = { + paymentIntents: { + list: jest.fn(), + }, + }; + + return jest.fn(() => stripeInstance); +}); +const jwtSecretKey = process.env.JWT_SECRET || ''; + +const getAccessToken = (id: string, email: string) => { + return jwt.sign( + { + id: id, + email: email, + }, + jwtSecretKey + ); +}; + +afterAll(async () => { + await cleanDatabase(); + server.close(); +}); + +const Admin = uuid(); +const sampleAdmin1: UserInterface = { + id: Admin, + firstName: 'vendor1o', + lastName: 'user', + email: 'vendor10@example.com', + password: 'password', + userType: 'Vendor', + gender: 'Male', + phoneNumber: '126380996348', + photoUrl: 'https://example.com/photo.jpg', + role: 'ADMIN', +}; + +const mockStripeInstance = new Stripe('fake-key', { apiVersion: '2024-04-10' }) as jest.Mocked; + +describe('Transaction function', () => { + beforeEach(async () => { + const connection = await dbConnection(); + (mockStripeInstance.paymentIntents.list as jest.Mock).mockClear(); + const userRepository = connection?.getRepository(User); + await userRepository?.save({ ...sampleAdmin1 }); + }); + + it('should return the correct payment statistics', async () => { + (mockStripeInstance.paymentIntents.list as jest.Mock).mockResolvedValue({ + data: [ + { amount: 1000, amount_received: 1000, status: 'succeeded' }, + { amount: 2000, amount_received: 0, status: 'pending' }, + ], + } as any); + + const response = await request(app) + .get('/product/transaction') + .set('Authorization', `Bearer ${getAccessToken(Admin, sampleAdmin1.email)}`); + + expect(response.body).toEqual({ + payments: [ + { amount: 1000, amount_received: 1000, status: 'succeeded' }, + { amount: 2000, amount_received: 0, status: 'pending' }, + ], + statistics: { + totalPayments: 2, + totalAmount: 3000, + totalCapturedAmount: 1000, + successfulPayments: 1, + pendingPayments: 1, + averagePaymentAmount: 1500, + }, + }); + }); + + it('should handle errors gracefully', async () => { + const error = new Error('Something went wrong'); + (mockStripeInstance.paymentIntents.list as jest.Mock).mockRejectedValueOnce(error); + + const response = await request(app) + .get('/product/transaction') + .set('Authorization', `Bearer ${getAccessToken(Admin, sampleAdmin1.email)}`); + + expect(response.status).toBe(500); + expect(response.body).toEqual({ error: 'Something went wrong' }); + }); +}); diff --git a/src/__test__/userServices.test.ts b/src/__test__/userServices.test.ts index a58dff7..e8fc8a9 100644 --- a/src/__test__/userServices.test.ts +++ b/src/__test__/userServices.test.ts @@ -7,7 +7,7 @@ import { cleanDatabase } from './test-assets/DatabaseCleanup'; import { v4 as uuid } from 'uuid'; import { dbConnection } from '../startups/dbConnection'; -import bcrypt from 'bcrypt' +import bcrypt from 'bcrypt'; import jwt from 'jsonwebtoken'; const userId = uuid(); @@ -132,66 +132,78 @@ describe('User service Test', () => { }); it('should Login a user, with valid credentials', async () => { - const res = await request(app) - .post('/user/login') - .send({ - email: 'user@example.com', - password: 'password', - }); + const res = await request(app).post('/user/login').send({ + email: 'user@example.com', + password: 'password', + }); // Assert expect(res.status).toBe(200); expect(res.body.data.token).toBeDefined(); }); it('should send OTP, if 2FA is enabled', async () => { - const res = await request(app) - .post('/user/login') - .send({ - email: 'user2@example.com', - password: 'password', - }); + const res = await request(app).post('/user/login').send({ + email: 'user2@example.com', + password: 'password', + }); // Assert expect(res.status).toBe(200); expect(res.body.data.message).toBe('Please provide the OTP sent to your email or phone'); }); it('should not Login a user, with invalid credentials', async () => { - const res = await request(app) - .post('/user/login') - .send({ - email: 'user@example.com', - password: 'passwo', - }); + const res = await request(app).post('/user/login').send({ + email: 'user@example.com', + password: 'passwo', + }); // Assert expect(res.status).toBe(401); }); it('should not login User if user email is not verified', async () => { - const res = await request(app) - .post('/user/login') - .send({ - email: 'john.doe1@example.com', - password: 'password', - }); + const res = await request(app).post('/user/login').send({ + email: 'john.doe1@example.com', + password: 'password', + }); expect(res.status).toBe(400); - expect(res.body.message).toBe("Please verify your account"); + expect(res.body.message).toBe('Please verify your account'); }); it('should not login User if user is currently suspended', async () => { - const res = await request(app) - .post('/user/login') - .send({ - email: sampleUser1.email, - password: sampleUser1.password, - }); + const res = await request(app).post('/user/login').send({ + email: sampleUser1.email, + password: sampleUser1.password, + }); expect(res.status).toBe(400); - expect(res.body.message).toBe("Your account has been suspended"); + expect(res.body.message).toBe('Your account has been suspended'); }); }); describe('User Profile update', () => { + it('should get user information', async () => { + const res = await request(app) + .get('/user/profile') + .set('Authorization', `Bearer ${getAccessToken(userId, sampleUser.email)}`); + + expect(res.status).toBe(200); + expect(res.body.status).toBe('success'); + expect(res.body.data.code).toBe(200); + expect(res.body.data.message).toBe('profile fetched successfully'); + }); + + it('should get user information', async () => { + const res = await request(app) + .put('/user/profile') + .send({ images: [] }) + .set('Authorization', `Bearer ${getAccessToken(userId, sampleUser.email)}`); + + expect(res.status).toBe(400); + expect(res.body.status).toBe('error'); + expect(res.body.message).toBe("Cannot read properties of undefined (reading 'length')"); + }); + it('should update user profile', async () => { const res = await request(app) .put('/user/update') @@ -200,7 +212,6 @@ describe('User service Test', () => { lastName: 'Doe', gender: 'Male', phoneNumber: '0789412421', - photoUrl: 'photo.jpg', }) .set('Authorization', `Bearer ${getAccessToken(userId, sampleUser.email)}`); @@ -220,7 +231,7 @@ describe('User service Test', () => { .put('/user/update') .send({ firstName: 'firstName updated', - lastName: 'lastName updated' + lastName: 'lastName updated', }) .set('Authorization', `Bearer ${getAccessToken(userId, sampleUser.email)}`); @@ -230,45 +241,40 @@ describe('User service Test', () => { describe('User Reset Password', () => { it('should return response error, if no email and userID provided', async () => { - const respond = await request(app) - .post('/user/password/reset'); + const respond = await request(app).post('/user/password/reset'); expect(respond.status).toBe(400); }); it('should not reset password, for no existing Users', async () => { - const respond = await request(app) - .post('/user/password/reset') - .query({ - email: 'example@gmail.com', - userid: uuid() - }); + const respond = await request(app).post('/user/password/reset').query({ + email: 'example@gmail.com', + userid: uuid(), + }); expect(respond.status).toBe(404); }); it('should not reset password, if no new password sent', async () => { - const respond = await request(app) - .post('/user/password/reset') - .query({ - email: sampleUser.email, - userid: sampleUser.id - }); + const respond = await request(app).post('/user/password/reset').query({ + email: sampleUser.email, + userid: sampleUser.id, + }); expect(respond.status).toBe(400); expect(respond.body.message).toBe('Please provide all required fields'); }); - it('should not reset password, if new password doesn\'t match password in confirmPassword field', async () => { + it("should not reset password, if new password doesn't match password in confirmPassword field", async () => { const respond = await request(app) .post('/user/password/reset') .query({ email: sampleUser.email, - userid: sampleUser.id + userid: sampleUser.id, }) .send({ newPassword: 'new-password', - confirmPassword: 'password' + confirmPassword: 'password', }); expect(respond.status).toBe(400); @@ -276,12 +282,10 @@ describe('User service Test', () => { }); it('should not reset password, for incorrect user id syntax (invalid uuid)', async () => { - const respond = await request(app) - .post('/user/password/reset') - .query({ - email: sampleUser.email, - userid: 'invalid-=uuid' - }); + const respond = await request(app).post('/user/password/reset').query({ + email: sampleUser.email, + userid: 'invalid-=uuid', + }); expect(respond.status).toBe(500); }); @@ -290,11 +294,11 @@ describe('User service Test', () => { .post('/user/password/reset') .query({ email: sampleUser.email, - userid: sampleUser.id + userid: sampleUser.id, }) .send({ newPassword: 'new-password', - confirmPassword: 'new-password' + confirmPassword: 'new-password', }); expect(respond.status).toBe(200); @@ -304,22 +308,19 @@ describe('User service Test', () => { describe('User password reset link', () => { it('should send link to reset password', async () => { - const response = await request(app) - .post('/user/password/reset/link') - .query({ email: sampleUser.email }); + const response = await request(app).post('/user/password/reset/link').query({ email: sampleUser.email }); expect(response.status).toBe(200); }); it('should not send link to reset password, if no email provided', async () => { - const response = await request(app) - .post('/user/password/reset/link'); + const response = await request(app).post('/user/password/reset/link'); expect(response.status).toBe(400); expect(response.body.message).toBe('Missing required field'); }); - it('should not send link to reset password, if email doesn\'t exist in DB', async () => { + it("should not send link to reset password, if email doesn't exist in DB", async () => { const response = await request(app) .post('/user/password/reset/link') .query({ email: 'nonexistingemail@gmail.com' }); @@ -330,7 +331,6 @@ describe('User service Test', () => { }); describe('Start@FAProcess', () => { - it('should return 400 if not sent email in body on enabling 2fa', async () => { const data = {}; @@ -359,7 +359,10 @@ describe('User service Test', () => { const res = await request(app).post('/user/enable-2fa').send(data); expect(res.status).toBe(200); - expect(res.body).toEqual({ status: 'success', message: 'Two factor authentication enabled successfully' }); + expect(res.body.status).toBe('success'); + expect(res.body.data.code).toBe(200); + expect(res.body.data.message).toBe('Two factor authentication enabled successfully'); + expect(res.body.data.profile.twoFactorEnabled).toBe(true); }); it('should return 400 if not sent email in body on disabling 2fa', async () => { @@ -390,7 +393,10 @@ describe('User service Test', () => { const res = await request(app).post('/user/disable-2fa').send(data); expect(res.status).toBe(200); - expect(res.body).toEqual({ status: 'success', message: 'Two factor authentication disabled successfully' }); + expect(res.body.status).toBe('success'); + expect(res.body.data.code).toBe(200); + expect(res.body.data.message).toBe('Two factor authentication disabled successfully'); + expect(res.body.data.profile.twoFactorEnabled).toBe(false); }); it('should return 400 if not sent email and otp in body on verifying OTP', async () => { @@ -454,12 +460,10 @@ describe('User service Test', () => { }); it('should login user, if OTP provided is valid', async () => { - const res = await request(app) - .post('/user/verify-otp') - .send({ - email: sampleUser3.email, - otp: '123456', - }); + const res = await request(app).post('/user/verify-otp').send({ + email: sampleUser3.email, + otp: '123456', + }); expect(res.status).toBe(200); expect(res.body.data.token).toBeDefined(); diff --git a/src/controllers/authController.ts b/src/controllers/authController.ts index 35c3d5a..eefdf0d 100644 --- a/src/controllers/authController.ts +++ b/src/controllers/authController.ts @@ -16,6 +16,8 @@ import { deactivateUserService } from '../services/updateUserStatus/deactivateUs import { userProfileUpdateServices } from '../services/userServices/userProfileUpdateServices'; import getAllUsers from '../services/userServices/getAllUsers'; import getUserById from '../services/userServices/getUserById'; +import getUserProfile from '../services/userServices/getUserProfile'; +import userUpdateProfilePicture from '../services/userServices/userUpdateProfileImage'; export const userRegistration = async (req: Request, res: Response) => { await userRegistrationService(req, res); @@ -76,4 +78,12 @@ export const getAllUsersController = async (req: Request, res: Response) => { export const getUserByIdController = async (req: Request, res: Response) => { await getUserById(req, res); -}; \ No newline at end of file +}; + +export const getUserProfileController = async (req: Request, res: Response) => { + await getUserProfile(req, res); +}; + +export const userUpdateProfilePictureController = async (req: Request, res: Response) => { + await userUpdateProfilePicture(req, res); +}; diff --git a/src/controllers/productController.ts b/src/controllers/productController.ts index 662a8a0..a5a18e3 100644 --- a/src/controllers/productController.ts +++ b/src/controllers/productController.ts @@ -10,9 +10,10 @@ import { productStatusServices, viewSingleProduct, searchProductService, - listAllProductsService, + listAllProductsService, confirmPayment, - getAllCategories + getAllCategories, + transaction, } from '../services'; export const readProduct = async (req: Request, res: Response) => { @@ -53,12 +54,14 @@ export const singleProduct = async (req: Request, res: Response) => { await viewSingleProduct(req, res); }; export const searchProduct = async (req: Request, res: Response) => { - await searchProductService (req, res); - + await searchProductService(req, res); }; export const Payment = async (req: Request, res: Response) => { await confirmPayment(req, res); }; export const getAllCategory = async (req: Request, res: Response) => { await getAllCategories(req, res); -}; \ No newline at end of file +}; +export const getAllTransaction = async (req: Request, res: Response) => { + await transaction(req, res); +}; diff --git a/src/routes/ProductRoutes.ts b/src/routes/ProductRoutes.ts index 902a1da..fa0ba4e 100644 --- a/src/routes/ProductRoutes.ts +++ b/src/routes/ProductRoutes.ts @@ -1,6 +1,6 @@ import { RequestHandler, Router } from 'express'; -import { productStatus, searchProduct, } from '../controllers/index'; +import { productStatus, searchProduct } from '../controllers/index'; import { hasRole } from '../middlewares/roleCheck'; import upload from '../middlewares/multer'; import { authMiddleware } from '../middlewares/verifyToken'; @@ -16,19 +16,23 @@ import { listAllProducts, singleProduct, createOrder, - getOrders, getOrder, + getOrders, + getOrder, updateOrder, - getOrdersHistory, Payment, + getOrdersHistory, + Payment, getSingleVendorOrder, getVendorOrders, updateVendorOrder, getBuyerVendorOrders, getSingleBuyerVendorOrder, updateBuyerVendorOrder, - getAllCategory + getAllCategory, + getAllTransaction, } from '../controllers'; const router = Router(); +router.get('/transaction', authMiddleware as RequestHandler, hasRole('ADMIN'), getAllTransaction); router.get('/search', searchProduct); router.get('/all', listAllProducts); router.get('/recommended', authMiddleware as RequestHandler, hasRole('BUYER'), getRecommendedProducts); @@ -55,10 +59,12 @@ router.get('/vendor/orders/:id', authMiddleware as RequestHandler, hasRole('VEND router.put('/vendor/orders/:id', authMiddleware as RequestHandler, hasRole('VENDOR'), updateVendorOrder); // Admin order management + router.get('/admin/orders', authMiddleware as RequestHandler, hasRole('ADMIN'), getBuyerVendorOrders); router.get('/admin/orders/:id', authMiddleware as RequestHandler, hasRole('ADMIN'), getSingleBuyerVendorOrder); router.put('/admin/orders/:id', authMiddleware as RequestHandler, hasRole('ADMIN'), updateBuyerVendorOrder); router.post('/payment/:id', authMiddleware as RequestHandler, hasRole('BUYER'), Payment); +//all transaction export default router; diff --git a/src/routes/UserRoutes.ts b/src/routes/UserRoutes.ts index 2a446ff..6a0cdd9 100644 --- a/src/routes/UserRoutes.ts +++ b/src/routes/UserRoutes.ts @@ -15,10 +15,13 @@ import { logout, getAllUsersController, getUserByIdController, + getUserProfileController, + userUpdateProfilePictureController, } from '../controllers'; import { activateUser, disactivateUser, userProfileUpdate } from '../controllers/index'; import { hasRole } from '../middlewares/roleCheck'; +import upload from '../middlewares/multer'; import passport from 'passport'; import '../utils/auth'; import { start2FAProcess } from '../services/userServices/userStartTwoFactorAuthProcess'; @@ -43,6 +46,8 @@ router.post('/deactivate', authMiddleware as RequestHandler, hasRole('ADMIN'), d router.post('/password/reset', userPasswordReset); router.post('/password/reset/link', sendPasswordResetLink); router.put('/update', authMiddleware as RequestHandler, userProfileUpdate); +router.get('/profile', authMiddleware as RequestHandler, getUserProfileController); +router.put('/profile', authMiddleware as RequestHandler, upload.array('images', 1), userUpdateProfilePictureController); router.get('/google-auth', passport.authenticate('google', { scope: ['profile', 'email'] })); router.get( diff --git a/src/services/index.ts b/src/services/index.ts index 80d463b..bd8a4ac 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -22,6 +22,7 @@ export * from './productServices/productStatus'; export * from './productServices/viewSingleProduct'; export * from './productServices/searchProduct'; export * from './productServices/payment'; +export * from './productServices/Transctions'; export * from './productServices/getCategories'; // Buyer wishlist services @@ -49,5 +50,5 @@ export * from './notificationServices/getNotifications'; export * from './notificationServices/deleteNotification'; export * from './notificationServices/updateNotification'; -// chatbot -export * from './chatbotServices/chatBot'; \ No newline at end of file +// chatbot +export * from './chatbotServices/chatBot'; diff --git a/src/services/productServices/Transctions.ts b/src/services/productServices/Transctions.ts new file mode 100644 index 0000000..00cc179 --- /dev/null +++ b/src/services/productServices/Transctions.ts @@ -0,0 +1,39 @@ +import { Request, Response } from 'express'; +import Stripe from 'stripe'; + +const stripe = new Stripe(process.env.STRIPE_SECRET_KEY as string, { + apiVersion: '2024-04-10', +}); + +export const transaction = async (req: Request, res: Response) => { + try { + const payments = await stripe.paymentIntents.list(); + const paymentData = payments.data; + + // Calculate statistics + const totalPayments = paymentData.length; + const totalAmount = paymentData.reduce((sum, payment) => sum + payment.amount, 0); + const totalCapturedAmount = paymentData.reduce((sum, payment) => sum + payment.amount_received, 0); + const successfulPayments = paymentData.filter(payment => payment.status === 'succeeded').length; + const pendingPayments = paymentData.filter(payment => payment.status !== 'succeeded').length; + const averagePaymentAmount = totalPayments > 0 ? totalAmount / totalPayments : 0; + + // Prepare the response data + const responseData = { + payments: paymentData, + statistics: { + totalPayments, + totalAmount, + totalCapturedAmount, + successfulPayments, + pendingPayments, + averagePaymentAmount, + }, + }; + + res.json(responseData); + } catch (error) { + console.log(error); + res.status(500).json({ error: 'Something went wrong' }); + } +}; diff --git a/src/services/productServices/payment.ts b/src/services/productServices/payment.ts index d8a66f1..c8e3b73 100644 --- a/src/services/productServices/payment.ts +++ b/src/services/productServices/payment.ts @@ -60,18 +60,3 @@ export const confirmPayment = async (req: Request, res: Response) => { res.status(500).json({ error: 'Something went wrong' }); } }; - -// export const confirmPayment = async (req: Request, res: Response) => { -// try { -// const paymentIntent = await stripeInstance.paymentIntents.create({ -// currency: 'eur', -// amount: 2000, -// automatic_payment_methods: { -// enabled: true, -// }, -// }); -// res.send({ clientSecret: paymentIntent.client_secret }); -// } catch (error) { -// res.status(500).json({ error: 'Something went wrong' }); -// } -// }; diff --git a/src/services/userServices/getUserProfile.ts b/src/services/userServices/getUserProfile.ts new file mode 100644 index 0000000..d1b1db1 --- /dev/null +++ b/src/services/userServices/getUserProfile.ts @@ -0,0 +1,18 @@ +import { Request, Response } from 'express'; +import { responseError, responseSuccess } from '../../utils/response.utils'; +import { UserInterface } from '../../entities/User'; + +const getUserProfile = async (req: Request, res: Response) => { + try { + const user = req.user; + // eslint-disable-next-line no-unused-vars + const { password, twoFactorCode, twoFactorCodeExpiresAt, ...safeUser } = user as UserInterface; + responseSuccess(res, 200, 'profile fetched successfully', { profile: safeUser }); + return; + } catch (error) { + responseError(res, 400, (error as Error).message); + return; + } +}; + +export default getUserProfile; diff --git a/src/services/userServices/userDisableTwoFactorAuth.ts b/src/services/userServices/userDisableTwoFactorAuth.ts index b4fc6e9..9644cde 100644 --- a/src/services/userServices/userDisableTwoFactorAuth.ts +++ b/src/services/userServices/userDisableTwoFactorAuth.ts @@ -1,7 +1,8 @@ import { Request, Response } from 'express'; -import { User } from '../../entities/User'; +import { User, UserInterface } from '../../entities/User'; import { getRepository } from 'typeorm'; import { sendNotification } from '../../utils/sendNotification'; +import { responseError, responseSuccess } from '../../utils/response.utils'; export const userDisableTwoFactorAuth = async (req: Request, res: Response) => { try { @@ -22,14 +23,23 @@ export const userDisableTwoFactorAuth = async (req: Request, res: Response) => { await userRepository.save(user); await sendNotification({ - content: "You disabled Two factor authentication on you account", + content: 'You disabled Two factor authentication on you account', type: 'user', - user: user - }) - return res.status(200).json({ status: 'success', message: 'Two factor authentication disabled successfully' }); + user: user, + }); + + const newUser = await userRepository.findOne({ + where: { + email: email, + }, + }); + + // eslint-disable-next-line no-unused-vars + const { password, twoFactorCode, twoFactorCodeExpiresAt, ...safeUser } = newUser as UserInterface; + return responseSuccess(res, 200, 'Two factor authentication disabled successfully', { + profile: safeUser, + }); } catch (error) { - if (error instanceof Error) { - return res.status(500).json({ status: 'error', message: error.message }); - } + responseError(res, 400, (error as Error).message); } }; diff --git a/src/services/userServices/userEnableTwoFactorAuth.ts b/src/services/userServices/userEnableTwoFactorAuth.ts index c5d3cbf..907848e 100644 --- a/src/services/userServices/userEnableTwoFactorAuth.ts +++ b/src/services/userServices/userEnableTwoFactorAuth.ts @@ -1,7 +1,8 @@ import { Request, Response } from 'express'; -import { User } from '../../entities/User'; +import { User, UserInterface } from '../../entities/User'; import { getRepository } from 'typeorm'; import { sendNotification } from '../../utils/sendNotification'; +import { responseError, responseSuccess } from '../../utils/response.utils'; export const userEnableTwoFactorAuth = async (req: Request, res: Response) => { try { @@ -22,14 +23,22 @@ export const userEnableTwoFactorAuth = async (req: Request, res: Response) => { await userRepository.save(user); await sendNotification({ - content: "You enabled Two factor authentication on you account", + content: 'You enabled Two factor authentication on you account', type: 'user', - user: user - }) - return res.status(200).json({ status: 'success', message: 'Two factor authentication enabled successfully' }); + user: user, + }); + + const newUser = await userRepository.findOne({ + where: { + email: email, + }, + }); + // eslint-disable-next-line no-unused-vars + const { password, twoFactorCode, twoFactorCodeExpiresAt, ...safeUser } = newUser as UserInterface; + return responseSuccess(res, 200, 'Two factor authentication enabled successfully', { + profile: safeUser, + }); } catch (error) { - if (error instanceof Error) { - return res.status(500).json({ status: 'error', message: error.message }); - } + responseError(res, 400, (error as Error).message); } }; diff --git a/src/services/userServices/userProfileUpdateServices.ts b/src/services/userServices/userProfileUpdateServices.ts index f65fc81..7b0e173 100644 --- a/src/services/userServices/userProfileUpdateServices.ts +++ b/src/services/userServices/userProfileUpdateServices.ts @@ -5,25 +5,21 @@ import { getRepository } from 'typeorm'; export const userProfileUpdateServices = async (req: Request, res: Response) => { try { - if (Object.keys(req.body).length === 0) { return responseError(res, 400, 'body required'); } - const { firstName, lastName, gender, phoneNumber, photoUrl} = req.body; + const { firstName, lastName, gender, phoneNumber } = req.body; // Validate user input - if ( - !firstName || !lastName || !gender || - !phoneNumber || !photoUrl - ) { + if (!firstName || !lastName || !gender || !phoneNumber) { return responseError(res, 400, 'Fill all the field'); } const userRepository = getRepository(User); const existingUser = await userRepository.findOne({ where: { - id: req.user?.id + id: req.user?.id, }, }); @@ -35,10 +31,19 @@ export const userProfileUpdateServices = async (req: Request, res: Response) => existingUser.lastName = lastName; existingUser.gender = gender; existingUser.phoneNumber = phoneNumber; - existingUser.photoUrl = photoUrl; - await userRepository.save(existingUser); - return responseSuccess(res, 200, 'User Profile has successfully been updated'); + + const newUser = await userRepository.findOne({ + where: { + id: req.user?.id, + }, + }); + + // eslint-disable-next-line no-unused-vars + const { password, twoFactorCode, twoFactorCodeExpiresAt, ...safeUser } = newUser as UserInterface; + return responseSuccess(res, 200, 'User Profile has successfully been updated', { + profile: safeUser, + }); } catch (error) { responseError(res, 400, (error as Error).message); } diff --git a/src/services/userServices/userUpdateProfileImage.ts b/src/services/userServices/userUpdateProfileImage.ts new file mode 100644 index 0000000..3a2279c --- /dev/null +++ b/src/services/userServices/userUpdateProfileImage.ts @@ -0,0 +1,58 @@ +import { Request, Response } from 'express'; +import { responseError, responseSuccess } from '../../utils/response.utils'; +import { User, UserInterface } from '../../entities/User'; +import { getRepository } from 'typeorm'; +import cloudinary from '../../utils/cloudinary'; + +declare module 'express' { + interface Request { + files?: any; + } +} + +const userUpdateProfilePicture = async (req: Request, res: Response) => { + try { + const user = req.user; + + const userRepository = getRepository(User); + const userToUpdate = await userRepository.findOne({ + where: { + email: user?.email, + }, + }); + + if (!userToUpdate) { + return responseError(res, 404, 'User not found'); + } + + const files: any = req.files; + + if (files.length < 1) { + return responseError(res, 400, 'Please upload an image'); + } + + for (const file of files) { + const image = file.path; + const link = await cloudinary.uploader.upload(image); + userToUpdate.photoUrl = link.secure_url; + } + + await userRepository.save(userToUpdate); + + const newUser = await userRepository.findOne({ + where: { + email: user?.email, + }, + }); + + // eslint-disable-next-line no-unused-vars + const { password, twoFactorCode, twoFactorCodeExpiresAt, ...safeUser } = newUser as UserInterface; + responseSuccess(res, 200, 'profile picture updated successfully', { profile: safeUser }); + return; + } catch (error) { + responseError(res, 400, (error as Error).message); + return; + } +}; + +export default userUpdateProfilePicture;