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

Get another user's event attendance #358

Merged
merged 32 commits into from
Dec 31, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
01be057
attendences from user uuid
maxwn04 Jul 20, 2023
2709f01
lint and bugfix
maxwn04 Jul 21, 2023
f77a18f
check same user
maxwn04 Jul 22, 2023
fec0bfe
controller factory changes
maxwn04 Jul 22, 2023
a02c023
lint fixes
maxwn04 Jul 25, 2023
7a53b80
unit test for get attendance by uuid
maxwn04 Jul 25, 2023
016cd72
lint
maxwn04 Jul 25, 2023
2ef8327
add permision
maxwn04 Aug 8, 2023
420842e
add types
maxwn04 Aug 8, 2023
f04a0c2
add everything else
maxwn04 Aug 8, 2023
21e5e22
rename migrtion
maxwn04 Aug 8, 2023
637db14
test when permision is off
maxwn04 Aug 9, 2023
bb34bab
lint
maxwn04 Aug 9, 2023
3aee217
forgor to add
maxwn04 Aug 9, 2023
060239b
change permission name and fix logic a bit
maxwn04 Aug 17, 2023
926aeb9
Merge branch 'Max/get-user-past-attendance' of https://github.com/acm…
maxwn04 Sep 1, 2023
13fbde5
rename permission, change patch user
maxwn04 Sep 1, 2023
6215f80
lint fix
maxwn04 Sep 1, 2023
ea21537
lint fix
maxwn04 Sep 1, 2023
6fcb46d
oops
maxwn04 Sep 1, 2023
a02f96e
check user exists
maxwn04 Nov 15, 2023
edd7946
lint
maxwn04 Nov 15, 2023
77b0166
rename tests
maxwn04 Nov 28, 2023
7fef0c4
Merge branch 'Max/get-user-past-attendance' of https://github.com/acm…
maxwn04 Nov 28, 2023
1cafea3
public profile change
maxwn04 Dec 27, 2023
afdf12d
change user model
maxwn04 Dec 27, 2023
8e87061
lint
maxwn04 Dec 27, 2023
2cf55f4
tests
maxwn04 Dec 27, 2023
9e62597
lint
maxwn04 Dec 27, 2023
43b87d7
Merge branch 'master' of https://github.com/acmucsd/membership-portal…
nik-dange Dec 31, 2023
16d789f
Merge branch 'Max/get-user-past-attendance' of https://github.com/acm…
nik-dange Dec 31, 2023
86ba025
updated api version
nik-dange Dec 31, 2023
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
12 changes: 11 additions & 1 deletion api/controllers/AttendanceController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,17 @@ export class AttendanceController {

@Get()
async getAttendancesForCurrentUser(@AuthenticatedUser() user: UserModel): Promise<GetAttendancesForUserResponse> {
const attendances = await this.attendanceService.getAttendancesForUser(user);
const attendances = await this.attendanceService.getAttendancesForCurrentUser(user);
return { error: null, attendances };
}

@Get('/user/:uuid')
async getAttendancesForUser(@Params() params: UuidParam,
@AuthenticatedUser() currentUser: UserModel): Promise<GetAttendancesForEventResponse> {
if (params.uuid === currentUser.uuid) {
return this.getAttendancesForCurrentUser(currentUser);
}
const attendances = await this.attendanceService.getAttendancesForUser(params.uuid);
return { error: null, attendances };
}

Expand Down
3 changes: 3 additions & 0 deletions api/validators/UserControllerRequests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ export class UserPatches implements IUserPatches {
@Allow()
bio?: string;

@Allow()
isAttendancePublic?: boolean;

@Type(() => PasswordUpdate)
@ValidateNested()
@HasMatchingPasswords()
Expand Down
17 changes: 17 additions & 0 deletions migrations/0037-add-userAttendancePermission-to-userTable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm';

const TABLE_NAME = 'Users';

export class AddUserAttendancePermissionToUserTable1691286073346 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.addColumn(TABLE_NAME, new TableColumn({
name: 'isAttendancePublic',
type: 'boolean',
default: true,
}));
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn(TABLE_NAME, 'isAttendancePublic');
}
}
3 changes: 3 additions & 0 deletions models/UserModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ export class UserModel extends BaseEntity {
})
bio: string;

@Column('boolean', { default: true })
isAttendancePublic: boolean;

