Merge pull request 'Fix/missing environment variable type#7' (#15) from fix/missing-environment-variable-type#7 into dev
Reviewed-on: #15
This commit was merged in pull request #15.
This commit is contained in:
@@ -0,0 +1,207 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Template" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"language" TEXT NOT NULL,
|
||||||
|
"deliveryCharge" TEXT NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Template_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Banner" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"isVisible" BOOLEAN NOT NULL,
|
||||||
|
"bannerTitle" TEXT NOT NULL,
|
||||||
|
"bannerDesc" TEXT NOT NULL,
|
||||||
|
"bannerImage" TEXT NOT NULL,
|
||||||
|
"templateId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Banner_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Address" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"isVisible" BOOLEAN NOT NULL,
|
||||||
|
"phoneNumber" TEXT NOT NULL,
|
||||||
|
"shopLocation" TEXT NOT NULL,
|
||||||
|
"shopEmail" TEXT NOT NULL,
|
||||||
|
"templateId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Address_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Ingredient" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"isVisible" BOOLEAN NOT NULL,
|
||||||
|
"templateId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Ingredient_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "ingredientOptions" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"ingrImg" TEXT NOT NULL,
|
||||||
|
"ingrTitle" TEXT NOT NULL,
|
||||||
|
"ingrDes" TEXT NOT NULL,
|
||||||
|
"ingredientId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "ingredientOptions_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Instruction" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"isVisible" BOOLEAN NOT NULL,
|
||||||
|
"instBanner" TEXT NOT NULL,
|
||||||
|
"templateId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Instruction_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "InstructionOptions" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"hint" TEXT NOT NULL,
|
||||||
|
"detail" TEXT NOT NULL,
|
||||||
|
"instructionId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "InstructionOptions_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "FAQ" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"isVisible" BOOLEAN NOT NULL,
|
||||||
|
"templateId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "FAQ_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "FAQOptions" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"index" INTEGER NOT NULL,
|
||||||
|
"text" TEXT NOT NULL,
|
||||||
|
"faqId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "FAQOptions_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Tips" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"isVisible" BOOLEAN NOT NULL,
|
||||||
|
"tipsBanner" TEXT NOT NULL,
|
||||||
|
"templateId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Tips_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "TipsOption" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"index" INTEGER NOT NULL,
|
||||||
|
"text" TEXT NOT NULL,
|
||||||
|
"tipsId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "TipsOption_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "PriceCombo" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"isVisible" BOOLEAN NOT NULL,
|
||||||
|
"templateId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "PriceCombo_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "PriceOption" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"quantity" TEXT NOT NULL,
|
||||||
|
"price" TEXT NOT NULL,
|
||||||
|
"comboId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "PriceOption_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Product" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"isVisible" BOOLEAN NOT NULL,
|
||||||
|
"price" TEXT NOT NULL,
|
||||||
|
"discount" INTEGER NOT NULL,
|
||||||
|
"productName" TEXT NOT NULL,
|
||||||
|
"templateId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Product_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Banner_templateId_key" ON "Banner"("templateId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Address_templateId_key" ON "Address"("templateId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Ingredient_templateId_key" ON "Ingredient"("templateId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Instruction_templateId_key" ON "Instruction"("templateId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "FAQ_templateId_key" ON "FAQ"("templateId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Tips_templateId_key" ON "Tips"("templateId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "PriceCombo_templateId_key" ON "PriceCombo"("templateId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Product_templateId_key" ON "Product"("templateId");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Banner" ADD CONSTRAINT "Banner_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Address" ADD CONSTRAINT "Address_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Ingredient" ADD CONSTRAINT "Ingredient_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "ingredientOptions" ADD CONSTRAINT "ingredientOptions_ingredientId_fkey" FOREIGN KEY ("ingredientId") REFERENCES "Ingredient"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Instruction" ADD CONSTRAINT "Instruction_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "InstructionOptions" ADD CONSTRAINT "InstructionOptions_instructionId_fkey" FOREIGN KEY ("instructionId") REFERENCES "Instruction"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "FAQ" ADD CONSTRAINT "FAQ_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "FAQOptions" ADD CONSTRAINT "FAQOptions_faqId_fkey" FOREIGN KEY ("faqId") REFERENCES "FAQ"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Tips" ADD CONSTRAINT "Tips_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "TipsOption" ADD CONSTRAINT "TipsOption_tipsId_fkey" FOREIGN KEY ("tipsId") REFERENCES "Tips"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "PriceCombo" ADD CONSTRAINT "PriceCombo_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "PriceOption" ADD CONSTRAINT "PriceOption_comboId_fkey" FOREIGN KEY ("comboId") REFERENCES "PriceCombo"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Product" ADD CONSTRAINT "Product_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "ShopStatus" AS ENUM ('ACTIVE', 'SUSPENDED', 'DELETED');
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Profile" ADD COLUMN "status" "ShopStatus" NOT NULL DEFAULT 'ACTIVE';
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Users" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Users_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterEnum
|
||||||
|
ALTER TYPE "ShopStatus" ADD VALUE 'INACTIVE';
|
||||||
@@ -1,3 +1,10 @@
|
|||||||
|
enum ShopStatus {
|
||||||
|
ACTIVE
|
||||||
|
SUSPENDED
|
||||||
|
DELETED
|
||||||
|
INACTIVE
|
||||||
|
}
|
||||||
|
|
||||||
model Profile {
|
model Profile {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
accountId String @unique
|
accountId String @unique
|
||||||
@@ -8,7 +15,5 @@ model Profile {
|
|||||||
shopAddress String?
|
shopAddress String?
|
||||||
shopMapLocation String?
|
shopMapLocation String?
|
||||||
shopCategory String?
|
shopCategory String?
|
||||||
|
status ShopStatus @default(ACTIVE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
model Template {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
language String
|
||||||
|
deliveryCharge String
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
address Address?
|
||||||
|
banner Banner?
|
||||||
|
ingredient Ingredient?
|
||||||
|
instruction Instruction?
|
||||||
|
faq FAQ?
|
||||||
|
tips Tips?
|
||||||
|
priceCombo PriceCombo?
|
||||||
|
product Product?
|
||||||
|
}
|
||||||
|
|
||||||
|
// banner model
|
||||||
|
model Banner {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
isVisible Boolean
|
||||||
|
bannerTitle String
|
||||||
|
bannerDesc String
|
||||||
|
bannerImage String
|
||||||
|
templateId String @unique
|
||||||
|
template Template @relation(fields: [templateId], references: [id])
|
||||||
|
}
|
||||||
|
|
||||||
|
// address model
|
||||||
|
model Address {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
isVisible Boolean
|
||||||
|
phoneNumber String
|
||||||
|
shopLocation String
|
||||||
|
shopEmail String
|
||||||
|
templateId String @unique
|
||||||
|
template Template @relation(fields: [templateId], references: [id])
|
||||||
|
}
|
||||||
|
|
||||||
|
//ingredient model
|
||||||
|
model Ingredient {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
isVisible Boolean
|
||||||
|
templateId String @unique
|
||||||
|
template Template @relation(fields: [templateId], references: [id])
|
||||||
|
options ingredientOptions[]
|
||||||
|
}
|
||||||
|
|
||||||
|
//ingredient options model
|
||||||
|
model ingredientOptions {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
ingrImg String
|
||||||
|
ingrTitle String
|
||||||
|
ingrDes String
|
||||||
|
ingredientId String
|
||||||
|
ingredient Ingredient @relation(fields: [ingredientId], references: [id])
|
||||||
|
}
|
||||||
|
|
||||||
|
//instruction model & instruction options
|
||||||
|
model Instruction {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
isVisible Boolean
|
||||||
|
instBanner String
|
||||||
|
templateId String @unique
|
||||||
|
template Template @relation(fields: [templateId], references: [id])
|
||||||
|
options InstructionOptions[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model InstructionOptions {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
hint String
|
||||||
|
detail String
|
||||||
|
instructionId String
|
||||||
|
instruction Instruction @relation(fields: [instructionId], references: [id])
|
||||||
|
}
|
||||||
|
|
||||||
|
//FAQ & FAQOptions model
|
||||||
|
model FAQ {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
isVisible Boolean
|
||||||
|
templateId String @unique
|
||||||
|
template Template @relation(fields: [templateId], references: [id])
|
||||||
|
options FAQOptions[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model FAQOptions {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
index Int
|
||||||
|
text String
|
||||||
|
|
||||||
|
faqId String
|
||||||
|
faq FAQ @relation(fields: [faqId], references: [id])
|
||||||
|
}
|
||||||
|
|
||||||
|
//Tips & Tips options model
|
||||||
|
model Tips {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
isVisible Boolean
|
||||||
|
tipsBanner String
|
||||||
|
templateId String @unique
|
||||||
|
template Template @relation(fields: [templateId], references: [id])
|
||||||
|
options TipsOption[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model TipsOption {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
index Int
|
||||||
|
text String
|
||||||
|
|
||||||
|
tipsId String
|
||||||
|
tips Tips @relation(fields: [tipsId], references: [id])
|
||||||
|
}
|
||||||
|
|
||||||
|
//PriceCombo & PriceComboOptions model
|
||||||
|
model PriceCombo {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
isVisible Boolean
|
||||||
|
templateId String @unique
|
||||||
|
template Template @relation(fields: [templateId], references: [id])
|
||||||
|
options PriceOption[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model PriceOption {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
quantity String
|
||||||
|
price String
|
||||||
|
comboId String
|
||||||
|
combo PriceCombo @relation(fields: [comboId], references: [id])
|
||||||
|
}
|
||||||
|
|
||||||
|
//product model
|
||||||
|
model Product {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
isVisible Boolean
|
||||||
|
price String
|
||||||
|
discount Int
|
||||||
|
productName String
|
||||||
|
templateId String @unique
|
||||||
|
template Template @relation(fields: [templateId], references: [id])
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
model Users {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,77 +1,74 @@
|
|||||||
# ⚡ Express Server CLI
|
# QuickLaunch Server
|
||||||
|
|
||||||
[](https://www.npmjs.com/package/exp-node-server)
|
### This server is a nodejs server with express framework. It provides a REST API for quicklunch app. It is written in typescript and uses prisma for database.It is deployed on docker and is managed by docker compose.
|
||||||
[](https://www.npmjs.com/package/exp-node-server)
|
|
||||||
[](https://www.npmjs.com/package/exp-node-server)
|
|
||||||
[](https://www.typescriptlang.org/)
|
|
||||||
[](https://nodejs.org/)
|
|
||||||
|
|
||||||
---
|
### Features
|
||||||
|
|
||||||
## 🚀 Overview
|
- Authentication
|
||||||
|
- Authorization
|
||||||
|
- Database Management
|
||||||
|
- REST API
|
||||||
|
- Testing
|
||||||
|
- Deployment
|
||||||
|
|
||||||
A powerful `Express + TypeScript CLI` that instantly generates scalable `backend` modules with `Mongoose `/ `Prisma`, `Zod` `validation`, and `Swagger` documentation.
|
### Technologies
|
||||||
|
|
||||||
This tool helps developers quickly scaffold `clean`, `modular` `Express` APIs with minimal setup.
|
- Nodejs
|
||||||
|
- Express
|
||||||
|
- Typescript
|
||||||
|
- Prisma
|
||||||
|
- Docker
|
||||||
|
- Docker Compose
|
||||||
|
- Bullmq
|
||||||
|
-Nodemailer
|
||||||
|
|
||||||
## ✨ Features
|
### Deployment
|
||||||
|
|
||||||
- ⚡ Generate complete `Express` + `TypeScript` modules
|
- Docker
|
||||||
- 🧩 Built-in `Mongoose` / `Prisma` support
|
- Docker Compose
|
||||||
- 📘 Adds Swagger documentation automatically
|
|
||||||
- 📘 Automatic `Swagger` documentation
|
|
||||||
- 🔐 `Zod` validation ready
|
|
||||||
- 🏗️ `Modular` clean architecture
|
|
||||||
- 🚀 One command project setup
|
|
||||||
- 🔄 Add modules anytime
|
|
||||||
- 📦 Zero boilerplate setup
|
|
||||||
|
|
||||||
## 📦 Quick Start
|
### Authentication
|
||||||
|
|
||||||
Run directly using npx (recommended):
|
- JWT
|
||||||
|
|
||||||
```Bash
|
### Installation
|
||||||
npx exp-node-server -c my-api
|
|
||||||
```
|
|
||||||
|
|
||||||
This will:
|
- git clone git@codelab.techzaa.tech:summer2026/quicklanch-server.git
|
||||||
|
- cd quicklunch-server
|
||||||
|
- npm install
|
||||||
|
- npm run dev
|
||||||
|
|
||||||
- Create an Express starter project
|
### Environment variables are stored in .env file. They are:
|
||||||
- Install dependencies
|
Set up or add the following environment variables in .env file to run the server. You will copy and paste them from the .env.example file by adding Database URL,APP USER EMAIL, APP PASSWORD, CLOUD NAME, CLOUD API KEY, CLOUD API SECRET and REDIS URL :
|
||||||
- Prepare the project for development
|
- PORT = 5000
|
||||||
|
- DATABASE_URL
|
||||||
|
-ACCESS_TOKEN=8b8ba26578276a8bf9d0599f8c0ec0d2d69e0aec9171e989a314c36db0b330a23fd0365a6c9b1059406856046e28dc0e13c9d6a165e2936e6614aa2d1862af68
|
||||||
|
- ACCESS_EXPIRES=24h
|
||||||
|
- RESET_SECRET=8b8ba26578276a8bf9d0599f8c0ec0d2d69e0aec9171e989a314c36db0b330a23fd0365a6c9b1059406856046e28dc0e13c9d6a165e2936e6614aa2d1862af68
|
||||||
|
- RESET_EXPIRES=5m
|
||||||
|
- VERIFIED_TOKEN=8b8ba26578276a8bf9d0599f8c0ec0d2d69e0aec9171e989a314c36db0b330a23fd0365a6c9b1059406856046e28dc0e13c9d6a165e2936e6614aa2d1862af68
|
||||||
|
- FRONT_END_URL=http://localhost:5173/
|
||||||
|
- APP_USER_EMAIL
|
||||||
|
- APP_PASSWORD
|
||||||
|
- CLOUD_NAME
|
||||||
|
- CLOUD_API_KEY
|
||||||
|
- CLOUD_API_SECRET
|
||||||
|
- REDIS_URL
|
||||||
|
|
||||||
## 🧩 Generate a Module
|
### API Documentation
|
||||||
|
|
||||||
Inside your project run:
|
- API documentation is available at http://localhost:5000/api-docs
|
||||||
|
|
||||||
|
### API Creating
|
||||||
|
If you need to create an new api you will only run simple command the command is
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npx express-server-cli -g <module-name>
|
npx exp-node-server -g API_NAME (Your api name or folder name)
|
||||||
```
|
```
|
||||||
|
|
||||||
Example: `npx express-server-cli -g order`
|
### API Structure
|
||||||
|
|
||||||
Output:
|
|
||||||
|
|
||||||
```Bash
|
|
||||||
✔ order.interface.ts created
|
|
||||||
✔ order.schema.ts created
|
|
||||||
✔ order.validation.ts created
|
|
||||||
✔ order.route.ts created
|
|
||||||
✔ order.controller.ts created
|
|
||||||
✔ order.service.ts created
|
|
||||||
✔ order.swagger.ts created
|
|
||||||
|
|
||||||
🔗 Route registered in routes.ts
|
|
||||||
📘 Swagger docs registered
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
src/app/modules/<module-name>/
|
||||||
## 📁 Generated Module Structure
|
|
||||||
|
|
||||||
Each module follows a clean structure:
|
|
||||||
|
|
||||||
```Bash
|
|
||||||
src/app/modules/<module-name>/
|
|
||||||
├── <module>.interface.ts
|
├── <module>.interface.ts
|
||||||
├── <module>.schema.ts
|
├── <module>.schema.ts
|
||||||
├── <module>.validation.ts
|
├── <module>.validation.ts
|
||||||
@@ -79,48 +76,4 @@ src/app/modules/<module-name>/
|
|||||||
├── <module>.controller.ts
|
├── <module>.controller.ts
|
||||||
├── <module>.service.ts
|
├── <module>.service.ts
|
||||||
└── <module>.swagger.ts
|
└── <module>.swagger.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
## ⚙️ Run the Project
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
Swagger docs available at:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
http://localhost:5000/docs
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🧠 Tech Stack
|
|
||||||
|
|
||||||
- Express.js — Backend framework
|
|
||||||
- TypeScript — Strongly typed JavaScript
|
|
||||||
- Mongoose — MongoDB ODM
|
|
||||||
- Prisma — PostgreSQL ORM
|
|
||||||
- Zod — Runtime schema validation
|
|
||||||
- JWT — Authentication
|
|
||||||
- Swagger — API documentation
|
|
||||||
|
|
||||||
## 👨💻 Author
|
|
||||||
|
|
||||||
### Abumahid
|
|
||||||
|
|
||||||
GitHub
|
|
||||||
https://github.com/dev-abumahid
|
|
||||||
|
|
||||||
npm
|
|
||||||
https://www.npmjs.com/~dev_abumahid
|
|
||||||
|
|
||||||
Portfolio
|
|
||||||
https://abumahid.me
|
|
||||||
|
|
||||||
LinkedIn
|
|
||||||
https://linkedin.com/in/md-abu-mahid-islam
|
|
||||||
|
|
||||||
## ⭐ Support
|
|
||||||
|
|
||||||
If you find this project helpful, consider giving it a ⭐ on `GitHub`.
|
|
||||||
|
|
||||||
It helps the project grow and reach more developers.
|
|
||||||
+29
-17
@@ -1,27 +1,39 @@
|
|||||||
import "dotenv/config";
|
import "dotenv/config";
|
||||||
|
|
||||||
|
function getEnv(key: string): string {
|
||||||
|
const value = process.env[key];
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
throw new Error(`Missing required environment variable: ${key}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
export const configs = {
|
export const configs = {
|
||||||
port: process.env.PORT,
|
port: getEnv("PORT"),
|
||||||
env: process.env.NODE_ENV,
|
env: getEnv("NODE_ENV"),
|
||||||
db_url: process.env.DATABASE_URL,
|
db_url: getEnv("DATABASE_URL"),
|
||||||
|
|
||||||
jwt: {
|
jwt: {
|
||||||
access_token: process.env.ACCESS_TOKEN,
|
access_token: getEnv("ACCESS_TOKEN"),
|
||||||
refresh_token: process.env.REFRESH_TOKEN,
|
access_expires: getEnv("ACCESS_EXPIRES"),
|
||||||
access_expires: process.env.ACCESS_EXPIRES,
|
reset_secret: getEnv("RESET_SECRET"),
|
||||||
refresh_expires: process.env.REFRESH_EXPIRES,
|
reset_expires: getEnv("RESET_EXPIRES"),
|
||||||
reset_secret: process.env.RESET_SECRET,
|
front_end_url: getEnv("FRONT_END_URL"),
|
||||||
reset_expires: process.env.RESET_EXPIRES,
|
verified_token: getEnv("VERIFIED_TOKEN"),
|
||||||
front_end_url: process.env.FRONT_END_URL,
|
|
||||||
verified_token: process.env.VERIFIED_TOKEN,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
email: {
|
email: {
|
||||||
app_email: process.env.APP_USER_EMAIL,
|
app_email: getEnv("APP_USER_EMAIL"),
|
||||||
app_password: process.env.APP_PASSWORD,
|
app_password: getEnv("APP_PASSWORD"),
|
||||||
},
|
},
|
||||||
|
|
||||||
cloudinary: {
|
cloudinary: {
|
||||||
cloud_name: process.env.CLOUD_NAME,
|
cloud_name: getEnv("CLOUD_NAME"),
|
||||||
cloud_api_key: process.env.CLOUD_API_KEY,
|
cloud_api_key: getEnv("CLOUD_API_KEY"),
|
||||||
cloud_api_secret: process.env.CLOUD_API_SECRET,
|
cloud_api_secret: getEnv("CLOUD_API_SECRET"),
|
||||||
},
|
},
|
||||||
redis_url: process.env.REDIS_URL,
|
|
||||||
|
redis_url: getEnv("REDIS_URL"),
|
||||||
};
|
};
|
||||||
@@ -19,54 +19,30 @@ const get_all_order_from_db = async (req: Request) => {
|
|||||||
const status = (req.query.status as string) || undefined;
|
const status = (req.query.status as string) || undefined;
|
||||||
const { page, limit, skip, sortBy, sortOrder } = paginationHelper(req.query);
|
const { page, limit, skip, sortBy, sortOrder } = paginationHelper(req.query);
|
||||||
|
|
||||||
const andCondition = [] as any[];
|
const andCondition = {} as any;
|
||||||
if (search) {
|
if (search) {
|
||||||
andCondition.push({
|
andCondition.productName = {
|
||||||
OR: [
|
|
||||||
{
|
|
||||||
productName: {
|
|
||||||
contains: search,
|
contains: search,
|
||||||
mode: "insensitive",
|
mode: "insensitive",
|
||||||
},
|
};
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (customerName) {
|
if (customerName) {
|
||||||
andCondition.push({
|
andCondition.customerName = {
|
||||||
OR: [
|
|
||||||
{
|
|
||||||
customerName: {
|
|
||||||
contains: customerName,
|
contains: customerName,
|
||||||
mode: "insensitive",
|
mode: "insensitive",
|
||||||
},
|
};
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (productName) {
|
if (productName) {
|
||||||
andCondition.push({
|
andCondition.productName = {
|
||||||
OR: [
|
|
||||||
{
|
|
||||||
productName: {
|
|
||||||
contains: productName,
|
contains: productName,
|
||||||
mode: "insensitive",
|
mode: "insensitive",
|
||||||
},
|
};
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (status) {
|
if (status) {
|
||||||
andCondition.push({
|
andCondition.status = {
|
||||||
OR: [
|
|
||||||
{
|
|
||||||
status: {
|
|
||||||
contains: status,
|
contains: status,
|
||||||
mode: "insensitive",
|
mode: "insensitive",
|
||||||
},
|
};
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// for date filter
|
// for date filter
|
||||||
@@ -82,16 +58,20 @@ const get_all_order_from_db = async (req: Request) => {
|
|||||||
dateFilter.lte = end;
|
dateFilter.lte = end;
|
||||||
}
|
}
|
||||||
if (Object.keys(dateFilter).length > 0) {
|
if (Object.keys(dateFilter).length > 0) {
|
||||||
andCondition.push({
|
andCondition.createdAt = dateFilter;
|
||||||
createdAt: dateFilter,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAllOrders = await prisma.order.findMany({
|
const getAllOrders = await prisma.order.findMany({
|
||||||
take: limit,
|
take: limit,
|
||||||
skip,
|
skip,
|
||||||
where: {
|
where: andCondition,
|
||||||
AND: andCondition,
|
select: {
|
||||||
|
id: true,
|
||||||
|
customerName: true,
|
||||||
|
productQuantity: true,
|
||||||
|
productPrice: true,
|
||||||
|
status: true,
|
||||||
|
createdAt: true,
|
||||||
},
|
},
|
||||||
orderBy: {
|
orderBy: {
|
||||||
[sortBy as string]: sortOrder,
|
[sortBy as string]: sortOrder,
|
||||||
@@ -122,7 +102,7 @@ const get_single_order_from_db = async (req: Request) => {
|
|||||||
|
|
||||||
const create_order_into_db = async (req: Request) => {
|
const create_order_into_db = async (req: Request) => {
|
||||||
const payload = req?.body;
|
const payload = req?.body;
|
||||||
console.log(payload);
|
|
||||||
payload.status = "INITIATED";
|
payload.status = "INITIATED";
|
||||||
payload.paymentType = "COD";
|
payload.paymentType = "COD";
|
||||||
|
|
||||||
@@ -145,7 +125,6 @@ const create_order_into_db = async (req: Request) => {
|
|||||||
const update_order_into_db = async (req: Request) => {
|
const update_order_into_db = async (req: Request) => {
|
||||||
// define your own login here
|
// define your own login here
|
||||||
const user = req.user;
|
const user = req.user;
|
||||||
console.log(user);
|
|
||||||
if (user?.role !== "ADMIN") {
|
if (user?.role !== "ADMIN") {
|
||||||
throw new AppError("You are not authorized to perform this action", 403);
|
throw new AppError("You are not authorized to perform this action", 403);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ export const orderSwaggerDocs = {
|
|||||||
patch: {
|
patch: {
|
||||||
tags: ["order"],
|
tags: ["order"],
|
||||||
summary: "Update order -(Admin route)",
|
summary: "Update order -(Admin route)",
|
||||||
description: "",
|
description: "The status can be updated to any of the following values : INITIATED,CONFIRMED,ONGOING,DELIVERED,CANCELLED",
|
||||||
parameters: [
|
parameters: [
|
||||||
{
|
{
|
||||||
name: "id",
|
name: "id",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const create_order = z.object({
|
|||||||
customerNote: z.string().optional()
|
customerNote: z.string().optional()
|
||||||
});
|
});
|
||||||
const update_order = z.object({
|
const update_order = z.object({
|
||||||
status: z.string().optional()
|
status: z.enum(["INITIATED","CONFIRMED","ONGOING","DELIVERED","CANCELLED"]).optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export const order_validations = {
|
export const order_validations = {
|
||||||
|
|||||||
@@ -5,7 +5,16 @@ import { AppError } from "../../utils/app_error.js";
|
|||||||
|
|
||||||
const get_all_plan_from_db = async (req: Request) => {
|
const get_all_plan_from_db = async (req: Request) => {
|
||||||
// define your own login here
|
// define your own login here
|
||||||
const result = await prisma.plan.findMany();
|
const result = await prisma.plan.findMany({
|
||||||
|
select:{
|
||||||
|
planName: true,
|
||||||
|
price: true,
|
||||||
|
planType: true,
|
||||||
|
planDesc: true,
|
||||||
|
planFeatures: true,
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ const update_profile_into_db = async (req: Request) => {
|
|||||||
const user = req?.user as JwtPayloadType;
|
const user = req?.user as JwtPayloadType;
|
||||||
const payload = req?.body;
|
const payload = req?.body;
|
||||||
const file = req?.file;
|
const file = req?.file;
|
||||||
console.log(payload);
|
|
||||||
// check file and upload to cloud
|
// check file and upload to cloud
|
||||||
if (file) {
|
if (file) {
|
||||||
const cloudRes = await uploadCloud(file);
|
const cloudRes = await uploadCloud(file);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const profileSwaggerDocs = {
|
|||||||
data: {
|
data: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
fullName: { type: "string" },
|
shopName: { type: "string" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
file: {
|
file: {
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
const update_profile = z.object({
|
const update_profile = z.object({
|
||||||
fullName: z.string().optional(),
|
shopName: z.string().optional(),
|
||||||
|
shopAddress: z.string().optional(),
|
||||||
|
shopPhone: z.string().optional(),
|
||||||
|
shopLocation: z.string().optional(),
|
||||||
|
shopImage: z.string().optional(),
|
||||||
|
shopMapLocation: z.string().optional(),
|
||||||
|
contactNumber: z.string().optional(),
|
||||||
|
shopCategory: z.string().optional(),
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const profile_validations = {
|
export const profile_validations = {
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
|
||||||
|
export const staticticsSwaggerDocs = {
|
||||||
|
"/api/statictics": {
|
||||||
|
post: {
|
||||||
|
tags: ["statictics"],
|
||||||
|
summary: "Create new statictics",
|
||||||
|
description: "",
|
||||||
|
requestBody: {
|
||||||
|
|
||||||
|
required: true,
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
example: JSON.stringify({}), // put your request body
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
201: { description: "statictics created successfully" },
|
||||||
|
500: { description: "Validation error or internal server error" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
get: {
|
||||||
|
tags: ["statictics"],
|
||||||
|
summary: "Get all statictics",
|
||||||
|
description: "",
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "page",
|
||||||
|
in: "query",
|
||||||
|
required: false,
|
||||||
|
schema: { type: "number" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "limit",
|
||||||
|
in: "query",
|
||||||
|
required: false,
|
||||||
|
schema: { type: "number" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
responses: {
|
||||||
|
200: { description: "statictics fetched successfully" },
|
||||||
|
401: { description: "unauthorized" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"/api/statictics/seller": {
|
||||||
|
get: {
|
||||||
|
tags: ["statistics"],
|
||||||
|
summary: "Get seller statistics",
|
||||||
|
description: "Fetch seller dashboard stats (7d, 30d, all)",
|
||||||
|
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "range",
|
||||||
|
in: "query",
|
||||||
|
required: false,
|
||||||
|
schema: {
|
||||||
|
type: "string",
|
||||||
|
enum: ["7d", "30d", "all"],
|
||||||
|
default: "7d",
|
||||||
|
},
|
||||||
|
description: "Time range for statistics",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: "Statistics fetched successfully",
|
||||||
|
},
|
||||||
|
401: {
|
||||||
|
description: "Unauthorized",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"/api/statictics/{id}": {
|
||||||
|
get: {
|
||||||
|
tags: ["statictics"],
|
||||||
|
summary: "Get single statictics",
|
||||||
|
description: "",
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
in: "path",
|
||||||
|
required: true,
|
||||||
|
schema: { type: "string" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
responses: {
|
||||||
|
200: { description: "statictics fetched successfully" },
|
||||||
|
401: { description: "unauthorized" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
patch: {
|
||||||
|
tags: ["statictics"],
|
||||||
|
summary: "Update statictics",
|
||||||
|
description: "",
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
in: "path",
|
||||||
|
required: true,
|
||||||
|
schema: { type: "string" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
requestBody: {
|
||||||
|
required: true,
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
example: JSON.stringify({}), // put your request body
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
200: { description: "statictics updated successfully" },
|
||||||
|
500: { description: "Validation error or internal server error" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
tags: ["statictics"],
|
||||||
|
summary: "Delete statictics",
|
||||||
|
description: "",
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
in: "path",
|
||||||
|
required: true,
|
||||||
|
schema: { type: "string" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
responses: {
|
||||||
|
200: { description: "statictics delete successfully" },
|
||||||
|
401: { description: "unauthorized" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import catchAsync from "../../utils/catch_async.js";
|
||||||
|
import manageResponse from "../../utils/manage_response.js";
|
||||||
|
import { template_service } from "./template.service.js";
|
||||||
|
|
||||||
|
const get_all_template = catchAsync(async (req, res) => {
|
||||||
|
const result = await template_service.get_all_template_from_db(req);
|
||||||
|
manageResponse(res, {
|
||||||
|
success: true,
|
||||||
|
statusCode: 200,
|
||||||
|
message: "All template fetched successfully.",
|
||||||
|
data: result,
|
||||||
|
meta: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const get_single_template = catchAsync(async (req, res) => {
|
||||||
|
const result = await template_service.get_single_template_from_db(req);
|
||||||
|
manageResponse(res, {
|
||||||
|
success: true,
|
||||||
|
statusCode: 200,
|
||||||
|
message: "Single template fetched successfully.",
|
||||||
|
data: result,
|
||||||
|
meta: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const create_template = catchAsync(async (req, res) => {
|
||||||
|
const result = await template_service.create_template_into_db(req);
|
||||||
|
manageResponse(res, {
|
||||||
|
success: true,
|
||||||
|
statusCode: 200,
|
||||||
|
message: "template created successfully.",
|
||||||
|
data: result,
|
||||||
|
meta: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const update_template = catchAsync(async (req, res) => {
|
||||||
|
const result = await template_service.update_template_into_db(req);
|
||||||
|
manageResponse(res, {
|
||||||
|
success: true,
|
||||||
|
statusCode: 200,
|
||||||
|
message: "template updated successfully.",
|
||||||
|
data: result,
|
||||||
|
meta: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const delete_template = catchAsync(async (req, res) => {
|
||||||
|
const result = await template_service.delete_template_from_db(req);
|
||||||
|
manageResponse(res, {
|
||||||
|
success: true,
|
||||||
|
statusCode: 200,
|
||||||
|
message: "template deleted successfully.",
|
||||||
|
data: result,
|
||||||
|
meta: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export const template_controller = {
|
||||||
|
get_all_template,
|
||||||
|
get_single_template,
|
||||||
|
create_template,
|
||||||
|
update_template,
|
||||||
|
delete_template,
|
||||||
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
import RequestValidator from "../../middlewares/request_validator.js";
|
||||||
|
import { template_controller } from "./template.controller.js";
|
||||||
|
import { template_validations } from "./template.validation.js";
|
||||||
|
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
router.get("/", template_controller.get_all_template);
|
||||||
|
router.post(
|
||||||
|
"/",
|
||||||
|
RequestValidator(template_validations.create_template),
|
||||||
|
template_controller.create_template,
|
||||||
|
);
|
||||||
|
router.get("/:id", template_controller.get_single_template);
|
||||||
|
router.patch(
|
||||||
|
"/:id",
|
||||||
|
RequestValidator(template_validations.update_template),
|
||||||
|
template_controller.update_template,
|
||||||
|
);
|
||||||
|
router.delete("/:id", template_controller.delete_template);
|
||||||
|
|
||||||
|
export default router;
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
import { Request } from "express";
|
||||||
|
import { prisma } from "../../lib/prisma.js";
|
||||||
|
|
||||||
|
const get_all_template_from_db = async (req: Request) => {
|
||||||
|
// define your own login here
|
||||||
|
const result = await prisma.template.findMany({});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const get_single_template_from_db = async (req: Request) => {
|
||||||
|
// define your own login here
|
||||||
|
const { id } = req.params as { id: string };
|
||||||
|
const result = await prisma.template.findUnique({
|
||||||
|
where: { id },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
language: true,
|
||||||
|
deliveryCharge: true,
|
||||||
|
banner: true,
|
||||||
|
address: true,
|
||||||
|
ingredient: true,
|
||||||
|
instruction: true,
|
||||||
|
faq: true,
|
||||||
|
tips: true,
|
||||||
|
priceCombo: true,
|
||||||
|
product: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const create_template_into_db = async (req: Request) => {
|
||||||
|
// define your own login here
|
||||||
|
const payload = req.body;
|
||||||
|
console.log(payload);
|
||||||
|
const result = await prisma.template.create({
|
||||||
|
data: {
|
||||||
|
language: payload.language,
|
||||||
|
deliveryCharge: payload.deliveryCharge,
|
||||||
|
|
||||||
|
banner: {
|
||||||
|
create: payload.banner,
|
||||||
|
},
|
||||||
|
|
||||||
|
address: {
|
||||||
|
create: payload.address,
|
||||||
|
},
|
||||||
|
|
||||||
|
ingredient: {
|
||||||
|
create: {
|
||||||
|
isVisible: payload.ingredient.isVisible,
|
||||||
|
options: {
|
||||||
|
create: payload.ingredient.options,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
instruction: {
|
||||||
|
create: {
|
||||||
|
isVisible: payload.instruction.isVisible,
|
||||||
|
instBanner: payload.instruction.instBanner,
|
||||||
|
options: {
|
||||||
|
create: payload.instruction.options,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
faq: {
|
||||||
|
create: {
|
||||||
|
isVisible: payload.faq.isVisible,
|
||||||
|
options: {
|
||||||
|
create: payload.faq.options,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
tips: {
|
||||||
|
create: {
|
||||||
|
isVisible: payload.tips.isVisible,
|
||||||
|
tipsBanner: payload.tips.tipsBanner,
|
||||||
|
options: {
|
||||||
|
create: payload.tips.options,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
priceCombo: {
|
||||||
|
create: {
|
||||||
|
isVisible: payload.priceCombo.isVisible,
|
||||||
|
options: {
|
||||||
|
create: payload.priceCombo.options,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
product: {
|
||||||
|
create: {
|
||||||
|
isVisible: payload.product.isVisible,
|
||||||
|
price: payload.product.price,
|
||||||
|
discount: payload.product.discount,
|
||||||
|
productName: payload.product.productName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
include: {
|
||||||
|
banner: true,
|
||||||
|
address: true,
|
||||||
|
ingredient: { include: { options: true } },
|
||||||
|
instruction: { include: { options: true } },
|
||||||
|
faq: { include: { options: true } },
|
||||||
|
tips: { include: { options: true } },
|
||||||
|
priceCombo: { include: { options: true } },
|
||||||
|
product: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const update_template_into_db = async (req: Request) => {
|
||||||
|
// define your own login here
|
||||||
|
const { id } = req.params as { id: string };
|
||||||
|
const result = await prisma.template.update({
|
||||||
|
where: { id },
|
||||||
|
data: req.body,
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const delete_template_from_db = async (req: Request) => {
|
||||||
|
// define your own login here
|
||||||
|
const { id } = req.params as { id: string };
|
||||||
|
const result = await prisma.template.delete({ where: { id } });
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const template_service = {
|
||||||
|
get_all_template_from_db,
|
||||||
|
get_single_template_from_db,
|
||||||
|
create_template_into_db,
|
||||||
|
update_template_into_db,
|
||||||
|
delete_template_from_db,
|
||||||
|
};
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
export const templateSwaggerDocs = {
|
||||||
|
"/api/template": {
|
||||||
|
post: {
|
||||||
|
tags: ["template"],
|
||||||
|
summary: "Create new template",
|
||||||
|
description: "",
|
||||||
|
requestBody: {
|
||||||
|
required: true,
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
example: JSON.stringify({
|
||||||
|
language: "en",
|
||||||
|
deliveryCharge: "60",
|
||||||
|
banner: {
|
||||||
|
isVisible: true,
|
||||||
|
bannerTitle: "Delicious Homemade Food",
|
||||||
|
bannerDesc:
|
||||||
|
"Fresh, healthy and tasty meals delivered to your door.",
|
||||||
|
bannerImage: "https://example.com/banner.jpg",
|
||||||
|
},
|
||||||
|
address: {
|
||||||
|
isVisible: true,
|
||||||
|
phoneNumber: "+8801712345678",
|
||||||
|
shopLocation: "Dhaka, Bangladesh",
|
||||||
|
shopEmail: "foodshop@example.com",
|
||||||
|
},
|
||||||
|
ingredient: {
|
||||||
|
isVisible: true,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
ingrImg: "https://example.com/tomato.jpg",
|
||||||
|
ingrTitle: "Tomato",
|
||||||
|
ingrDes: "Fresh organic tomatoes",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ingrImg: "https://example.com/chicken.jpg",
|
||||||
|
ingrTitle: "Chicken",
|
||||||
|
ingrDes: "Premium quality chicken",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
instruction: {
|
||||||
|
isVisible: true,
|
||||||
|
instBanner: "https://example.com/instruction-banner.jpg",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
hint: "Step 1",
|
||||||
|
detail: "Wash all ingredients properly",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hint: "Step 2",
|
||||||
|
detail: "Cook on medium heat for 20 minutes",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
faq: {
|
||||||
|
isVisible: true,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
index: 1,
|
||||||
|
text: "Is the food fresh?",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 2,
|
||||||
|
text: "Do you offer home delivery?",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
tips: {
|
||||||
|
isVisible: true,
|
||||||
|
tipsBanner: "https://example.com/tips-banner.jpg",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
index: 1,
|
||||||
|
text: "Use fresh ingredients for best taste",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 2,
|
||||||
|
text: "Serve hot for better flavor",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
priceCombo: {
|
||||||
|
isVisible: true,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
quantity: "1",
|
||||||
|
price: "120",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
quantity: "2",
|
||||||
|
price: "220",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
product: {
|
||||||
|
isVisible: true,
|
||||||
|
price: "120",
|
||||||
|
discount: 10,
|
||||||
|
productName: "Chicken Burger",
|
||||||
|
},
|
||||||
|
}), // put your request body
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
201: { description: "template created successfully" },
|
||||||
|
500: { description: "Validation error or internal server error" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
get: {
|
||||||
|
tags: ["template"],
|
||||||
|
summary: "Get all template",
|
||||||
|
description: "",
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "page",
|
||||||
|
in: "query",
|
||||||
|
required: false,
|
||||||
|
schema: { type: "number" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "limit",
|
||||||
|
in: "query",
|
||||||
|
required: false,
|
||||||
|
schema: { type: "number" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
responses: {
|
||||||
|
200: { description: "template fetched successfully" },
|
||||||
|
401: { description: "unauthorized" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"/api/template/{id}": {
|
||||||
|
get: {
|
||||||
|
tags: ["template"],
|
||||||
|
summary: "Get single template",
|
||||||
|
description: "",
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
in: "path",
|
||||||
|
required: true,
|
||||||
|
schema: { type: "string" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
responses: {
|
||||||
|
200: { description: "template fetched successfully" },
|
||||||
|
401: { description: "unauthorized" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
patch: {
|
||||||
|
tags: ["template"],
|
||||||
|
summary: "Update template",
|
||||||
|
description: "",
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
in: "path",
|
||||||
|
required: true,
|
||||||
|
schema: { type: "string" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
requestBody: {
|
||||||
|
required: true,
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
example: JSON.stringify({}), // put your request body
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
200: { description: "template updated successfully" },
|
||||||
|
500: { description: "Validation error or internal server error" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
tags: ["template"],
|
||||||
|
summary: "Delete template",
|
||||||
|
description: "",
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
in: "path",
|
||||||
|
required: true,
|
||||||
|
schema: { type: "string" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
responses: {
|
||||||
|
200: { description: "template delete successfully" },
|
||||||
|
401: { description: "unauthorized" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
// Template Options that we need to use for validation.
|
||||||
|
|
||||||
|
// Ingredient Option
|
||||||
|
const ingredientOptionSchema = z.object({
|
||||||
|
ingrImg: z.string().url().or(z.string()),
|
||||||
|
ingrTitle: z.string().min(1),
|
||||||
|
ingrDes: z.string().min(1),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Instruction Option
|
||||||
|
const instructionOptionSchema = z.object({
|
||||||
|
hint: z.string().min(1),
|
||||||
|
detail: z.string().min(1),
|
||||||
|
});
|
||||||
|
|
||||||
|
// FAQ Option
|
||||||
|
const faqOptionSchema = z.object({
|
||||||
|
index: z.number(),
|
||||||
|
text: z.string().min(1),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Tips Option
|
||||||
|
const tipsOptionSchema = z.object({
|
||||||
|
index: z.number(),
|
||||||
|
text: z.string().min(1),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Price Option
|
||||||
|
const priceOptionSchema = z.object({
|
||||||
|
quantity: z.string().min(1),
|
||||||
|
price: z.string().min(1),
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Create the main template schema validation
|
||||||
|
const create_template = z.object({
|
||||||
|
language: z.string().min(1),
|
||||||
|
deliveryCharge: z.string().min(1),
|
||||||
|
banner: z.object({
|
||||||
|
isVisible: z.boolean(),
|
||||||
|
bannerTitle: z.string().min(1),
|
||||||
|
bannerDesc: z.string().min(1),
|
||||||
|
bannerImage: z.string(),
|
||||||
|
}),
|
||||||
|
address: z.object({
|
||||||
|
isVisible: z.boolean(),
|
||||||
|
phoneNumber: z.string().min(1),
|
||||||
|
shopLocation: z.string().min(1),
|
||||||
|
shopEmail: z.string().email(),
|
||||||
|
}),
|
||||||
|
ingredient: z.object({
|
||||||
|
isVisible: z.boolean(),
|
||||||
|
options: z.array(ingredientOptionSchema).min(1),
|
||||||
|
}),
|
||||||
|
instruction: z.object({
|
||||||
|
isVisible: z.boolean(),
|
||||||
|
instBanner: z.string(),
|
||||||
|
options: z.array(instructionOptionSchema).min(1),
|
||||||
|
}),
|
||||||
|
faq: z.object({
|
||||||
|
isVisible: z.boolean(),
|
||||||
|
options: z.array(faqOptionSchema).min(1),
|
||||||
|
}),
|
||||||
|
tips: z.object({
|
||||||
|
isVisible: z.boolean(),
|
||||||
|
tipsBanner: z.string(),
|
||||||
|
options: z.array(tipsOptionSchema).min(1),
|
||||||
|
}),
|
||||||
|
priceCombo: z.object({
|
||||||
|
isVisible: z.boolean(),
|
||||||
|
options: z.array(priceOptionSchema).min(1),
|
||||||
|
}),
|
||||||
|
product: z.object({
|
||||||
|
isVisible: z.boolean(),
|
||||||
|
price: z.string().min(1),
|
||||||
|
discount: z.number().min(0),
|
||||||
|
productName: z.string().min(1),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const update_template = z.object({});
|
||||||
|
|
||||||
|
export const template_validations = {
|
||||||
|
create_template,
|
||||||
|
update_template,
|
||||||
|
};
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import catchAsync from "../../utils/catch_async.js";
|
||||||
|
import manageResponse from "../../utils/manage_response.js";
|
||||||
|
import { users_service } from "./users.service.js";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const get_all_users = catchAsync(async (req, res) => {
|
||||||
|
const result = await users_service.get_all_users_from_db(req);
|
||||||
|
manageResponse(res, {
|
||||||
|
success: true,
|
||||||
|
statusCode: 200,
|
||||||
|
message: "All users fetched successfully.",
|
||||||
|
data: result,
|
||||||
|
meta: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const get_single_users = catchAsync(async (req, res) => {
|
||||||
|
const result = await users_service.get_single_users_from_db(req);
|
||||||
|
manageResponse(res, {
|
||||||
|
success: true,
|
||||||
|
statusCode: 200,
|
||||||
|
message: "Single users fetched successfully.",
|
||||||
|
data: result,
|
||||||
|
meta: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const create_users = catchAsync(async (req, res) => {
|
||||||
|
const result = await users_service.create_users_into_db(req);
|
||||||
|
manageResponse(res, {
|
||||||
|
success: true,
|
||||||
|
statusCode: 200,
|
||||||
|
message: "users created successfully.",
|
||||||
|
data: result,
|
||||||
|
meta: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const update_users = catchAsync(async (req, res) => {
|
||||||
|
const result = await users_service.update_users_into_db(req);
|
||||||
|
manageResponse(res, {
|
||||||
|
success: true,
|
||||||
|
statusCode: 200,
|
||||||
|
message: "users updated successfully.",
|
||||||
|
data: result,
|
||||||
|
meta: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const delete_users = catchAsync(async (req, res) => {
|
||||||
|
const result = await users_service.delete_users_from_db(req);
|
||||||
|
manageResponse(res, {
|
||||||
|
success: true,
|
||||||
|
statusCode: 200,
|
||||||
|
message: "users deleted successfully.",
|
||||||
|
data: result,
|
||||||
|
meta: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export const users_controller = {
|
||||||
|
get_all_users,
|
||||||
|
get_single_users,
|
||||||
|
create_users,
|
||||||
|
update_users,
|
||||||
|
delete_users,
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
import { Router } from "express";
|
||||||
|
import { users_controller } from "./users.controller.js";
|
||||||
|
import { users_validations } from "./users.validation.js";
|
||||||
|
import RequestValidator from "../../middlewares/request_validator.js";
|
||||||
|
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
router.get("/", users_controller.get_all_users);
|
||||||
|
router.post(
|
||||||
|
"/",
|
||||||
|
RequestValidator(users_validations.create_users),
|
||||||
|
users_controller.create_users,
|
||||||
|
);
|
||||||
|
router.get("/:id", users_controller.get_single_users);
|
||||||
|
router.patch(
|
||||||
|
"/:id",
|
||||||
|
RequestValidator(users_validations.update_users),
|
||||||
|
users_controller.update_users,
|
||||||
|
);
|
||||||
|
router.delete("/:id", users_controller.delete_users);
|
||||||
|
|
||||||
|
export default router;
|
||||||
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import { Request } from "express";
|
||||||
|
import { prisma } from "../../lib/prisma.js";
|
||||||
|
import paginationHelper from "../../utils/pagination_helper.js";
|
||||||
|
|
||||||
|
const get_all_users_from_db = async (req: Request) => {
|
||||||
|
const { page, skip, limit } = paginationHelper(req.query);
|
||||||
|
const search = req.query.search as string;
|
||||||
|
|
||||||
|
const andCondition = {} as any;
|
||||||
|
if (search) {
|
||||||
|
andCondition.shopName = {
|
||||||
|
contains: search,
|
||||||
|
mode: "insensitive",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// define your own login here
|
||||||
|
const result = await prisma.profile.findMany({
|
||||||
|
take: limit,
|
||||||
|
skip,
|
||||||
|
where: andCondition,
|
||||||
|
select: {
|
||||||
|
account: {
|
||||||
|
select: {
|
||||||
|
isSubscribe: true,
|
||||||
|
email: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shopName: true,
|
||||||
|
id: true,
|
||||||
|
status: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const usersCount = await prisma.profile.count();
|
||||||
|
return { result, usersCount, page, limit, skip };
|
||||||
|
};
|
||||||
|
|
||||||
|
const get_single_users_from_db = async (req: Request) => {
|
||||||
|
// define your own login here
|
||||||
|
const { id } = req.params as { id: string };
|
||||||
|
const result = await prisma.profile.findUnique({ where: { id } });
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const create_users_into_db = async (req: Request) => {
|
||||||
|
// define your own login here
|
||||||
|
const result = await prisma.account.create({ data: req.body });
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const update_users_into_db = async (req: Request) => {
|
||||||
|
// define your own login here
|
||||||
|
const { id } = req.params as { id: string };
|
||||||
|
const result = await prisma.account.update({ where: { id }, data: req.body });
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const delete_users_from_db = async (req: Request) => {
|
||||||
|
// define your own login here
|
||||||
|
const { id } = req.params as { id: string };
|
||||||
|
const result = await prisma.account.delete({ where: { id } });
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const users_service = {
|
||||||
|
get_all_users_from_db,
|
||||||
|
get_single_users_from_db,
|
||||||
|
create_users_into_db,
|
||||||
|
update_users_into_db,
|
||||||
|
delete_users_from_db,
|
||||||
|
};
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
export const usersSwaggerDocs = {
|
||||||
|
"/api/users": {
|
||||||
|
post: {
|
||||||
|
tags: ["users"],
|
||||||
|
summary: "Create new users",
|
||||||
|
description: "",
|
||||||
|
requestBody: {
|
||||||
|
required: true,
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
example: JSON.stringify({}), // put your request body
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
201: { description: "users created successfully" },
|
||||||
|
500: { description: "Validation error or internal server error" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
get: {
|
||||||
|
tags: ["users"],
|
||||||
|
summary: "Get all users",
|
||||||
|
description: "",
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "page",
|
||||||
|
in: "query",
|
||||||
|
required: false,
|
||||||
|
schema: { type: "number" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "limit",
|
||||||
|
in: "query",
|
||||||
|
required: false,
|
||||||
|
schema: { type: "number" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "search",
|
||||||
|
in: "query",
|
||||||
|
required: false,
|
||||||
|
schema: { type: "string" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
responses: {
|
||||||
|
200: { description: "users fetched successfully" },
|
||||||
|
401: { description: "unauthorized" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"/api/users/{id}": {
|
||||||
|
get: {
|
||||||
|
tags: ["users"],
|
||||||
|
summary: "Get single users",
|
||||||
|
description: "",
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
in: "path",
|
||||||
|
required: true,
|
||||||
|
schema: { type: "string" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
responses: {
|
||||||
|
200: { description: "users fetched successfully" },
|
||||||
|
401: { description: "unauthorized" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
patch: {
|
||||||
|
tags: ["users"],
|
||||||
|
summary: "Update users",
|
||||||
|
description: "",
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
in: "path",
|
||||||
|
required: true,
|
||||||
|
schema: { type: "string" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
requestBody: {
|
||||||
|
required: true,
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
example: JSON.stringify({}), // put your request body
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
200: { description: "users updated successfully" },
|
||||||
|
500: { description: "Validation error or internal server error" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
tags: ["users"],
|
||||||
|
summary: "Delete users",
|
||||||
|
description: "",
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
in: "path",
|
||||||
|
required: true,
|
||||||
|
schema: { type: "string" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
responses: {
|
||||||
|
200: { description: "users delete successfully" },
|
||||||
|
401: { description: "unauthorized" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
const create_users = z.object({});
|
||||||
|
const update_users = z.object({});
|
||||||
|
|
||||||
|
export const users_validations = {
|
||||||
|
create_users,
|
||||||
|
update_users,
|
||||||
|
};
|
||||||
@@ -4,10 +4,14 @@ import orderRoute from "./app/modules/order/order.route.js";
|
|||||||
import planRoute from "./app/modules/plan/plan.route.js";
|
import planRoute from "./app/modules/plan/plan.route.js";
|
||||||
import profileRoute from "./app/modules/profile/profile.route.js";
|
import profileRoute from "./app/modules/profile/profile.route.js";
|
||||||
import supportRoute from "./app/modules/support/support.route.js";
|
import supportRoute from "./app/modules/support/support.route.js";
|
||||||
|
import templateRoute from "./app/modules/template/template.route.js";
|
||||||
|
import usersRoute from "./app/modules/users/users.route.js";
|
||||||
|
|
||||||
const appRouter = Router();
|
const appRouter = Router();
|
||||||
|
|
||||||
const moduleRoutes = [
|
const moduleRoutes = [
|
||||||
|
{ path: "/users", route: usersRoute },
|
||||||
|
{ path: "/template", route: templateRoute },
|
||||||
{ path: "/order", route: orderRoute },
|
{ path: "/order", route: orderRoute },
|
||||||
{ path: "/support", route: supportRoute },
|
{ path: "/support", route: supportRoute },
|
||||||
{ path: "/plan", route: planRoute },
|
{ path: "/plan", route: planRoute },
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import { orderSwaggerDocs } from "./app/modules/order/order.swagger.js";
|
|||||||
import { planSwaggerDocs } from "./app/modules/plan/plan.swagger.js";
|
import { planSwaggerDocs } from "./app/modules/plan/plan.swagger.js";
|
||||||
import { profileSwaggerDocs } from "./app/modules/profile/profile.swagger.js";
|
import { profileSwaggerDocs } from "./app/modules/profile/profile.swagger.js";
|
||||||
import { supportSwaggerDocs } from "./app/modules/support/support.swagger.js";
|
import { supportSwaggerDocs } from "./app/modules/support/support.swagger.js";
|
||||||
|
import { templateSwaggerDocs } from "./app/modules/template/template.swagger.js";
|
||||||
|
import { usersSwaggerDocs } from "./app/modules/users/users.swagger.js";
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
@@ -24,6 +26,8 @@ export const swaggerOptions = {
|
|||||||
...orderSwaggerDocs,
|
...orderSwaggerDocs,
|
||||||
...profileSwaggerDocs,
|
...profileSwaggerDocs,
|
||||||
...supportSwaggerDocs,
|
...supportSwaggerDocs,
|
||||||
|
...templateSwaggerDocs,
|
||||||
|
...usersSwaggerDocs,
|
||||||
},
|
},
|
||||||
servers:
|
servers:
|
||||||
configs.env === "production"
|
configs.env === "production"
|
||||||
|
|||||||
Reference in New Issue
Block a user