-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create an endpoint to add calendara events
- Loading branch information
Showing
10 changed files
with
237 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
CREATE MIGRATION m1sty7i6q5winkndbyoecud6k7wkx6cd7hvlg4yx5d3ncwdjlbba3q | ||
ONTO m1k5kk6wjhcyjkqblwsla7tml2hbmfohxsdafccqr45wapyvwfwhva | ||
{ | ||
CREATE TYPE default::Tag { | ||
CREATE REQUIRED LINK class: default::Class; | ||
CREATE PROPERTY color: std::str; | ||
CREATE REQUIRED PROPERTY tag: std::str; | ||
}; | ||
CREATE SCALAR TYPE default::Priority EXTENDING enum<Critical, High, Medium, Low>; | ||
CREATE TYPE default::Calendar { | ||
CREATE REQUIRED LINK class: default::Class { | ||
SET readonly := true; | ||
}; | ||
CREATE MULTI LINK tags: default::Tag; | ||
CREATE MULTI LINK updates: default::Change { | ||
ON SOURCE DELETE DELETE TARGET; | ||
ON TARGET DELETE ALLOW; | ||
}; | ||
CREATE REQUIRED PROPERTY beginning: std::datetime; | ||
CREATE PROPERTY ending: std::datetime; | ||
CREATE PROPERTY location: std::str; | ||
CREATE PROPERTY priority: default::Priority; | ||
CREATE PROPERTY summary: std::str; | ||
CREATE REQUIRED PROPERTY title: std::str; | ||
}; | ||
ALTER TYPE default::Change { | ||
CREATE LINK calendar := (.<updates[IS default::Calendar]); | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import e from "@edgedb"; | ||
import { 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 { isIncreasing } from "utils/arrays/increasing"; | ||
import { promiseResult } from "utils/errors"; | ||
import { classBySchoolAndName } from "utils/queries/class"; | ||
import { responseBuilder } from "utils/response"; | ||
import { savePredicate } from "utils/undefined"; | ||
|
||
export const createCalendar = new Elysia() | ||
.use(HttpStatusCode()) | ||
.use(auth) | ||
.post( | ||
"/", | ||
async ({ body, auth, set, httpStatus }) => { | ||
if (!auth.isAuthorized) { | ||
set.status = httpStatus.HTTP_401_UNAUTHORIZED; | ||
return UNAUTHORIZED; | ||
} | ||
|
||
if (!isIncreasing([body.beginning, body.ending ?? Infinity])) { | ||
set.status = httpStatus.HTTP_422_UNPROCESSABLE_ENTITY; | ||
return responseBuilder("error", { | ||
error: "Ending must be later then beginning" | ||
}) | ||
} | ||
|
||
const isUserInClassQuery = e.count( | ||
e.select(e.Class, (c) => ({ | ||
filter_single: e.op( | ||
e.op( | ||
e.op(c.name, "=", body.class), | ||
"and", | ||
e.op(c.school.name, "=", body.school), | ||
), | ||
"and", | ||
e.op(auth.username, "in", c.students.username), | ||
), | ||
})), | ||
); | ||
|
||
const updateQuery = e.insert(e.Calendar, { | ||
title: body.title, | ||
summary: body.summary, | ||
class: classBySchoolAndName({ | ||
className: body.class, | ||
schoolName: body.school, | ||
}), | ||
beginning: new Date(body.beginning), | ||
ending: savePredicate(body.ending, (ending) => new Date(ending)), | ||
updates: e.insert(e.Change, { | ||
user: e.select(e.User, (u) => ({ | ||
filter_single: e.op(u.username, "=", auth.username), | ||
})), | ||
}), | ||
location: body.location, | ||
priority: body.priority, | ||
}); | ||
|
||
const result = await promiseResult(() => { | ||
return client.transaction(async (tx) => { | ||
const isInClass = await isUserInClassQuery | ||
.run(tx) | ||
.then((c) => c === 1); | ||
if (!isInClass) return "NOT_IN_CLASS"; | ||
|
||
return updateQuery.run(tx); | ||
}); | ||
}); | ||
|
||
if (result.isError) { | ||
set.status = httpStatus.HTTP_500_INTERNAL_SERVER_ERROR; | ||
return DATABASE_WRITE_FAILED; | ||
} | ||
|
||
if (result.data === "NOT_IN_CLASS") { | ||
set.status = httpStatus.HTTP_404_NOT_FOUND; | ||
return responseBuilder("error", { | ||
error: | ||
"This class doesn't exist or you don't have rights to create data for it", | ||
}); | ||
} | ||
|
||
set.status = httpStatus.HTTP_201_CREATED; | ||
return responseBuilder("success", { | ||
message: "Successfully created calendar event", | ||
data: result.data, | ||
}); | ||
}, | ||
{ | ||
body: t.Object({ | ||
title: t.String({ minLength: 1 }), | ||
school: t.String({ minLength: 1 }), | ||
class: t.String({ minLength: 1 }), | ||
beginning: t.Number({ minimum: 0 }), | ||
ending: t.Optional(t.Number({ minimum: 1 })), | ||
summary: t.Optional(t.String({ minLength: 1 })), | ||
location: t.Optional(t.String({ minLength: 1 })), | ||
priority: t.Optional(t.Union([ | ||
t.Literal("Critical"), | ||
t.Literal("High"), | ||
t.Literal("Medium"), | ||
t.Literal("Low"), | ||
])) | ||
}), | ||
}, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import Elysia from "elysia"; | ||
import { createCalendar } from "./create"; | ||
|
||
export const calendarRouter = new Elysia({ prefix: "/calendar" }).use( | ||
createCalendar, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
export const isIncreasing = (arr: number[]): boolean => { | ||
if (arr.length <= 1) return true | ||
|
||
const [first, second] = arr.slice(0, 2) | ||
if (second < first) return false | ||
|
||
return isIncreasing(arr.slice(1)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# EdgeDB Queries | ||
|
||
The functions in this directory should only make it simpler to create queries. | ||
These functions are not supposed to execute those queries. This makes it way | ||
clearer what does what and makes it possible to use these queries in | ||
transactions. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import e from "@edgedb"; | ||
|
||
interface ClassBySchoolAndNameProps { | ||
schoolName: string; | ||
className: string; | ||
} | ||
|
||
export const classBySchoolAndName = ({ | ||
schoolName, | ||
className, | ||
}: ClassBySchoolAndNameProps) => { | ||
return e.select(e.Class, (c) => ({ | ||
filter_single: e.op( | ||
e.op(c.name, "=", className), | ||
"and", | ||
e.op(c.school.name, "=", schoolName), | ||
), | ||
})); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters