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 submissions service find by UUID method #17

Merged
merged 7 commits into from
Jun 22, 2024
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
31 changes: 29 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,39 @@ 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
38 changes: 32 additions & 6 deletions app/challenges-platform/services/participants-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,39 @@ 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);
};

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"));
}

return Ok(challenge);
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 (
Expand Down
110 changes: 92 additions & 18 deletions app/challenges-platform/services/submissions-service.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,70 @@
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 @@ -45,19 +84,54 @@ export const create = async (
const result = await db
.insert(submissions)
.values({
uuid: id,
challengeId: challengeResult.val.id,
participantId: participantResult.val.id,
uuid: id.toString(),
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"));
} else if (challengeResult.val.deleted === true) {
return Err(new Error("Challenge is deleted"));
}

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]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const accessibleChallengeFactory = async ({
}: {
challenge?: Challenge;
participant?: Participant;
} = {}): Promise<any> => {
} = {}): Promise<[Challenge, Participant]> => {
const c = challenge || (await challengeFactory());
const p = participant || (await participantFactory());

Expand All @@ -24,4 +24,6 @@ export const accessibleChallengeFactory = async ({
participantId: p.id,
})
.returning();

return [c, p];
};
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,6 +28,41 @@ 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", () => {
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
Loading
Loading