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

added check to see if a participant can access a challenge #5

Closed
wants to merge 4 commits into from
Closed
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: 1 addition & 0 deletions app/challenges-platform/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export {
ParticipantsService,
ReviewsService,
SubmissionService,
AccesibleChallengesService,
} from "./services";
import { Transformer } from "./models";
import { transformers } from "../../config/challenges-platform/transformers";
Expand Down
24 changes: 24 additions & 0 deletions app/challenges-platform/services/accesible-challenges-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { accessibleChallenges } from "../../../db/schema";
import { Ok, Result } from "ts-results";
import { eq } from "drizzle-orm";
import { db } from "../../../db";
import { Challenge, Participant } from "../models";

export const count = async (
challenge: Challenge,
participant: Participant,
): Promise<Result<Number, Error>> => {
const accessibleChallengesResult = await db
.select({
pId: accessibleChallenges.participantId,
cId: accessibleChallenges.challengeId,
})
.from(accessibleChallenges)
.where(
eq(accessibleChallenges.participantId, participant.id) &&
eq(accessibleChallenges.challengeId, challenge.id),
)
.execute();

return Ok(accessibleChallengesResult.length);
};
1 change: 1 addition & 0 deletions app/challenges-platform/services/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * as AccesibleChallengesService from "./accesible-challenges-service";
export * as ChallengesService from "./challenges-service";
export * as ParticipantsService from "./participants-service";
export * as ReviewsService from "./reviews-service";
Expand Down
54 changes: 46 additions & 8 deletions app/challenges-platform/services/submissions-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ import { Ok, Err, Result } from "ts-results";
import { db } from "../../../db";
import { submissions } from "../../../db/schema";
import { uuid } from "../../../app/common";
import { Submission } from "../models";
import { ChallengesService, ParticipantsService } from "../services";
import { Challenge, Participant, Submission } from "../models";
import {
AccesibleChallengesService,
ChallengesService,
ParticipantsService,
} from "../services";
import { challengesPlatform } from "..";

export const create = async (
Expand All @@ -12,6 +16,8 @@ export const create = async (
type: string = "base",
metadata?: any,
): Promise<Result<Submission, Error>> => {
const result = await beforeCreate(challengeId, participantId);
if (!result.ok) return result;
const challengeResult = await ChallengesService.findByUuid(challengeId);
if (!challengeResult.ok) {
return Err(new Error("Failed to find challenge"));
Expand All @@ -24,8 +30,7 @@ export const create = async (
return Err(new Error("Failed to find participant"));
}

// TODO: Validate that the participant is allowed to submit this challenge (available challenges)
// throw new Error("Participant is not allowed to submit this challenge") if not allowed (use participant-service)
const [challenge, participant] = result.val;

// TODO: switch on submission.challenge.evaluation
// if submission.challenge.evaluation is MANUAL, than save it to the database
Expand All @@ -46,18 +51,51 @@ export const create = async (
.insert(submissions)
.values({
uuid: id.toString(),
challengeId: challengeResult.val.id,
participantId: participantResult.val.id,
challengeId: challenge.id,
participantId: participant.id,
})
.returning();

const submission = transformer.newSubmission(
result[0],
challengeResult.val,
participantResult.val,
challenge,
participant,
);
return Ok(submission);
} catch (e) {
return Err(new Error("Failed to create submission"));
}
};

// private
const beforeCreate = async (
challengeId: string,
participantId: string,
): Promise<Result<[Challenge, Participant], Error>> => {
const challengeResult = await ChallengesService.findByUuid(challengeId);
if (!challengeResult.ok) {
return Err(new Error("Failed to find challenge"));
}

const participantResult = await ParticipantsService.findByUuid(participantId);
if (!participantResult.ok) {
return Err(new Error("Failed to find participant"));
}

const countResult = await AccesibleChallengesService.count(
challengeResult.val,
participantResult.val,
);
if (!countResult.ok) {
return Err(new Error("Failed to count accessible challenges"));
}

const count = countResult.val;
if (count === 0) {
return Err(
new Error("Participant is not allowed to submit this challenge"),
);
}

return Ok([challengeResult.val, participantResult.val]);
};
8 changes: 8 additions & 0 deletions db/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ export const challenges = sqliteTable("challenges", {
deleted: integer("deleted", { mode: "boolean" }).notNull().default(false),
});

export const accessibleChallenges = sqliteTable("accessible_challenges", {
id: integer("id").primaryKey(),
challengeId: integer("challenge_id").references(() => challenges.id),
participantId: integer("participant_id").references(() => participants.id),
createdAt: text("created_at").default(sql`CURRENT_TIMESTAMP`),
updatedAt: text("updated_at").default(sql`CURRENT_TIMESTAMP`),
});

export const participants = sqliteTable("participants", {
id: integer("id").primaryKey(),
uuid: text("uuid").notNull(),
Expand Down
32 changes: 32 additions & 0 deletions test/challenges-platform/factories/accessible-challenge-factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { challengeFactory } from "./challenge-factory";
import { participantFactory } from "./participant-factory";
import {
Challenge,
Participant,
} from "../../../app/challenges-platform/models";
import { AccesibleChallengesService } from "../../../app/challenges-platform";
import { db } from "../../../db";
import { accessibleChallenges } from "../../../db/schema";

export const accessibleChallengeFactory = async ({
challenge,
participant,
}: {
challenge?: Challenge;
participant?: Participant;
} = {}): Promise<Number> => {
const c = challenge || (await challengeFactory());
const p = participant || (await participantFactory());

const insertResult = await db
.insert(accessibleChallenges)
.values({
challengeId: c.id,
participantId: p.id,
})
.returning();

const result = await AccesibleChallengesService.count(c, p);
if (!result.ok) fail("Expected result to be Ok");
return result.val;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { challengeFactory } from "../factories/challenge-factory";
import { participantFactory } from "../factories/participant-factory";
import { accessibleChallengeFactory } from "../factories/accessible-challenge-factory";
import { AccesibleChallengesService } from "../../../app/challenges-platform";

describe("AccessibleChallengesService", () => {
describe("count", () => {
describe("when the challenge is not accessible", () => {
it("returns 0", async () => {
const challenge = await challengeFactory();
const participant = await participantFactory();

const result = await AccesibleChallengesService.count(challenge, participant);

if (!result.ok) fail("Expected result to be Ok");
expect(result.val).toBe(0);
});
});
describe("when the challenge is accessible", () => {
it("returns 1", async () => {
const challenge = await challengeFactory();
const participant = await participantFactory();

const insert = await accessibleChallengeFactory({
challenge,
participant
});

const result = await AccesibleChallengesService.count(challenge, participant);

if (!result.ok) fail("Expected result to be Ok");
expect(result.val).toBe(1);
});
});
})
});
Loading