Skip to content

Commit

Permalink
Added submissions service findByUuid method
Browse files Browse the repository at this point in the history
  • Loading branch information
AJaccP committed Jun 14, 2024
1 parent bcaf2dd commit 5858d64
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 26 deletions.
34 changes: 32 additions & 2 deletions app/challenges-platform/services/challenges-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,42 @@ export const findByUuid = async (
.from(challenges)
.where(eq(challenges.uuid, id));

const transformer = challengesPlatform.findTransformer(result[0].type);
const challenge = transformer.newChallenge(result[0]);
if (result.length === 0) {
return Err(new Error("Challenge not found"));
}

const challenge = await convert(result[0]);

return Ok(challenge);
}

export const findById = async (
id: number,
): Promise<Result<Challenge, Error>> => {

const result = await db
.select()
.from(challenges)
.where(eq(challenges.id, id));

if (result.length === 0) {
return Err(new Error("Challenge not found"));
}

const challenge = await convert(result[0]);

return Ok(challenge);
};

export const convert = async (
result: any,
): Promise<Challenge> => {
const transformer = challengesPlatform.findTransformer(result.type);
const challenge = transformer.newChallenge(result);

return challenge;
}

export const create = async ({
title,
body,
Expand Down
43 changes: 36 additions & 7 deletions app/challenges-platform/services/participants-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,43 @@ export const findByUuid = async (
.from(participants)
.where(eq(participants.uuid, id));

const challenge = new Participant({
id: result[0].id,
uuid: result[0].uuid,
email: result[0].email,
});
if (result.length === 0) {
return Err(new Error("Participant not found"));
}

const participant = await convert(result[0]);

return Ok(participant);
}

return Ok(challenge);
};
export const findById = async (
id: number,
): Promise<Result<Participant, Error>> => {

const result = await db
.select()
.from(participants)
.where(eq(participants.id, id));

if (result.length === 0) {
return Err(new Error("Participant not found"));
}

const participant = await convert(result[0]);

return Ok(participant);
}

export const convert = async (
result: any,
): Promise<Participant> => {
const participant = new Participant({
id: result.id,
uuid: result.uuid,
email: result.email,
});
return participant;
}

export const findByEmail = async (
email?: string,
Expand Down
100 changes: 83 additions & 17 deletions app/challenges-platform/services/submissions-service.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,64 @@
import { eq } from "drizzle-orm";
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 {
AccessibleChallengesService,
ChallengesService,
ParticipantsService,
} from "../services";
import { challengesPlatform } from "..";

export const create = async (
challengeId: string,
participantId: string,
export const findByUuid = async (
id: string,
type: string = "base",
metadata?: any,
): Promise<Result<Submission, Error>> => {
const challengeResult = await ChallengesService.findByUuid(challengeId);
if (!uuid.isValid(id)) {
return Err(new Error("Invalid UUID"));
}

const result = await db
.select()
.from(submissions)
.where(eq(submissions.uuid, id));

if (result.length === 0) {
return Err(new Error("Submission not found"));
}

const record = result[0];
if (!record.challengeId || !record.participantId) {
return Err(new Error("Invalid submission"));
}

const challengeResult = await ChallengesService.findById(record.challengeId);
if (!challengeResult.ok) {
return Err(new Error("Failed to find challenge"));
}
if (challengeResult.val.deleted === true) {
return Err(new Error("Challenge is deleted"));
}
const participantResult = await ParticipantsService.findByUuid(participantId);

const participantResult = await ParticipantsService.findById(record.participantId);
if (!participantResult.ok) {
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 transformer = challengesPlatform.findTransformer(type);
const submission = transformer.newSubmission(result[0], challengeResult.val, participantResult.val);

return Ok(submission);
}

export const create = async (
challengeId: string,
participantId: string,
type: string = "base",
metadata?: any,
): Promise<Result<Submission, Error>> => {
const result = await beforeCreate(challengeId, participantId);
if (!result.ok) return result;

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 +79,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 AccessibleChallengesService.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]);
};
37 changes: 37 additions & 0 deletions test/challenges-platform/services/challenges-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { ChallengesService } from "../../../app/challenges-platform";
import { challengeFactory } from "../factories/challenge-factory";
import { CustomTransformer, CustomChallenge } from "../custom-transformer";
import { challengesPlatform } from "../../../app/challenges-platform";
import { desc } from "drizzle-orm";
import { uuid } from "../../../app/common";

describe("ChallengesService", () => {
describe("findByUuid", () => {
Expand All @@ -26,8 +28,43 @@ describe("ChallengesService", () => {
expect(result.val.points).toBe(100);
});
});

describe("when there is no record", () => {
it("returns an error", async () => {
const testUuid = uuid.create();
const result = await ChallengesService.findByUuid(testUuid);

expect(result.err).toBe(true);
expect(result.val.toString()).toBe("Error: Challenge not found");
});
});
});

describe("findById", () => {
describe("when there is an existing record", () => {
it("returns the challenge", async () => {
const challenge = await challengeFactory();

const result = await ChallengesService.findById(challenge.id);

if (!result.ok) fail("Expected result to be Ok");
expect(result.val.title).toBe("Test Challenge");
expect(result.val.body).toBe("This is a test challenge");
expect(result.val.points).toBe(100);
});
});

describe("when there is no record", () => {
it("returns an error", async () => {
const testId = -1;
const result = await ChallengesService.findById(testId);

expect(result.err).toBe(true);
expect(result.val.toString()).toBe("Error: Challenge not found");
});
});
});

describe("create", () => {
it("succesfully creates a challenge", async () => {
const title = "Test Challenge";
Expand Down
42 changes: 42 additions & 0 deletions test/challenges-platform/services/participants-service.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ParticipantsService } from "../../../app/challenges-platform";
import { participantFactory } from "../factories/participant-factory";
import { uuid } from "../../../app/common";

describe("ParticipantsService", () => {
describe("create", () => {
Expand All @@ -16,6 +17,15 @@ describe("ParticipantsService", () => {
});

describe("findByUuid", () => {
describe("when the id is invalid", () => {
it("returns an error", async () => {
const result = await ParticipantsService.findByUuid("invalid-id");

expect(result.err).toBe(true);
expect(result.val.toString()).toBe("Error: Invalid UUID");
});
});

describe("when there is an existing record", () => {
it("returns the participant", async () => {
const participant = await participantFactory();
Expand All @@ -25,6 +35,38 @@ describe("ParticipantsService", () => {
expect(result.val.email).toBe(participant.email);
});
});

describe("when there is no record", () => {
it("returns an error", async () => {
const testUuid = uuid.create();
const result = await ParticipantsService.findByUuid(testUuid);

expect(result.err).toBe(true);
expect(result.val.toString()).toBe("Error: Participant not found");
});
});
});

describe("findById", () => {
describe("when there is an existing record", () => {
it("returns the participant", async () => {
const participant = await participantFactory();
const result = await ParticipantsService.findById(participant.id);

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

describe("when there is no record", () => {
it("returns an error", async () => {
const testId = -1;
const result = await ParticipantsService.findById(testId);

expect(result.err).toBe(true);
expect(result.val.toString()).toBe("Error: Participant not found");
});
});
});

describe("findByEmail", () => {
Expand Down
39 changes: 39 additions & 0 deletions test/challenges-platform/services/submissions-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,47 @@ import {
} from "../../../app/challenges-platform";
import { challengeFactory } from "../factories/challenge-factory";
import { participantFactory } from "../factories/participant-factory";
import { uuid } from "../../../app/common";

describe("SubmissionService", () => {
describe("findByUuid", () => {
describe("when the id is invalid", () => {
it("returns an error", async () => {
const result = await SubmissionService.findByUuid("invalid-id");

expect(result.err).toBe(true);
expect(result.val.toString()).toBe("Error: Invalid UUID");
});
});
describe("when there is an existing record", () => {
it("returns the submission", async () => {
const challenge = await challengeFactory();
const participant = await participantFactory();

const submission = await SubmissionService.create(
challenge.uuid,
participant.uuid,
);
if (!submission.ok) fail("Expected submission to be Ok");

const result = await SubmissionService.findByUuid(submission.val.uuid);

if (!result.ok) fail("Expected result to be Ok");
expect(result.val.challenge.id).toBe(challenge.id);
expect(result.val.participant.id).toBe(participant.id);
});
});
describe("when there is no record", () => {
it("returns an error", async () => {
const testUuid = uuid.create();
const result = await SubmissionService.findByUuid(testUuid);

expect(result.err).toBe(true);
expect(result.val.toString()).toBe("Error: Submission not found");
});
});
});

describe("create", () => {
describe("when challenge and participant exist", () => {
it("succesfully creates a submission", async () => {
Expand Down

0 comments on commit 5858d64

Please sign in to comment.