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
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ CREATE TABLE "Guest" (
"name" TEXT NOT NULL,
"key" TEXT NOT NULL,
"eventId" TEXT,
"pollId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"deletedAt" TIMESTAMP(3),
Expand Down Expand Up @@ -154,9 +153,6 @@ ALTER TABLE "WhitelistUser" ADD CONSTRAINT "WhitelistUser_pollId_fkey" FOREIGN K
-- AddForeignKey
ALTER TABLE "Guest" ADD CONSTRAINT "Guest_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "Event"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Guest" ADD CONSTRAINT "Guest_pollId_fkey" FOREIGN KEY ("pollId") REFERENCES "Poll"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "VoteRestriction" ADD CONSTRAINT "VoteRestriction_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

Expand Down
3 changes: 0 additions & 3 deletions backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ model Poll {
options Option[]
whitelist WhitelistUser[]
votes Vote[]
guestVotes Guest[]
voteRestrict VoteRestriction[]

createdAt DateTime @default(now())
Expand Down Expand Up @@ -112,8 +111,6 @@ model Guest {
key String
eventId String?
event Event? @relation(fields: [eventId], references: [id], onDelete: Cascade)
pollId String?
poll Poll? @relation(fields: [pollId], references: [id], onDelete: Cascade)

votes Vote[]
guestVotes VoteRestriction[]
Expand Down
128 changes: 128 additions & 0 deletions backend/src/controllers/poll.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export class PollController {
constructor(private pollService: PollService) {
this.getPoll = this.getPoll.bind(this);
this.getPolls = this.getPolls.bind(this);
this.myPolls = this.myPolls.bind(this);
this.publicPolls = this.publicPolls.bind(this);
this.myVotedPolls = this.myVotedPolls.bind(this);
}

/**
Expand Down Expand Up @@ -55,6 +58,110 @@ export class PollController {
}
}


/**
* Get all polls user has participated in
* @param req - Request
* @param res - Response
* @param next - NextFunction
* @returns - JSON
*/
public async myPolls(req: Request, res: Response, next: NextFunction): Promise<any> {
try {
const user = req.user

// Check if user exists
if (!user) {
return res.status(400).json({
success: false,
message: "User not found",
error: "User not found"
});
}

// Fetch polls
const polls = await this.pollService.myPolls(user.id, user.guest);

res.status(200).json({
message: "Polls fetched successfully",
data: polls
});

} catch (error) {
return res.status(500).json({
success: false,
message: "Failed to fetch polls",
error: error
});
}
}

/**
* Get all polls user has voted ins
* @param req - Request
* @param res - Response
* @param next - NextFunction
* @returns - JSON
*/

public async myVotedPolls(req: Request, res: Response, next: NextFunction): Promise<any> {
try {
const user = req.user

// Check if user exists
if (!user) {
return res.status(400).json({
success: false,
message: "User not found",
error: "User not found"
});
}

// Fetch polls
const polls = await this.pollService.myVotedPolls(user.id, user.guest);

res.status(200).json({
message: "Polls fetched successfully",
data: polls
});

} catch (error) {
return res.status(500).json({
success: false,
message: "Failed to fetch polls",
error: error
});
}
}

public async publicPolls(req: Request, res: Response, next: NextFunction): Promise<any> {
try {

const page = Number(req.query.page) || 1;
const pageSize = Number(req.query.pageSize) || 10;
const search = req.query.search as string;
const logs = req.query.logs === "true";

const polls = await this.pollService.publicPolls(
page,
pageSize,
search,
logs
);

res.status(200).json({
message: "Polls fetched successfully",
data: { polls }
});
} catch (error) {
return res.status(500).json({
success: false,
message: "Failed to fetch polls",
error: error
});
}
}

/**
* Get a poll by ID
* @param req - Request
Expand All @@ -67,6 +174,27 @@ export class PollController {
try {

const { pollId } = req.params;
const user = req.user;

if (!user) {
return res.status(400).json({
success: false,
message: "User not found",
error: "User not found"
});
}

// Check if user or guest can vote on poll
const canGetPoll = await this.pollService.userCanVote(pollId, user.id, user.guest);

// If user cannot vote on poll
if (!canGetPoll) {
return res.status(403).json({
success: false,
message: "You cannot vote on this poll",
error: "You cannot vote on this poll"
});
}

const polls = await this.pollService.getPoll(pollId);

Expand Down
7 changes: 4 additions & 3 deletions backend/src/middlewares/auth.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,10 @@ class AuthMiddleware {
const isValidGuest = this.cryptoService.verifyAccessTokenGuest(token, envConfig.app.serviceName);
if (!isValidGuest) return null;

let user = await cacheService.get<UserEx>(`guest:${decode.id}`);
let user = await cacheService.get<UserEx>(`guest:${decode.sub}`);

if (!user) {
const userDatabase = await this.userService.getGuestUserById(decode.id);
const userDatabase = await this.userService.getGuestUserById(decode.sub);
if (!userDatabase) return null;

user = {
Expand All @@ -109,7 +110,7 @@ class AuthMiddleware {
dataLogs: Array.isArray(userDatabase.dataLogs) ? (userDatabase.dataLogs as unknown as DataLog[]) : [],
};

await cacheService.set(`guest:${decode.id}`, user, 600);
await cacheService.set(`guest:${decode.sub}`, user, 600);
}

return { ...user, guest: true };
Expand Down
22 changes: 20 additions & 2 deletions backend/src/routes/poll.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { PollService } from "../services/poll.service";
import { PollController } from "../controllers/poll.controller";
import { getAllPollValidator, getPollByIdValidator } from "../utils/validators/poll.util";
import { validateRequest } from "../middlewares/validate.middleware";
import { UserService } from "../services/user.service";
import { AuthService } from "../services/auth.service";
import { CryptoService } from "../services/crypto.service";
import AuthMiddleware from "../middlewares/auth.middleware";

const router = Router();

Expand All @@ -13,9 +17,23 @@ const pollService = new PollService(prisma)

const pollController = new PollController(pollService);

const userService = new UserService(
prisma
);

router.get('/', getAllPollValidator(), validateRequest, pollController.getPolls);
router.get('/:pollId', getPollByIdValidator(), pollController.getPoll);
const authService = new AuthService();
const cryptoService = new CryptoService();

const authMiddleware = new AuthMiddleware(
userService,
cryptoService,
authService
)

router.get('/my-polls', authMiddleware.validateMulti, pollController.myPolls);
router.get('/public-polls', authMiddleware.validateMulti, pollController.publicPolls);
router.get('/my-voted-polls', authMiddleware.validateMulti, pollController.myVotedPolls);
router.get('/:pollId', getPollByIdValidator(), authMiddleware.validateMulti, pollController.getPoll);

export {
router as pollRouters
Expand Down
Loading