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
2 changes: 0 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,3 @@ jobs:
- name: Run build
run: npm run build

- name: Create certificate
run: npm run generate-ssl
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@ jobs:
sudo docker pull adil56/my-uni-backend:latest
sudo docker stop my-uni-backend || true
sudo docker rm my-uni-backend || true
sudo docker run -d --name my-uni-backend -p 8080:8000 adil56/my-uni-backend:latest
sudo docker run -d --name my-uni-backend -p 8080:8000 --env-file /home/ubuntu/.env.docker adil56/my-uni-backend:latest
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FROM node:20-slim
RUN apt-get update -y && apt-get install -y openssl && rm -rf /var/lib/apt/lists/*

WORKDIR /src

Expand All @@ -7,8 +8,6 @@ RUN npm install

COPY . .

COPY ./src/config/certs ./dist/config/certs

RUN npm run db:generate
RUN npm run build

Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
- delete the "graphql" dependency from the package.json
- npm install
- npm install graphql
- npm run generate-ssl // for generating instance in dist folder
- 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
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"dev": "tsc-watch --onSuccess \"npm start\" ",
"build": "tsc",
"test": "echo \"Error: no test specified\" && exit 1",
"generate-ssl": "mkdir -p dist/config/certs && cp -r src/config/certs/* dist/config/certs/",
"db:generate": "npx prisma generate",
"db:migrate": "npx prisma migrate deploy",
"db:push": "npx prisma db push",
Expand Down
74 changes: 59 additions & 15 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ model User {
createdAt DateTime @default(now())

// Relations
courseData CourseData[] @relation("UserToProgramData")
programData ProgramData[] @relation("programsByUser")
semesterData SemesterData[] @relation("semesterByuser")
DepartmentData DepartmentData[] @relation("UserToDepartmentData")
AnnouncementData AnnouncementData[] @relation("announcementByUser")
EventsData EventsData[] @relation("eventsByUser")
courseData CourseData[] @relation("UserToProgramData")
programData ProgramData[] @relation("programsByUser")
semesterData SemesterData[] @relation("semesterByuser")
DepartmentData DepartmentData[] @relation("UserToDepartmentData")
AnnouncementData AnnouncementData[] @relation("announcementByUser")
EventsData EventsData[] @relation("eventsByUser")
ContentManagement ContentManagement[] @relation("articleByUser")

@@map("users")
}
Expand All @@ -88,12 +89,12 @@ model CourseData {
}

model DepartmentData {
id String @id @default(uuid())
userId String
name String
school String
id String @id @default(uuid())
userId String
name String
school String

head String
head String

established DateTime @db.Date
createdAt DateTime @default(now())
Expand Down Expand Up @@ -122,13 +123,13 @@ model ProgramData {
}

model SemesterData {
id String @id @default(uuid())
id String @id @default(uuid())
userId String
semester String
startdate DateTime @db.Date
enddate DateTime @db.Date
startdate DateTime @db.Date
enddate DateTime @db.Date

courses String
courses String

status SemesterStatus @default(Planning)
createdAt DateTime @default(now())
Expand Down Expand Up @@ -183,3 +184,46 @@ model EventsData {
createdBy User @relation("eventsByUser", fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
createdAt DateTime @default(now())
}

// ======= content-management ======= //

enum ArticleCategory {
ACADEMIC
EVENTS
FACILITIES
NEWS
ANNOUNCEMENTS
}

enum ArticleStatus {
DRAFT
PUBLISHED
}

model ContentManagement {
id String @id @default(uuid())
title String
userId String
subtitle String?
slug String? @unique
content String @db.Text
coverimage String?
category ArticleCategory @default(NEWS)
status ArticleStatus @default(DRAFT)

metaTitle String?
metaDescription String?
keywords String[]
focusKeyword String?

createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
publishedAt DateTime? @default(now())

author User @relation("articleByUser", fields: [userId], references: [id], onDelete: Cascade)

@@index([status, publishedAt])
@@index([category, status])
@@index([userId])
@@map("content_management")
}
32 changes: 32 additions & 0 deletions src/config/types/content-management.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import z from "zod";

export const ContentManagementFileds = z.object({
title: z.string().min(3, { message: "title is required" }),
subtitle: z.string().optional(),
userId: z.string(),
slug: z.string().optional(),
content: z
.string()
.min(10, { message: "Content is required, minimum 10 words" }),
coverimage: z.string().optional(),
status: z.enum(["PUBLISHED", "DRAFT"]),
category: z.enum([
"ACADEMIC",
"EVENTS",
"FACILITIES",
"NEWS",
"ANNOUNCEMENTS",
]),

metaTitle: z.string().optional(),
metaDescription: z.string().optional(),
keywords: z.array(z.string()).optional(),
focusKeyword: z.string().optional(),
});

export const updateContentMenagementField = ContentManagementFileds.partial();

type ContentManagement = z.infer<typeof ContentManagementFileds>;
type updateContentManagement = z.infer<
typeof updateContentMenagementField
>;
2 changes: 1 addition & 1 deletion src/controllers/announcement/announcement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class AnnouncementController {
announcementData,
3600
);
await delCache("announcement:all"); // for removing old cache --
await delCache("announcement:all");

res.status(200).json({ message: "announcement created !" });
return;
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/auth/google/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Strategy as GoogleStrategy } from "passport-google-oauth2";
import { PrismaClient } from "@prisma/client";
import { Request } from "express";
import { WelcomeEmail } from "../../../services/email-service";
import { getCache, setCache } from "../../../services/cached/cached-data";
import { setCache } from "../../../services/cached/cached-data";

const prisma = new PrismaClient();

Expand Down
182 changes: 182 additions & 0 deletions src/controllers/content-management/content-management.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { PrismaClient } from "@prisma/client";
import { NextFunction, Request, Response } from "express";
import {
delCache,
getCache,
setCache,
} from "../../services/cached/cached-data";
import { uploadToCloudinary } from "../../lib/cloudnary/uploadToCloudinary";

export class Contentmanagement {
prisma = new PrismaClient();

// create blog
async createArticle(
req: Request,
res: Response,
next: NextFunction
): Promise<void> {
try {
const {
title,
subtitle,
slug,
content,
status,
category,
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,
title,
subtitle,
slug,
userId,
content,
status,
category,
metaTitle,
metaDescription,
keywords,
focusKeyword,
},
});

await setCache(`article:${createdArticle.id}`, createdArticle, 3600);
await delCache("article:all");

res.status(200).json({ message: "article created !" });
} catch (error) {
next(error.message);
}
}

// read blog
async getAllArticles(
req: Request,
res: Response,
next: NextFunction
): Promise<void> {
try {
const cachedKey = "article:all";
const cachedArticle = await getCache(cachedKey);

if (cachedArticle) {
res.status(200).json({
message: "article fetched (cache)",
AllArticles: cachedArticle,
});
return;
}

const AllArticles = await this.prisma.contentManagement.findMany({
select: {
id: true,
coverimage: true,
title: true,
subtitle: true,
slug: true,
author: {
select: {
firstname: true,
lastname: true,
},
},
content: true,
status: true,
category: true,
metaTitle: true,
metaDescription: true,
keywords: true,
focusKeyword: true,
},
});

if (AllArticles.length > 0) {
res.status(200).json({ message: "Articles Data", AllArticles });
return;
}

res.status(200).json({ message: "Not any articles Data exist to show" });
return;
} catch (error) {
next(error.message);
}
}
// update blog

async updateArticle(
req: Request,
res: Response,
next: NextFunction
): Promise<void> {
try {
const { id } = req.params;
const filedsToUpdate = req.body.data ?? req.body;

const isArticleExist = await this.prisma.contentManagement.findFirst({
where: { id: id },
});

if (!isArticleExist) {
res.status(401).json({ message: "Article not found for update" });
return;
}

const updatedArticles = await this.prisma.contentManagement.update({
where: { id: id },
data: filedsToUpdate,
});

await setCache(`article:${id}`, updatedArticles, 3600);
await delCache("article:all");

res.status(200).json({ message: "article created !", updatedArticles });
return;
} catch (error) {}
}

// delete blog

async deleteArticle(
req: Request,
res: Response,
next: NextFunction
): Promise<void> {
try {
const { id } = req.params;

const isArticleExist = await this.prisma.contentManagement.findFirst({
where: { id: id },
});

if (!isArticleExist) {
res.status(401).json({ message: "article not founce to delete" });
return;
}

await this.prisma.contentManagement.delete({
where: { id: id },
});

await delCache(`article:${id}`);
await delCache("article:all"); // for removing old cache --

res.status(200).json({ message: "article deleted" });
} catch (error) {
next(error.message);
}
}
}
4 changes: 2 additions & 2 deletions src/routes/auth/google-account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ router.get(

const redirectUser =
user.role === "Admin"
? "https://localhost:5174"
: "https://localhost:5173";
? "http://localhost:5174"
: "http://localhost:5173";

req.session.save((err) => {
if (err) {
Expand Down
Loading