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
16 changes: 16 additions & 0 deletions backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,22 @@ model refresh_tokens {
@@schema("auth")
}

/// This model contains row level security and requires additional setup for migrations. Visit https://pris.ly/d/row-level-security for more info.
model local_event {
id String @id(map: "local_events_pkey") @default(uuid()) @db.Uuid
title String
time DateTime? @default(dbgenerated("(now() AT TIME ZONE 'utc'::text)")) @db.Timestamptz(6)
description String
genre String
cost Float? @db.Real
occasion String?
languages String[]
lat Float?
lon Float?

@@schema("public")
}

/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
/// This model contains row level security and requires additional setup for migrations. Visit https://pris.ly/d/row-level-security for more info.
Expand Down
161 changes: 161 additions & 0 deletions backend/src/controllers/local-events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import type { Request, Response } from "express";
import { prisma } from "../services/db.js";

type LocalEvent = {
id: string;
title: string;
time: Date;
description: string;
genre: string;
languages: string[];
occasion: string;
cost: number;
lat: number;
lon: number;
};

export const getLocalEvent = async (req: Request, res: Response) => {
const { id } = req.params;
if (!id) return res.status(400).json({ message: "Event ID is required." });

try {
const event = await prisma.local_event.findUnique({ where: { id } });
if (!event) return res.status(404).json({ message: "Local event not found." });

const data: LocalEvent = {
id: event.id,
title: event.title,
time: event.time,
description: event.description,
genre: event.genre,
languages: event.languages,
occasion: event.occasion,
cost: event.cost,
lat: event.lat,
lon: event.lon,
};

res.status(200).json({ message: "Local event retrieved.", data });
} catch (err) {
res.status(404).json({ message: "Local event not found." });
}
};

export const createLocalEvent = async (req: Request, res: Response) => {
const { title, time, description, genre, languages, cost, occasion, lat, lon } = req.body;

if (
!title ||
!time ||
!description ||
!genre ||
!languages ||
cost == null ||
!occasion ||
lat == null ||
lon == null
) {
return res.status(400).json({ message: "Missing required event fields." });
}

try {
const event = await prisma.local_event.create({
data: {
title,
time: new Date(time),
description,
genre,
languages,
occasion,
cost,
lat,
lon,
},
});

res.status(201).json({
message: "Local event created.",
data: {
id: event.id,
title: event.title,
time: event.time,
description: event.description,
genre: event.genre,
languages: event.languages,
occasion: event.occasion,
cost: event.cost,
lat: event.lat,
lon: event.lon,
},
});
} catch (err) {
res.status(500).json({
message: "Failed to create local event.",
error: err instanceof Error ? err.message : "Unknown error",
});
}
};

export const updateLocalEvent = async (req: Request, res: Response) => {
const { id } = req.params;
const { title, time, description, genre, languages, cost, occasion, lat, lon } = req.body;

if (!id) return res.status(400).json({ message: "Event ID is required." });

try {
const existing = await prisma.local_event.findUnique({ where: { id } });
if (!existing) {
return res.status(404).json({ message: "Local event not found." });
}

const updated = await prisma.local_event.update({
where: { id },
data: {
title: title ?? existing.title,
time: time ? new Date(time) : existing.time,
description: description ?? existing.description,
genre: genre ?? existing.genre,
languages: languages ?? existing.languages,
cost: cost ?? existing.cost,
occasion: occasion ?? existing.occasion,
lat: lat ?? existing.lat,
lon: lon ?? existing.lon,
},
});

res.status(200).json({
message: "Local event updated.",
data: {
id: updated.id,
title: updated.title,
time: updated.time,
description: updated.description,
genre: updated.genre,
languages: updated.languages,
cost: updated.cost,
occasion: updated.occasion,
lat: updated.lat,
lon: updated.lon,
},
});
} catch (err) {
res.status(404).json({ message: "Local event not found." });
}
};

export const deleteLocalEvent = async (req: Request, res: Response) => {
const { id } = req.params;
if (!id) return res.status(400).json({ message: "Event ID is required." });

try {
const existing = await prisma.local_event.findUnique({ where: { id } });
if (!existing) {
return res.status(404).json({ message: "Local event not found." });
}

await prisma.local_event.delete({ where: { id } });
res.status(200).json({ message: "Local event deleted successfully." });
} catch (err) {
res.status(404).json({ message: "Local event not found." });
}
};
106 changes: 106 additions & 0 deletions backend/src/docs/swagger-output.json
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,112 @@
}
}
}
},
"/local-event/{id}": {
"get": {
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "OK"
},
"400": {
"description": "Bad Request"
},
"404": {
"description": "Not Found"
},
"500": {
"description": "Internal Server Error"
}
}
},
"delete": {
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "OK"
},
"400": {
"description": "Bad Request"
},
"404": {
"description": "Not Found"
},
"500": {
"description": "Internal Server Error"
}
}
}
},
"/local-event": {
"post": {
"description": "",
"parameters": [
{
"name": "body",
"in": "body",
"schema": {
"type": "object",
"properties": {
"title": {
"example": "any"
},
"time": {
"example": "any"
},
"description": {
"example": "any"
},
"genre": {
"example": "any"
},
"languages": {
"example": "any"
},
"cost": {
"example": "any"
},
"occasion": {
"example": "any"
},
"lat": {
"example": "any"
},
"lon": {
"example": "any"
}
}
}
}
],
"responses": {
"201": {
"description": "Created"
},
"400": {
"description": "Bad Request"
},
"500": {
"description": "Internal Server Error"
}
}
}
}
}
}
8 changes: 8 additions & 0 deletions backend/src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import {
import { deleteUserProfile, ensureUserProfile, getUserComments, getUserProfile, getUserRatings, updateUserProfile } from '../controllers/user';
import { authenticateUser } from '../middleware/auth';
import { protect } from "../controllers/protected";
import { getLocalEvent, createLocalEvent, updateLocalEvent, deleteLocalEvent } from "../controllers/local-events"
import { followUser, unfollowUser, getFollowers, getFollowing } from "../controllers/userFollows";


const router = Router();

router.get("/api/ping", ping);
Expand Down Expand Up @@ -43,4 +45,10 @@ router.get("/movies/cinecircle/:movieId", getMovieById);
router.put("/movies/cinecircle/:movieId", updateMovie);
router.delete("/movies/:movieId", deleteMovie);

// Local events routes
router.get("/api/local-event/:id", getLocalEvent);
router.post("/api/local-event", createLocalEvent);
router.delete("/api/local-event/:id", deleteLocalEvent);
router.put("/api/local-event/:id", updateLocalEvent);

export default router;
Loading