diff --git a/README.md b/README.md index 5be8993..672b992 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ # Taskora 🚀 ![NodeJS](https://img.shields.io/badge/Node.js-6DA55F?logo=node.js&logoColor=white) ![Express.js](https://img.shields.io/badge/Express.js-%23404d59.svg?logo=express&logoColor=%2361DAFB) ![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=fff) ![Docker](https://img.shields.io/badge/Docker-2496ED?logo=docker&logoColor=fff) ![MySQL](https://img.shields.io/badge/MySQL-4479A1?logo=mysql&logoColor=fff) ![Prisma](https://img.shields.io/badge/Prisma-2D3748?logo=prisma&logoColor=white) ![Redis](https://img.shields.io/badge/Redis-%23DD0031.svg?logo=redis&logoColor=white) ![Nginx](https://img.shields.io/badge/Nginx-009639.svg?logo=nginx&logoColor=white) -![Postman](https://img.shields.io/badge/Postman-FF6C37?logo=postman&logoColor=white) ![Microsoft Azure](https://custom-icon-badges.demolab.com/badge/Microsoft%20Azure-0089D6?logo=msazure&logoColor=white) +![Postman](https://img.shields.io/badge/Postman-FF6C37?logo=postman&logoColor=white) ![Swagger](https://img.shields.io/badge/Swagger-?logo=swagger&logoColor=white) ![Microsoft Azure](https://custom-icon-badges.demolab.com/badge/Microsoft%20Azure-0089D6?logo=msazure&logoColor=white) Taskora API built using **Node.js**, **Express.js**, **TypeScript**, **Prisma ORM**, and **Redis**. It allows users to **create**, **read**, **update**, and **delete** projects & tasks while following RESTful API design principles. -🌐 **[Frontend Repository](https://github.com/amatter23/Taskora)** | 🚀 **[Live Demo](https://Taskora.live)** +🌐 **[Frontend Repository](https://github.com/amatter23/Taskora)** | 🚀 **[Live Preview](https://Taskora.live)** --- -**[⚠️ Alert]** Taskora now has `+200` active users! 🎉 +**[⚠️ Alert]** Taskora now has `+250` active users! 🎉 --- -**[⚠️ Alert]** I have created a [Node.js script](https://github.com/MuhammedMagdyy/taskora-user-tracker) to monitor new user registrations passionately and celebrate every new member of the Taskora community. +**[⚠️ Alert]** I have created a [Node.js script](https://github.com/MuhammedMagdyy/taskora-user-tracker) to monitor new user registrations passionately and celebrate every new member of the Taskora community by sending me an email notification. --- diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts index 7bb1c66..daab830 100644 --- a/src/interfaces/index.ts +++ b/src/interfaces/index.ts @@ -2,6 +2,5 @@ export * from './auth.interface'; export * from './database.interface'; export * from './email.interface'; export * from './jwt.interface'; -export * from './query.interface'; export * from './strategy.interface'; export * from './user.interface'; diff --git a/src/interfaces/query.interface.ts b/src/interfaces/query.interface.ts deleted file mode 100644 index 5804017..0000000 --- a/src/interfaces/query.interface.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface IPagination { - skip: number; - take: number; -} - -export interface IPaginationQuery { - pageNumber: number; - pageSize: number; -} diff --git a/src/services/competition.service.ts b/src/services/competition.service.ts index 9ca21e1..ee179ae 100644 --- a/src/services/competition.service.ts +++ b/src/services/competition.service.ts @@ -62,7 +62,7 @@ export class CompetitionService { const userInfo = await userService.getUserInfo(userUuid); - await emailService.sendNotifyWinnerEmail( + await emailService.notifyWinnerViaEmail( userInfo.email, userInfo.name as string, ); diff --git a/src/services/email.service.ts b/src/services/email.service.ts index 3d04bfe..641eb9f 100644 --- a/src/services/email.service.ts +++ b/src/services/email.service.ts @@ -39,7 +39,7 @@ export class EmailService { }); } - async sendNotifyWinnerEmail(email: string, name: string) { + async notifyWinnerViaEmail(email: string, name: string) { const html = getWinnersTemplate().replace(/{{name}}/g, name); await this.mailProvider.sendEmail({ diff --git a/src/services/index.ts b/src/services/index.ts index b6bb4cf..b2e546a 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -6,7 +6,6 @@ export * from './github.service'; export * from './google.service'; export * from './hashing.service'; export * from './otp.service'; -export * from './pagination.service'; export * from './project.service'; export * from './redis.service'; export * from './refreshToken.service'; diff --git a/src/services/pagination.service.ts b/src/services/pagination.service.ts deleted file mode 100644 index 57a89a0..0000000 --- a/src/services/pagination.service.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { IPagination, IPaginationQuery } from '../interfaces'; - -export class PaginationService { - static getPagination({ - pageNumber, - pageSize, - }: IPaginationQuery): IPagination { - const skip = (pageNumber - 1) * pageSize; - const take = pageSize; - - return { skip, take }; - } -} diff --git a/src/services/providers/smtp.provider.ts b/src/services/providers/smtp.provider.ts index f0dd5a1..cf4102a 100644 --- a/src/services/providers/smtp.provider.ts +++ b/src/services/providers/smtp.provider.ts @@ -22,7 +22,10 @@ export class SmtpMailProvider implements IMailProvider { } async sendEmail(options: nodemailer.SendMailOptions): Promise { - await this.transporter.sendMail({ from: mailAuthUser, ...options }); + await this.transporter.sendMail({ + from: `Taskora support <${mailAuthUser}>`, + ...options, + }); } } diff --git a/src/types/index.ts b/src/types/index.ts index 33a4bb8..c7bdc74 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,5 +1,4 @@ export * from './jwt'; -export * from './query'; export * from './status'; export * from './statusCodes'; export * from './user'; diff --git a/src/types/query.ts b/src/types/query.ts deleted file mode 100644 index 646a14a..0000000 --- a/src/types/query.ts +++ /dev/null @@ -1 +0,0 @@ -export type ISortQuery = Array<{ [key: string]: 'asc' | 'desc' }>; diff --git a/src/utils/constants.ts b/src/utils/constants.ts index b438978..b9b405c 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -1,41 +1,3 @@ -// TODO: Need to make DB_COLUMNS a type -export const DB_COLUMNS = { - PROJECT: { - UUID: 'uuid', - NAME: 'name', - DESCRIPTION: 'description', - DUE_DATE: 'dueDate', - COLOR: 'color', - CREATED_AT: 'createdAt', - UPDATED_AT: 'updatedAt', - STATUS_UUID: 'statusUuid', - }, - TASK: { - UUID: 'uuid', - NAME: 'name', - DESCRIPTION: 'description', - DUE_DATE: 'dueDate', - CREATED_AT: 'createdAt', - UPDATED_AT: 'updatedAt', - PROJECT_UUID: 'projectUuid', - TAG_UUID: 'tagUuid', - STATUS_UUID: 'statusUuid', - }, - TAG: { - UUID: 'uuid', - NAME: 'name', - COLOR: 'color', - CREATED_AT: 'createdAt', - UPDATED_AT: 'updatedAt', - }, - STATUS: { - UUID: 'uuid', - NAME: 'name', - COLOR: 'color', - CREATED_AT: 'createdAt', - UPDATED_AT: 'updatedAt', - }, -}; export const SERVER = { DEVELOPMENT: 'development', PRODUCTION: 'production', @@ -50,6 +12,7 @@ export const SERVER = { `, LOCALHOST_URLS: ['http://localhost:3000', 'http://localhost:5174'], }; + export const API_INTEGRATION = { GOOGLE: { USER_INFO_SCOPES: [ @@ -66,6 +29,7 @@ export const API_INTEGRATION = { `https://api.github.com/applications/${clientId}/token`, }, }; + export const MAGIC_NUMBERS = { ONE_MINUTE_IN_MILLISECONDS: 60 * 1000, ONE_DAY_IN_MILLISECONDS: 24 * 60 * 60 * 1000, @@ -85,6 +49,7 @@ export const MAGIC_NUMBERS = { TEN: 10, }, }; + export const DEFAULT_VALUES = { PROJECTS: { name: '🚀 First Launch', diff --git a/src/utils/validations/index.ts b/src/utils/validations/index.ts index a5af440..4e03e3d 100644 --- a/src/utils/validations/index.ts +++ b/src/utils/validations/index.ts @@ -2,7 +2,6 @@ export * from './auth'; export * from './eid'; export * from './params'; export * from './project'; -export * from './query'; export * from './tags'; export * from './tasks'; export * from './user'; diff --git a/src/utils/validations/query.ts b/src/utils/validations/query.ts deleted file mode 100644 index 4eb8874..0000000 --- a/src/utils/validations/query.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { z } from 'zod'; - -export const paginationSchema = z.object({ - pageNumber: z.coerce.number().int().min(1).default(1), - pageSize: z.coerce.number().int().min(1).max(100).default(10), -}); - -export const sortSchema = z - .object({ - sortBy: z.string().optional(), - order: z.string().optional(), - }) - .refine( - (data) => - (!data.sortBy && !data.order) || - data.sortBy?.split(',').length === data.order?.split(',').length, - { message: "'sortBy' and 'order' must have the same number of fields" }, - );