@Column('integer', { default: 0 })
@Index('leaderboard_index')
points: number;
Expand Down
13 changes: 11 additions & 2 deletions services/AttendanceService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Service } from 'typedi';
import { InjectManager } from 'typeorm-typedi-extensions';
import { BadRequestError, NotFoundError } from 'routing-controllers';
import { BadRequestError, ForbiddenError, NotFoundError } from 'routing-controllers';
import { EntityManager } from 'typeorm';
import * as moment from 'moment';
import { ActivityType, PublicAttendance, Uuid } from '../types';
Expand All @@ -27,13 +27,22 @@ export default class AttendanceService {
return attendances.map((attendance) => attendance.getPublicAttendance());
}

public async getAttendancesForUser(user: UserModel): Promise<PublicAttendance[]> {
public async getAttendancesForCurrentUser(user: UserModel): Promise<PublicAttendance[]> {
const attendances = await this.transactions.readOnly(async (txn) => Repositories
.attendance(txn)
.getAttendancesForUser(user));
return attendances.map((attendance) => attendance.getPublicAttendance());
}

public async getAttendancesForUser(uuid: Uuid): Promise<PublicAttendance[]> {
return this.transactions.readOnly(async (txn) => {
const user = await Repositories.user(txn).findByUuid(uuid);
maxwn04 marked this conversation as resolved.
Show resolved Hide resolved
if (!user.isAttendancePublic) throw new ForbiddenError();
const attendances = await Repositories.attendance(txn).getAttendancesForUser(user);
return attendances.map((attendance) => attendance.getPublicAttendance());
});
}

public async attendEvent(user: UserModel, attendanceCode: string, asStaff = false): Promise<PublicAttendance> {
return this.transactions.readWrite(async (txn) => {
const event = await Repositories.event(txn).findByAttendanceCode(attendanceCode);
Expand Down
54 changes: 54 additions & 0 deletions tests/attendance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,58 @@ describe('attendance', () => {
expect(attendance.user.uuid).toEqual(staff.uuid);
expect(attendance.event.uuid).toEqual(event.uuid);
});

test('get user attendance by uuid', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's rename this to 'get another user's attendance by uuid' for clarification

const conn = await DatabaseConnection.get();
const member1 = UserFactory.fake();
const member2 = UserFactory.fake();
const event1 = EventFactory.fake({ requiresStaff: true });
const event2 = EventFactory.fake({ requiresStaff: true });

await new PortalState()
.createUsers(member1, member2)
.createEvents(event1, event2)
.attendEvents([member1], [event1, event2])
.write();

const attendanceController = ControllerFactory.attendance(conn);
const params = { uuid: member1.uuid };

// returns all attendances for uuid
const getAttendancesForUserUuid = await attendanceController.getAttendancesForUser(params, member2);
const attendancesForEvent = getAttendancesForUserUuid.attendances.map((a) => ({
user: a.user.uuid,
event: a.event.uuid,
asStaff: a.asStaff,
}));
const expectedAttendances = [
{ event: event1.uuid, user: member1.uuid, asStaff: false },
{ event: event2.uuid, user: member1.uuid, asStaff: false },
];
expect(attendancesForEvent).toEqual(expect.arrayContaining(expectedAttendances));
});

test('throws error when canSeeAttendanceFalse', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of canSeeAttendanceFalse, let's update the test description to "throws error when isAttendancePublilc is false"

const conn = await DatabaseConnection.get();
const member1 = UserFactory.fake();
const member2 = UserFactory.fake();
const event1 = EventFactory.fake({ requiresStaff: true });
const event2 = EventFactory.fake({ requiresStaff: true });

await new PortalState()
.createUsers(member1, member2)
.createEvents(event1, event2)
.attendEvents([member1, member2], [event1, event2])
.write();

const attendanceController = ControllerFactory.attendance(conn);
const userController = ControllerFactory.user(conn);
const params = { uuid: member1.uuid };

const changePublicAttendancePatch = { user: { isAttendancePublic: false } };
await userController.patchCurrentUser(changePublicAttendancePatch, member1);

await expect(attendanceController.getAttendancesForUser(params, member2))
.rejects.toThrow(ForbiddenError);
});
});
1 change: 1 addition & 0 deletions tests/data/UserFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export class UserFactory {
points: 0,
credits: 0,
handle: UserAccountService.generateDefaultHandle(firstName, lastName),
isAttendancePublic: true,
});
return UserModel.merge(fake, substitute);
}
Expand Down
1 change: 1 addition & 0 deletions types/ApiRequests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export interface UserPatches {
major?: string;
graduationYear?: number;
bio?: string;
isAttendancePublic?: boolean;
passwordChange?: PasswordUpdate;
}

Expand Down
Loading