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
1 change: 0 additions & 1 deletion backend/src/controllers/application-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,6 @@ export class ApplicationController {
@Authorized(UserRole.User)
public async getAllTeams(): Promise<readonly TeamDTO[]> {
const teams = await this._teams.getAllTeams();
// TODO test member emails not exposed
return teams.map((team) => convertBetweenEntityAndDTO(team, TeamDTO));
}

Expand Down
1 change: 0 additions & 1 deletion backend/src/services/rating-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ export class RatingService implements IRatingService {
projectId: number,
user: User,
): Promise<readonly Rating[]> {
// TODO test
return this._database.getRepository(Rating).find({
where: {
project: {
Expand Down
9 changes: 0 additions & 9 deletions backend/src/services/team-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,10 @@ export class TeamService implements ITeamService {
team.teamImg = placeholder_img[randomIndex];
}

// TODO test
team.owner = user;

const createdTeam = await this._teams.save(team);

// TODO test
user.team = createdTeam;
await this._users.save(user);

Expand Down Expand Up @@ -289,7 +287,6 @@ export class TeamService implements ITeamService {
const isAdmin = requestedBy.role === UserRole.Root;
const isOwner = team.owner?.id === requestedBy.id;
if (!isAdmin && !isOwner) {
// TODO test only admins or owners may accept requests
throw new Error("You are not the owner of this team");
}

Expand Down Expand Up @@ -322,20 +319,17 @@ export class TeamService implements ITeamService {
const isOwner = team.owner?.id === requestedBy.id;
const isAdmin = requestedBy.role === UserRole.Root;
if (!isOwner && !isAdmin && userId !== requestedBy.id) {
// TODO test removing oneself should work
throw new Error("Only the owner may remove other users from a team");
}

if (team.owner?.id === userId) {
// TODO test
throw new Error("Make someone else owner of the team first");
}

if (!team.userIds().includes(userId)) {
throw new Error(`user ${userId} is not part of the team ${teamId}`);
}

// TODO test success
await this._users.update({ id: userId }, { team: null, teamRequest: null });

return Promise.resolve();
Expand All @@ -361,12 +355,10 @@ export class TeamService implements ITeamService {
const isAdmin = requestedBy.role === UserRole.Root;
const isOwner = team.owner?.id === requestedBy.id;
if (!isAdmin && !isOwner) {
// TODO test
throw new Error("Only the owner may change the owner");
}

if (!team.userIds().includes(userId)) {
// TODO test
throw new Error(`User ${userId} is not part of the team ${teamId}`);
}

Expand All @@ -376,7 +368,6 @@ export class TeamService implements ITeamService {
throw new Error(`User ${userId} not found`);
}

// TODO test success
await this._teams.update({ id: teamId }, { owner: newOwner });

return Promise.resolve();
Expand Down
70 changes: 70 additions & 0 deletions backend/test/controllers/application-controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { classToPlain } from "class-transformer";
import { ApplicationController } from "../../src/controllers/application-controller";
import { Team } from "../../src/entities/team";
import { User } from "../../src/entities/user";
import { UserRole } from "../../src/entities/user-role";
import { IApplicationService } from "../../src/services/application-service";
import { ITeamService } from "../../src/services/team-service";
import { IUserService } from "../../src/services/user-service";
import { MockedService } from "../services/mock";
import { MockApplicationService } from "../services/mock/mock-application-service";
import { MockTeamsService } from "../services/mock/mock-teams-service";
import { MockUserService } from "../services/mock/mock-user-service";

describe("ApplicationController", () => {
let applicationService: MockedService<IApplicationService>;
let userService: MockedService<IUserService>;
let teamService: MockedService<ITeamService>;
let controller: ApplicationController;

beforeEach(() => {
applicationService = new MockApplicationService();
userService = new MockUserService();
teamService = new MockTeamsService();
controller = new ApplicationController(
applicationService.instance,
userService.instance,
teamService.instance,
);
});

describe("getAllTeams", () => {
it("does not expose member email addresses", async () => {
expect.assertions(2);

const member = Object.assign(new User(), {
id: 1,
firstName: "Jane",
lastName: "Doe",
email: "jane@example.com",
role: UserRole.User,
password: "",
verifyToken: "",
tokenSecret: "",
forgotPasswordToken: "",
team: null,
teamRequest: null,
});

const mockTeam = Object.assign(new Team(), {
id: 1,
title: "Test Team",
teamImg: "",
description: "A team",
owner: member,
users: [member],
requests: [],
});

teamService.mocks.getAllTeams.mockResolvedValue([mockTeam]);

const teams = await controller.getAllTeams();

// Simulate the ResponseInterceptor which serializes with excludeAll
const serialized = classToPlain(teams, { strategy: "excludeAll" }) as any[];

expect(serialized).toHaveLength(1);
expect(serialized[0].users[0]).not.toHaveProperty("email");
});
});
});
89 changes: 89 additions & 0 deletions backend/test/services/rating-service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,95 @@ describe("RatingService", () => {
await ratingService.bootstrap();
});

describe("getUsersRatingsForProject", () => {
it("returns ratings for the specified project and user", async () => {
expect.assertions(2);

settingsService.mocks.getSettings.mockResolvedValue({
project: { allowRatingProjects: true },
} as any);

const rating = Object.assign(new Rating(), {
project: mockProject,
user: ratingUser,
criterion: mockCriterion,
rating: 4,
});
await ratingService.upsertRating(rating, ratingUser);

const results = await ratingService.getUsersRatingsForProject(
mockProject.id,
ratingUser,
);

expect(results).toHaveLength(1);
expect(results[0].rating).toBe(4);
});

it("returns an empty list when no ratings exist for the project", async () => {
expect.assertions(1);

const results = await ratingService.getUsersRatingsForProject(
mockProject.id,
ratingUser,
);

expect(results).toHaveLength(0);
});

it("does not return ratings belonging to other users", async () => {
expect.assertions(1);

await ratingRepo.save(
Object.assign(new Rating(), {
project: mockProject,
user: teamMember,
criterion: mockCriterion,
rating: 3,
}),
);

const results = await ratingService.getUsersRatingsForProject(
mockProject.id,
ratingUser,
);

expect(results).toHaveLength(0);
});

it("does not return ratings for other projects", async () => {
expect.assertions(1);

settingsService.mocks.getSettings.mockResolvedValue({
project: { allowRatingProjects: true },
} as any);

const otherProject = await projectRepo.save(
Object.assign(new Project(), {
team: mockTeam,
title: "Other Project",
description: "",
allowRating: true,
}),
);

const rating = Object.assign(new Rating(), {
project: otherProject,
user: ratingUser,
criterion: mockCriterion,
rating: 3,
});
await ratingService.upsertRating(rating, ratingUser);

const results = await ratingService.getUsersRatingsForProject(
mockProject.id,
ratingUser,
);

expect(results).toHaveLength(0);
});
});

describe("checkPermission", () => {
describe("via upsertRating", () => {
it("throws ForbiddenError if user is not admitted", async () => {
Expand Down
Loading