Skip to content

Commit dc5b42b

Browse files
authored
Merge pull request #70 from GeneralMagicio/add-optionsTotalVotes-and-totalVotes-to-getPollDetails
Add optionsTotalVotes and totalVotes to getPollDetails
2 parents 0b3d89c + 30dbc89 commit dc5b42b

File tree

6 files changed

+143
-109
lines changed

6 files changed

+143
-109
lines changed

src/auth/auth.controller.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import { Body, Controller, Get, Post, Req, Res } from '@nestjs/common';
2-
import { Response, Request } from 'express';
3-
import { AuthService } from './auth.service';
42
import { MiniAppWalletAuthSuccessPayload } from '@worldcoin/minikit-js';
3+
import { Request, Response } from 'express';
4+
import { handleError } from '../common/helpers';
5+
import { AuthService } from './auth.service';
56

67
interface IRequestPayload {
78
payload: MiniAppWalletAuthSuccessPayload;
89
}
910

11+
type RequestWithCookies = Request & {
12+
cookies: {
13+
siwe?: string;
14+
};
15+
};
16+
1017
function isHttps(req: Request) {
1118
return (
1219
req.protocol === 'https' || req.headers['x-forwarded-proto'] === 'https'
@@ -32,12 +39,12 @@ export class AuthController {
3239

3340
@Post('verifyPayload')
3441
async verifyPayload(
35-
@Req() req: Request,
42+
@Req() req: RequestWithCookies,
3643
@Body() body: IRequestPayload,
3744
@Res() res: Response,
3845
) {
3946
const { payload } = body;
40-
const storedNonce = req.cookies?.siwe;
47+
const storedNonce = req.cookies.siwe;
4148
if (!storedNonce) {
4249
return res.status(400).json({
4350
status: 'error',
@@ -51,11 +58,8 @@ export class AuthController {
5158
storedNonce,
5259
);
5360
return res.status(200).json({ isValid: validMessage });
54-
} catch (error: any) {
55-
console.log('Error verifying payload:', error);
56-
return res
57-
.status(400)
58-
.json({ status: 'error', isValid: false, message: error.message });
61+
} catch (error: unknown) {
62+
return handleError(error);
5963
}
6064
}
6165
}

src/common/helpers.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { InternalServerErrorException } from '@nestjs/common';
2+
3+
export function handleError(error: unknown): never {
4+
const errorMessage =
5+
error instanceof Error ? error.message : 'An unexpected error occurred';
6+
throw new InternalServerErrorException(errorMessage);
7+
}

src/poll/poll.controller.ts

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
11
import {
2+
Body,
23
Controller,
4+
Delete,
35
Get,
4-
Post,
5-
Body,
66
Param,
7-
Req,
7+
Post,
88
Query,
9+
Req,
910
Res,
10-
Delete,
11-
UsePipes,
12-
ValidationPipe,
13-
BadRequestException,
1411
} from '@nestjs/common';
1512
import { Response } from 'express';
16-
import { PollService } from './poll.service';
13+
import { handleError } from '../common/helpers';
1714
import { CreatePollDto, DeletePollDto, GetPollsDto } from './Poll.dto';
15+
import { PollService } from './poll.service';
1816

1917
@Controller('poll')
2018
export class PollController {
2119
constructor(private readonly pollService: PollService) {}
2220

2321
@Post()
24-
@UsePipes(ValidationPipe)
25-
create(@Body() createPollDto: CreatePollDto) {
26-
return this.pollService.createPoll(createPollDto);
22+
async createPoll(@Body() dto: CreatePollDto) {
23+
try {
24+
return await this.pollService.createPoll(dto);
25+
} catch (error: unknown) {
26+
return handleError(error);
27+
}
2728
}
2829

2930
@Get()
30-
@UsePipes(ValidationPipe)
3131
async getPolls(
3232
@Req() req,
3333
@Query() query: GetPollsDto,
@@ -37,9 +37,7 @@ export class PollController {
3737
const polls = await this.pollService.getPolls(query);
3838
return res.status(200).json(polls);
3939
} catch (error: unknown) {
40-
const errorMessage =
41-
error instanceof Error ? error.message : 'An unexpected error occurred';
42-
throw new BadRequestException(errorMessage);
40+
return handleError(error);
4341
}
4442
}
4543

@@ -48,14 +46,8 @@ export class PollController {
4846
try {
4947
const poll = await this.pollService.getPollDetails(Number(id));
5048
return res.status(200).json(poll);
51-
} catch (error) {
52-
if (error.message === 'Poll Id not found') {
53-
return res.status(404).json({ message: error.message });
54-
}
55-
56-
return res
57-
.status(500)
58-
.json({ message: 'Internal server error', error: error.message });
49+
} catch (error: unknown) {
50+
return handleError(error);
5951
}
6052
}
6153

@@ -67,12 +59,9 @@ export class PollController {
6759
) {
6860
try {
6961
const poll = await this.pollService.deletePoll(Number(id), query);
70-
7162
return res.status(200).json({ message: 'Poll deleted', poll: poll });
7263
} catch (error: unknown) {
73-
const errorMessage =
74-
error instanceof Error ? error.message : 'An unexpected error occurred';
75-
throw new BadRequestException(errorMessage);
64+
return handleError(error);
7665
}
7766
}
7867
}

src/poll/poll.service.ts

Lines changed: 62 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { BadRequestException, Injectable } from '@nestjs/common';
2-
import { ActionType, Prisma } from '@prisma/client';
2+
import { ActionType } from '@prisma/client';
33
import { DatabaseService } from 'src/database/database.service';
4+
import {
5+
PollNotFoundException,
6+
UnauthorizedActionException,
7+
UserNotFoundException,
8+
} from '../common/exceptions';
49
import { CreatePollDto, DeletePollDto, GetPollsDto } from './Poll.dto';
510

611
@Injectable()
@@ -12,22 +17,18 @@ export class PollService {
1217
where: { worldID: createPollDto.worldID },
1318
});
1419
if (!user) {
15-
throw new BadRequestException('User does not exist');
20+
throw new UserNotFoundException();
1621
}
1722
const startDate = new Date(createPollDto.startDate);
1823
const endDate = new Date(createPollDto.endDate);
1924
const now = new Date();
20-
2125
if (startDate < now) {
2226
throw new BadRequestException('Start date cannot be in the past');
2327
}
24-
2528
if (endDate <= startDate) {
2629
throw new BadRequestException('End date must be after start date');
2730
}
28-
2931
return this.databaseService.$transaction(async (tx) => {
30-
// Create the poll
3132
const newPoll = await tx.poll.create({
3233
data: {
3334
authorUserId: user.id,
@@ -38,29 +39,28 @@ export class PollService {
3839
endDate,
3940
tags: createPollDto.tags || [],
4041
isAnonymous: createPollDto.isAnonymous || false,
41-
voteResults: {}, // Initialize empty vote results
42+
voteResults: {},
4243
},
4344
});
44-
45-
// Create user action for CREATED
4645
await tx.userAction.create({
4746
data: {
4847
userId: user.id,
4948
pollId: newPoll.pollId,
5049
type: ActionType.CREATED,
5150
},
5251
});
53-
54-
// Update user's pollsCreatedCount
52+
const pollsCreatedCount = await tx.userAction.count({
53+
where: {
54+
userId: user.id,
55+
type: ActionType.CREATED,
56+
},
57+
});
5558
await tx.user.update({
5659
where: { worldID: createPollDto.worldID },
5760
data: {
58-
pollsCreatedCount: {
59-
increment: 1,
60-
},
61+
pollsCreatedCount,
6162
},
6263
});
63-
6464
return newPoll;
6565
});
6666
}
@@ -95,7 +95,7 @@ export class PollService {
9595
});
9696

9797
if (!user) {
98-
throw new Error('User not found');
98+
throw new UserNotFoundException();
9999
}
100100
userId = user.id;
101101
} else if (userCreated || userVoted) {
@@ -154,48 +154,46 @@ export class PollService {
154154
async getPollDetails(id: number) {
155155
const poll = await this.databaseService.poll.findUnique({
156156
where: { pollId: id },
157+
include: {
158+
author: true,
159+
},
157160
});
158161
if (!poll) {
159-
throw new Error('Poll Id not found');
162+
throw new PollNotFoundException();
160163
}
161-
const user = await this.databaseService.user.findUnique({
162-
where: { id: poll?.authorUserId },
163-
});
164164
const now = new Date();
165165
const isActive = now >= poll.startDate && now <= poll.endDate;
166-
167-
return { user, poll, isActive };
166+
const optionsTotalVotes = await this.getPollQuadraticResults(id);
167+
const totalVotes = Object.values(optionsTotalVotes).reduce(
168+
(acc, votes) => acc + votes,
169+
0,
170+
);
171+
return { poll, isActive, optionsTotalVotes, totalVotes };
168172
}
169173

170174
async deletePoll(pollId: number, query: DeletePollDto) {
171175
const user = await this.databaseService.user.findUnique({
172176
where: { worldID: query.worldID },
173177
select: { id: true },
174178
});
175-
176179
if (!user) {
177-
throw new Error('User not found');
180+
throw new UserNotFoundException();
178181
}
179-
180182
const poll = await this.databaseService.poll.findUnique({
181183
where: { pollId },
182184
});
183-
184185
if (!poll) {
185-
throw new Error('Poll not found');
186+
throw new PollNotFoundException();
186187
}
187188
if (poll.authorUserId !== user.id) {
188-
throw new Error('User Not Authorized');
189+
throw new UnauthorizedActionException();
189190
}
190-
191191
return this.databaseService.$transaction(async (tx) => {
192192
const deleted = await tx.poll.delete({
193193
where: {
194194
pollId,
195195
},
196196
});
197-
198-
// Update user's pollsCreatedCount
199197
await tx.user.update({
200198
where: { id: deleted.authorUserId },
201199
data: {
@@ -204,8 +202,40 @@ export class PollService {
204202
},
205203
},
206204
});
207-
208205
return deleted;
209206
});
210207
}
208+
209+
async getPollQuadraticResults(
210+
pollId: number,
211+
): Promise<Record<string, number>> {
212+
const poll = await this.databaseService.poll.findUnique({
213+
where: { pollId },
214+
select: { options: true },
215+
});
216+
if (!poll) {
217+
throw new PollNotFoundException();
218+
}
219+
const votes = await this.databaseService.vote.findMany({
220+
where: { pollId },
221+
select: { quadraticWeights: true },
222+
});
223+
const result: Record<string, number> = poll.options.reduce(
224+
(acc, option) => {
225+
acc[option] = 0;
226+
return acc;
227+
},
228+
{} as Record<string, number>,
229+
);
230+
votes.forEach((vote) => {
231+
if (vote.quadraticWeights) {
232+
Object.entries(vote.quadraticWeights as Record<string, number>).forEach(
233+
([option, weight]) => {
234+
result[option] = (result[option] || 0) + weight;
235+
},
236+
);
237+
}
238+
});
239+
return result;
240+
}
211241
}

0 commit comments

Comments
 (0)