Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/event route refactor #431

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
21 changes: 20 additions & 1 deletion api/controllers/EventController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
GetFutureEventsResponse,
GetAllEventsResponse,
GetPastEventsResponse,
GetFeedbackForEventResponse,
} from '../../types';
import { UuidParam } from '../validators/GenericRequests';
import {
Expand All @@ -27,18 +28,23 @@ import {
CreateEventRequest,
SubmitEventFeedbackRequest,
} from '../validators/EventControllerRequests';
import FeedbackService from '../../services/FeedbackService';

@JsonController('/event')
export class EventController {
private eventService: EventService;

private feedbackService: FeedbackService;

private storageService: StorageService;

private attendanceService: AttendanceService;

constructor(eventService: EventService, storageService: StorageService, attendanceService: AttendanceService) {
constructor(eventService: EventService, storageService: StorageService,
attendanceService: AttendanceService, feedbackService: FeedbackService) {
this.eventService = eventService;
this.storageService = storageService;
this.feedbackService = feedbackService;
this.attendanceService = attendanceService;
}

Expand All @@ -60,6 +66,19 @@ export class EventController {
return { error: null, events };
}

@UseBefore(OptionalUserAuthentication)
@Get('/:uuid/feedback')
async getFeedbackByEvent(@Params() params: UuidParam, @AuthenticatedUser() user: UserModel):
Promise<GetFeedbackForEventResponse> {
const options = {
event: params.uuid,
};
const canSeeAllFeedback = PermissionsService.canSeeAllFeedback(user);

const feedback = await this.feedbackService.getFeedback(canSeeAllFeedback, user, options);
return { error: null, feedback };
}

@UseBefore(UserAuthentication)
@Post('/picture/:uuid')
async updateEventCover(@UploadedFile('image',
Expand Down
16 changes: 9 additions & 7 deletions api/controllers/FeedbackController.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Body, ForbiddenError, Get, JsonController, Params,
Patch, Post, UseBefore, QueryParams } from 'routing-controllers';
Patch, Post, UseBefore } from 'routing-controllers';
import { AuthenticatedUser } from '../decorators/AuthenticatedUser';
import { UserModel } from '../../models/UserModel';
import PermissionsService from '../../services/PermissionsService';
Expand All @@ -10,7 +10,6 @@ import { UserAuthentication } from '../middleware/UserAuthentication';
import {
SubmitFeedbackRequest,
UpdateFeedbackStatusRequest,
FeedbackSearchOptions,
} from '../validators/FeedbackControllerRequests';

@UseBefore(UserAuthentication)
Expand All @@ -22,11 +21,14 @@ export class FeedbackController {
this.feedbackService = feedbackService;
}

@Get()
async getFeedback(@QueryParams() options: FeedbackSearchOptions,
@AuthenticatedUser() user: UserModel): Promise<GetFeedbackResponse> {
const canSeeAllFeedback = PermissionsService.canSeeAllFeedback(user);
const feedback = await this.feedbackService.getFeedback(canSeeAllFeedback, user, options);
@Get('/event/:uuid')
async getEventFeedback(@Params() params: UuidParam, @AuthenticatedUser() user: UserModel):
Promise<GetFeedbackResponse> {
const options = {
user: user.uuid,
event: params.uuid,
};
const feedback = await this.feedbackService.getFeedback(true, user, options);
return { error: null, feedback };
}

Expand Down
8 changes: 4 additions & 4 deletions services/FeedbackService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ export default class FeedbackService {
options: FeedbackSearchOptions): Promise<PublicFeedback[]> {
return this.transactions.readOnly(async (txn) => {
const feedbackRepository = Repositories.feedback(txn);
if (canSeeAllFeedback) {
return (await feedbackRepository.getAllFeedback(options))
.map((fb) => fb.getPublicFeedback());

if (!canSeeAllFeedback) {
throw new UserError('Incorrect permissions to view event feedback');
}

const userFeedback = await feedbackRepository.getStandardUserFeedback(user, options);
const userFeedback = await feedbackRepository.getAllFeedback(options);
return userFeedback.map((fb) => fb.getPublicFeedback());
});
}
Expand Down
3 changes: 2 additions & 1 deletion tests/controllers/ControllerFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ export class ControllerFactory {
const eventService = new EventService(conn.manager);
const storageService = new StorageService();
const attendanceService = new AttendanceService(conn.manager);
return new EventController(eventService, storageService, attendanceService);
const feedbackService = new FeedbackService(conn.manager);
return new EventController(eventService, storageService, attendanceService, feedbackService);
}

public static leaderboard(conn: Connection): LeaderboardController {
Expand Down
97 changes: 96 additions & 1 deletion tests/event.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import * as moment from 'moment';
import { ForbiddenError } from 'routing-controllers';
import { UserAccessType } from '../types';
import { FeedbackStatus, UserAccessType } from '../types';
import { ControllerFactory } from './controllers';
import { DatabaseConnection, EventFactory, PortalState, UserFactory } from './data';
import { CreateEventRequest } from '../api/validators/EventControllerRequests';
import { EventModel } from '../models/EventModel';
import { FeedbackFactory } from './data/FeedbackFactory';

function buildFeedbackRequest(feedback) {
return {
feedback: {
event: feedback.event.uuid,
source: feedback.source,
status: feedback.status,
type: feedback.type,
description: feedback.description,
},
};
}

beforeAll(async () => {
await DatabaseConnection.connect();
Expand Down Expand Up @@ -175,4 +188,86 @@ describe('event deletion', () => {

expect(repositoryEvent).toEqual(event);
});

test('admin can view all feedback for any event', async () => {
// setting up inputs
const conn = await DatabaseConnection.get();
const admin = UserFactory.fake({ accessType: UserAccessType.ADMIN });
const [member1, member2] = UserFactory.create(2);
const event1 = EventFactory.fake();
const event2 = EventFactory.fake();
const feedback1 = FeedbackFactory.fake({ event: event1, user: member1 });
const feedback2 = FeedbackFactory.fake({ event: event1, user: member2 });
const feedback3 = FeedbackFactory.fake({ event: event2, user: member1 });

await new PortalState()
.createUsers(admin, member1, member2)
.createEvents(event1, event2)
.write();

const eventController = ControllerFactory.event(conn);
const feedbackController = ControllerFactory.feedback(conn);
await feedbackController.submitFeedback(buildFeedbackRequest(feedback1), member1);
await feedbackController.submitFeedback(buildFeedbackRequest(feedback2), member2);
await feedbackController.submitFeedback(buildFeedbackRequest(feedback3), member1);

const event1Feedback = await eventController.getFeedbackByEvent({ uuid: event1.uuid }, admin);
const event2Feedback = await eventController.getFeedbackByEvent({ uuid: event2.uuid }, admin);
const event1Sorted = event1Feedback.feedback.sort();

expect(event1Feedback.feedback).toHaveLength(2);
expect(event2Feedback.feedback).toHaveLength(1);

expect(event2Feedback.feedback[0]).toMatchObject({
...event2Feedback.feedback[0],
user: member1.getPublicProfile(),
event: event2.getPublicEvent(),
source: feedback3.source,
description: feedback3.description,
status: FeedbackStatus.SUBMITTED,
type: feedback3.type,
});

expect(event1Sorted[1]).toMatchObject({
...event1Sorted[1],
user: member1.getPublicProfile(),
event: event1.getPublicEvent(),
source: feedback1.source,
description: feedback1.description,
status: FeedbackStatus.SUBMITTED,
type: feedback1.type,
});

expect(event1Sorted[0]).toMatchObject({
...event1Sorted[0],
user: member2.getPublicProfile(),
event: event1.getPublicEvent(),
source: feedback2.source,
description: feedback2.description,
status: FeedbackStatus.SUBMITTED,
type: feedback2.type,
});
});

test('members cannot view all feedback for event', async () => {
// setting up inputs
const conn = await DatabaseConnection.get();
const [member1, member2] = UserFactory.create(2);
const event1 = EventFactory.fake();
const feedback1 = FeedbackFactory.fake({ event: event1, user: member1 });

await new PortalState()
.createUsers(member1, member2)
.createEvents(event1)
.write();

const eventController = ControllerFactory.event(conn);
const feedbackController = ControllerFactory.feedback(conn);
await feedbackController.submitFeedback(buildFeedbackRequest(feedback1), member1);

const errorMessage = 'Incorrect permissions to view event feedback';

await expect(eventController.getFeedbackByEvent({ uuid: event1.uuid }, member1))
.rejects.toThrow(errorMessage);
});
});
Loading
Loading