Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ RUN npm install

COPY . .

RUN npm run db:generate
RUN npx prisma generate
RUN npx prisma migrate deploy

RUN npm run build

COPY entrypoint.sh /entrypoint.sh
Expand Down
11 changes: 3 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,15 @@

- delete the "graphql" dependency from the package.json
- npm install
- npm install graphql

- npm run db:migrate // migrating all prisma model
- npx prisam migrate reset // reset all prisma model
- npm run db:generate // generate all models in postgress-db
- npm run db:studio // open database locally -- optional
- npm run dev // for starting development server


# docker

- build image

`docker build -t myuni-backend`
# run via docker

- run locally
`docker compose up -d`

`docker run -p 8000:8000 myuni-backend`
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"build": "tsc",
"test": "echo \"Error: no test specified\" && exit 1",
"db:generate": "npx prisma generate",
"db:migrate": "npx prisma migrate deploy",
"db:migrate": "npx prisma migrate dev",
"db:push": "npx prisma db push",
"db:studio": "npx prisma studio"
},
Expand Down
62 changes: 62 additions & 0 deletions prisma/migrations/20250827110545_webbuilderschema/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
-- CreateEnum
CREATE TYPE "public"."ArticleCategory" AS ENUM ('ACADEMIC', 'EVENTS', 'FACILITIES', 'NEWS', 'ANNOUNCEMENTS');

-- CreateEnum
CREATE TYPE "public"."ArticleStatus" AS ENUM ('DRAFT', 'PUBLISHED');

