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
11 changes: 0 additions & 11 deletions backend/src/services/rating-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,17 +235,6 @@ export class RatingService implements IRatingService {
throw new ForbiddenError("Only admitted users may rate projects");
}

// TODO only users in a team are allowed to vote. Prevent them from
// leaving their team to vote for themselves. However, they could leave
// their team and create a new one. So they need to be in a team that has
// been created before the rating started. I don't track the timestamp yet...
// Prevent teams from changing once rating starts is the best bet. Use the
// existing switch and prevent changes, add some text to the settings page that
// this is the case to avoid confusion. Still, people could join a second team
// before voting starts, in order to vote for their own project. I don't think
// it is possible to avoid this situation. It needs to be prohibited via the
// rules and it needs a way to check if this happened, but the ratings are
// anonymous. HOORAY. Or we allow people to rate their own project after all.
if (user.team == null) {
throw new ForbiddenError("You need to be part of a team to vote");
}
Expand Down
11 changes: 11 additions & 0 deletions backend/src/services/team-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,17 @@ export class TeamService implements ITeamService {
);
}

if (user.team != null) {
const oldTeam = await this._teams.findOne({
where: { id: user.team.id },
relations: ["users", "requests", "owner"],
});

if (oldTeam?.owner?.id === user.id) {
throw new Error("Make someone else owner of your other team first");
}
}

await this._users.save({
...user,
teamRequest: team,
Expand Down
17 changes: 17 additions & 0 deletions backend/test/services/team-service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,23 @@ describe("TeamService", () => {
});
});

describe("requestToJoinTeam", () => {
it("throws when the requester is owner of a team", async () => {
expect.assertions(1);

const requestingUser = await userRepo.save(makeUser("req@test.com"));
const createdTeam = await teamService.createTeam(
makeTeam(),
requestingUser,
);
await userRepo.save({ ...requestingUser, team: createdTeam });

await expect(
teamService.requestToJoinTeam(createdTeam.id, requestingUser),
).rejects.toThrow("Make someone else owner of your other team first");
});
});

describe("acceptUserToTeam", () => {
it("throws when the requester is neither owner nor admin", async () => {
expect.assertions(1);
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/base/notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const NotificationContainer = styled(NonGrowingFlexContainer)`
right: -5rem;
opacity: 0;

pointer-events: none;

padding: 0.75rem 1.5rem;

text-transform: uppercase;
Expand Down
17 changes: 16 additions & 1 deletion frontend/src/components/pages/rating-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ interface IRatingFormProps {
project: ProjectDTO;
}

const NOT_RATED = -1;

/**
* Component that allows users to submit and edit ratings for projects.
* Only for one criterion, use multiple of this to cover all of them.
Expand All @@ -32,7 +34,9 @@ export const RatingForm = ({

const { showNotification } = useNotificationContext();

const [ratingValue, setRatingValue] = useState<number>(rating?.rating || 3);
const [ratingValue, setRatingValue] = useState<number>(
rating?.rating || NOT_RATED,
);
const [isSubmitting, setIsSubmitting] = useState(false);

React.useEffect(() => {
Expand All @@ -42,6 +46,10 @@ export const RatingForm = ({
}, [rating]);

const handleSubmit = async () => {
if (ratingValue === NOT_RATED) {
return;
}

setIsSubmitting(true);

await api.createRating({
Expand All @@ -64,6 +72,13 @@ export const RatingForm = ({
value={ratingValue?.toString()}
onChange={(e) => setRatingValue(parseInt(e.target.value, 10))}
>
<FormControlLabel
key="hidden"
value={NOT_RATED.toString()}
control={<Radio disabled={isSubmitting} />}
label=""
style={{ display: "none" }}
/>
{[1, 2, 3, 4, 5].map((value) => (
<FormControlLabel
key={value.toString()}
Expand Down
11 changes: 9 additions & 2 deletions frontend/src/components/pages/read-only-team.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,19 @@ export const ReadOnlyTeam = ({ team }: { team: TeamResponseDTO }) => {

const { forcePerformRequest: sendRequestToJoin } = useApi(
async (apiClient, wasTriggeredManually) => {
if (wasTriggeredManually) {
if (!wasTriggeredManually) {
return false;
}

try {
await apiClient.requestToJoinTeam(Number(params.get("id")));
showNotification("Request sent");
return true;
} catch (error) {
if (error instanceof Error) {
showNotification(error.message);
}
}
return false;
},
[],
);
Expand Down
Loading