Skip to content

Commit

Permalink
Add an endpoint to list tags
Browse files Browse the repository at this point in the history
  • Loading branch information
Dlurak committed Apr 10, 2024
1 parent ed01e45 commit 86e8f9d
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { calendarRouter } from "routes/calendar";
import { classRouter } from "routes/classes";
import { moderationRouter } from "routes/moderation";
import { schoolRouter } from "routes/school";
import { tagRouter } from "routes/tags";
import { deleteUser } from "routes/user/delete";
import { userInfoRouter } from "routes/user/info";
import { changeUserDetailsRouter } from "routes/user/settings";
Expand All @@ -24,6 +25,7 @@ const app = new Elysia()
.use(moderationRouter)
.use(assignmentsRouter)
.use(calendarRouter)
.use(tagRouter)
.get(
"/",
() => ({
Expand Down
94 changes: 94 additions & 0 deletions src/routes/tags/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import e from "@edgedb";
import {
DATABASE_READ_FAILED,
DATABASE_WRITE_FAILED,
UNAUTHORIZED,
} from "constants/responses";
import Elysia, { t } from "elysia";
import { HttpStatusCode } from "elysia-http-status-code";
import { client } from "index";
import { auth } from "plugins/auth";
import { promiseResult } from "utils/errors";
import { responseBuilder } from "utils/response";

export const createTag = new Elysia()
.use(auth)
.use(HttpStatusCode())
.post(
"/",
async ({ set, body, auth, httpStatus }) => {
if (!auth.isAuthorized) {
set.status = httpStatus.HTTP_401_UNAUTHORIZED;
return UNAUTHORIZED;
}

const classQuery = e.select(e.Class, (c) => ({
filter_single: e.op(
e.op(auth.username, "in", c.students.username),
"and",
e.op(c.name, "=", body.class),
),
}));

const tagsQuery = e.select(e.Tag, (t) => ({
filter: e.op(
e.op(e.str_lower(t.tag), "=", body.tag.toLowerCase()),
"and",
e.op(
e.op(t.class.name, "=", body.class),
"and",
e.op(auth.username, "in", t.class.students.username),
),
),
}));

const vaidationlResult = await promiseResult(async () => {
const [classes, tags] = await Promise.all([
e.count(classQuery).run(client),
e.count(tagsQuery).run(client),
]);

return { classes, tags };
});
if (vaidationlResult.isError) {
set.status = httpStatus.HTTP_500_INTERNAL_SERVER_ERROR;
return DATABASE_READ_FAILED;
}
if (vaidationlResult.data.tags > 0) {
set.status = httpStatus.HTTP_400_BAD_REQUEST;
return responseBuilder("error", { error: "This tag already exists" });
}
if (vaidationlResult.data.classes === 0) {
set.status = httpStatus.HTTP_404_NOT_FOUND;
return responseBuilder("error", {
error: "This class doesn't exist or you need to join it",
});
}

const query = e.insert(e.Tag, {
tag: body.tag,
class: classQuery,
color: body.color,
});

const result = await promiseResult(() => query.run(client));

if (result.isError) {
set.status = httpStatus.HTTP_500_INTERNAL_SERVER_ERROR;
return DATABASE_WRITE_FAILED;
}

set.status = httpStatus.HTTP_201_CREATED;
return responseBuilder("success", {
message: "Created a new tag",
data: null,
});
},
{
body: t.Object({
tag: t.String({ minLength: 1 }),
class: t.String({ minLength: 1 }),
color: t.Optional(t.RegExp(/^#[0-9a-f]{3}([0-9a-f]{3})?$/)),
}),
},
);
7 changes: 7 additions & 0 deletions src/routes/tags/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Elysia from "elysia";
import { createTag } from "./create";
import { listTags } from "./list";

export const tagRouter = new Elysia({ prefix: "/tags" })
.use(createTag)
.use(listTags);
54 changes: 54 additions & 0 deletions src/routes/tags/list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import e from "@edgedb";
import { DATABASE_READ_FAILED } from "constants/responses";
import Elysia, { t } from "elysia";
import { HttpStatusCode } from "elysia-http-status-code";
import { client } from "index";
import { promiseResult } from "utils/errors";
import { responseBuilder } from "utils/response";
import { surround } from "utils/strings/surround";

export const listTags = new Elysia().use(HttpStatusCode()).get(
"/",
async ({ set, httpStatus, query }) => {
const dbQuery = e.select(e.Tag, (t) => {
const queryFilter = query.query
? e.op(t.tag, "ilike", surround(query.query, "%"))
: e.bool(true);

const classFilter = e.op(
e.op(t.class.name, "=", query.class),
"and",
e.op(t.class.school.name, "=", query.school),
);

return {
filter: e.op(queryFilter, "and", classFilter),
offset: query.offset,
limit: query.limit === -1 ? undefined : query.limit,

tag: true,
color: true,
};
});

const result = await promiseResult(() => dbQuery.run(client));
if (result.isError) {
set.status = httpStatus.HTTP_500_INTERNAL_SERVER_ERROR;
return DATABASE_READ_FAILED;
}

return responseBuilder("success", {
message: "Successfully retrieved tags",
data: result.data,
});
},
{
query: t.Object({
class: t.String(),
school: t.String(),
query: t.Optional(t.String()),
limit: t.Numeric({ minimum: 0, default: 50 }),
offset: t.Numeric({ minimum: 0, default: 0 }),
}),
},
);

0 comments on commit 86e8f9d

Please sign in to comment.