-- CreateTable
CREATE TABLE "public"."content_management" (
"id" TEXT NOT NULL,
"title" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"subtitle" TEXT,
"slug" TEXT,
"content" TEXT NOT NULL,
"coverimage" TEXT,
"category" "public"."ArticleCategory" NOT NULL DEFAULT 'NEWS',
"status" "public"."ArticleStatus" NOT NULL DEFAULT 'DRAFT',
"metaTitle" TEXT,
"metaDescription" TEXT,
"keywords" TEXT[],
"focusKeyword" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"publishedAt" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "content_management_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "public"."website" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"slug" TEXT NOT NULL,
"data" JSONB NOT NULL,
"userId" TEXT NOT NULL,
"published" BOOLEAN NOT NULL DEFAULT false,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "website_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "content_management_slug_key" ON "public"."content_management"("slug");

-- CreateIndex
CREATE INDEX "content_management_status_publishedAt_idx" ON "public"."content_management"("status", "publishedAt");

-- CreateIndex
CREATE INDEX "content_management_category_status_idx" ON "public"."content_management"("category", "status");

-- CreateIndex
CREATE INDEX "content_management_userId_idx" ON "public"."content_management"("userId");

-- CreateIndex
CREATE UNIQUE INDEX "website_slug_key" ON "public"."website"("slug");

-- AddForeignKey
ALTER TABLE "public"."content_management" ADD CONSTRAINT "content_management_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."users"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "public"."website" ADD CONSTRAINT "website_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
3 changes: 3 additions & 0 deletions prisma/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
25 changes: 24 additions & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ model User {
AnnouncementData AnnouncementData[] @relation("announcementByUser")
EventsData EventsData[] @relation("eventsByUser")
ContentManagement ContentManagement[] @relation("articleByUser")
websites Website[] @relation("UserWebsite")

@@map("users")
}
Expand Down Expand Up @@ -203,7 +204,7 @@ enum ArticleStatus {
model ContentManagement {
id String @id @default(uuid())
title String
userId String
userId String
subtitle String?
slug String? @unique
content String @db.Text
Expand All @@ -227,3 +228,25 @@ model ContentManagement {
@@index([userId])
@@map("content_management")
}

// ========== restuarant Schema ==========
// ========== Library Schema ==========
// ========== Academic Schema ==========
// ========== Freshman Schema ==========
// ========== Services Schema ==========
// ========== Site Schema ==========
model Website {
id String @id @default(cuid())
name String
slug String @unique
data Json
user User @relation("UserWebsite", fields: [userId], references: [id])
userId String
published Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

@@map("website")
}

// ========== Map Schema ==========
16 changes: 16 additions & 0 deletions src/config/types/web-builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import z from "zod";

export const websiteFields = z.object({
name: z
.string()
.min(3, { message: "name name is required,more than 3 characters" }),
slug: z
.string()
.min(3, { message: "slug are required, more than 3 characters" }),
data: z.any(),
});

export const updateWebsiteField = websiteFields.partial();

type websiteFileds = z.infer<typeof websiteFields>;
type updateWebsiteFileds = z.infer<typeof updateWebsiteField>;
1 change: 1 addition & 0 deletions src/controllers/auth/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ export class AuthController {
const isUserExist = await this.prisma.user.findFirst({
where: { id: userId },
select: {
id: true,
firstname: true,
lastname: true,
address: true,
Expand Down
9 changes: 2 additions & 7 deletions src/controllers/content-management/content-management.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
getCache,
setCache,
} from "../../services/cached/cached-data";
import { uploadToCloudinary } from "../../lib/cloudnary/uploadToCloudinary";

export class Contentmanagement {
prisma = new PrismaClient();
Expand All @@ -24,19 +23,14 @@ export class Contentmanagement {
content,
status,
category,
coverimage,
metaTitle,
metaDescription,
keywords,
focusKeyword,
userId,
} = req.body;

let coverimage: string | null = null;

if (req.file) {
coverimage = await uploadToCloudinary(req.file.buffer, "articles");
}

const createdArticle = await this.prisma.contentManagement.create({
data: {
coverimage,
Expand Down Expand Up @@ -96,6 +90,7 @@ export class Contentmanagement {
},
content: true,
status: true,
publishedAt: true,
category: true,
metaTitle: true,
metaDescription: true,
Expand Down
75 changes: 75 additions & 0 deletions src/controllers/website/web-builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { PrismaClient } from "@prisma/client";
import { NextFunction, Request, Response } from "express";
import {
delCache,
getCache,
setCache,
} from "../../services/cached/cached-data";

export class WebBuilder {
prisma = new PrismaClient();

// save website data
async createWebsite(
req: Request,
res: Response,
next: NextFunction
): Promise<void> {
try {
const { userId, name, slug, data } = req.body;

const saveWebsite = await this.prisma.website.create({
data: {
userId,
name,
slug,
data,
},
});

await setCache(`website:${saveWebsite.id}`, saveWebsite, 3600);
await delCache(`website:${slug}`);

res.status(200).json({ message: "website saved !" });
} catch (error) {
next(error.message);
}
}
// get wbesite data

async getWebsiteData(
req: Request,
res: Response,
next: NextFunction
): Promise<void> {
try {
console.log("hitted");
const { slug } = req.params;

const cachedKey = `website:${slug}`;
const cachedWebsite = await getCache(cachedKey);

if (cachedWebsite) {
res.status(200).json({
message: "webiste data fetched (cache)",
getWebsiteData: cachedWebsite,
});
return;
}

const website = await this.prisma.website.findUnique({
where: { slug },
});

if (!website) {
res.status(404).json({ message: "Website not found" });
return;
}

res.status(200).json(website);
return;
} catch (error) {
next(error.message);
}
}
}
6 changes: 6 additions & 0 deletions src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ import Events from "./events/events";
// content-management
import ContentManagement from "./content-management/content-management";

// website
import websiteBuilder from "./website/web-builder";

const router = Router();

// Grouped by path prefix
Expand Down Expand Up @@ -87,4 +90,7 @@ router.use(Events);
// ----- conetnt-management ---- //
router.use(ContentManagement);

// ----- website ---- //
router.use(websiteBuilder);

export default router;
26 changes: 26 additions & 0 deletions src/routes/website/web-builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import express from "express";
import { check_user_logged_in } from "../../lib/middlewares/check-user-logged-in";
import { userId } from "../../lib/middlewares/use-user-id";
import { isUserVerified } from "../../lib/middlewares/is-user-verified";
import { verifyInputFields } from "../../lib/middlewares/verify-fileds";
import { websiteFields } from "../../config/types/web-builder";
import { WebBuilder } from "../../controllers/website/web-builder";

const router = express.Router();
const websiteControllers = new WebBuilder();

router
.route("/api/v1/create-website")
.post(
check_user_logged_in,
isUserVerified,
verifyInputFields(websiteFields),
userId,
websiteControllers.createWebsite.bind(websiteControllers)
);

router
.route("/api/v1/get-website/:slug")
.get(websiteControllers.getWebsiteData.bind(websiteControllers));

export default router;