Skip to content

Commit

Permalink
Added door mapper
Browse files Browse the repository at this point in the history
  • Loading branch information
hopperelec committed Jan 21, 2024
1 parent 1799d55 commit f2e10b4
Show file tree
Hide file tree
Showing 14 changed files with 390 additions and 178 deletions.
17 changes: 17 additions & 0 deletions prisma/migrations/20240120175240_add_doors/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-- CreateTable
CREATE TABLE `Door` (
`map_id` INTEGER UNSIGNED NOT NULL,
`room1_id` INTEGER UNSIGNED NOT NULL,
`room2_id` INTEGER UNSIGNED NOT NULL,

PRIMARY KEY (`map_id`, `room1_id`, `room2_id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- AddForeignKey
ALTER TABLE `Door` ADD CONSTRAINT `Door_map_id_fkey` FOREIGN KEY (`map_id`) REFERENCES `Map`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `Door` ADD CONSTRAINT `Door_map_id_room1_id_fkey` FOREIGN KEY (`map_id`, `room1_id`) REFERENCES `Room`(`map_id`, `id`) ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `Door` ADD CONSTRAINT `Door_map_id_room2_id_fkey` FOREIGN KEY (`map_id`, `room2_id`) REFERENCES `Room`(`map_id`, `id`) ON DELETE RESTRICT ON UPDATE CASCADE;
22 changes: 18 additions & 4 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,27 @@ model Map {
img_url String @db.Text
name String?
rooms Room[]
doors Door[]
}

model Room {
id Int @default(autoincrement()) @db.UnsignedInt
map Map @relation(fields: [map_id], references: [id])
map_id Int @db.UnsignedInt
name String?
id Int @default(autoincrement()) @db.UnsignedInt
map Map @relation(fields: [map_id], references: [id])
map_id Int @db.UnsignedInt
name String?
primary_doors Door[] @relation("room1")
secondary_doors Door[] @relation("room2")
@@id([id, map_id])
}

model Door {
map Map @relation(fields: [map_id], references: [id])
room1 Room @relation("room1", fields: [map_id, room1_id], references: [map_id, id])
room2 Room @relation("room2", fields: [map_id, room2_id], references: [map_id, id])
map_id Int @db.UnsignedInt
room1_id Int @db.UnsignedInt
room2_id Int @db.UnsignedInt
@@id([map_id, room1_id, room2_id])
}
32 changes: 12 additions & 20 deletions src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,9 @@ const minification_options: Options = {
};

async function isAuthorized(event: RequestEvent): Promise<boolean> {
if (event.url.pathname.startsWith("/login")) {
return true;
}
if (event.url.pathname.startsWith("/login")) return true;
const sessionUUID = event.cookies.get(SESSION_COOKIE_KEY);
if (!sessionUUID) {
return false;
}
if (!sessionUUID) return false;
const session = await prisma.session.findUnique({
where: {
uuid_bin: toBuffer(sessionUUID),
Expand All @@ -31,21 +27,17 @@ async function isAuthorized(event: RequestEvent): Promise<boolean> {
user: true,
},
});
if (!session) {
throw error(400, "Invalid session UUID");
}
if (new Date() > session.expires) {
return false;
}
if (session.user.allowed) {
event.locals.user = session.user;
if (!session) throw error(400, "Invalid session UUID");
if (new Date() > session.expires) return false;
if (!session.user.allowed)
throw error(
403,
"Currently, only accounts registered with my school are allowed to access Definition Dash",
);
event.locals.user = session.user;
if (!event.url.pathname.startsWith("/teacher") || session.user.is_teacher)
return true;
}

throw error(
403,
"Currently, only accounts registered with my school are allowed to access Definition Dash",
);
throw error(403, "Only teachers can access this page!");
}

export const handle: Handle = async ({ event, resolve }) => {
Expand Down
151 changes: 151 additions & 0 deletions src/lib/SVGMap.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
<script lang="ts">
import { onMount } from "svelte";
import { ICON_SIZE, SVG_NS } from "$lib/constants";
let container: HTMLElement;
let svg: SVGSVGElement;
export function getSVG() {
return svg;
}
export function getElmWhere(
dataName: string,
dataValue: number,
): SVGGraphicsElement | null {
return svg.querySelector(`[data-${dataName}='${dataValue}']`);
}
export function getRoom(id: number): SVGGraphicsElement | null {
return getElmWhere("room", id) as SVGGraphicsElement;
}
export function getLabelsFor(roomId: number): IterableIterator<HTMLElement> | null {
return svg
.querySelectorAll(`[data-label-for='${roomId}']`)
.values() as IterableIterator<HTMLElement>;
}
export function removeIcon(icon: SVGImageElement) {
if (icon.parentElement && icon.parentElement.childElementCount === 1) {
const labels = getLabelsFor(Number(icon.parentElement.dataset.iconFor));
if (labels) {
for (const label of labels) {
label.style.display = "block";
}
}
}
icon.remove();
}
export function getCenterOf(roomId: number) {
const room = getRoom(roomId);
if (!room) return;
const roomBBox = room.getBBox();
let center = new DOMPoint(
roomBBox.x + roomBBox.width / 2,
roomBBox.y + roomBBox.height / 2,
);
const roomCTM = room.getCTM();
const svgCTM = svg.getCTM();
if (roomCTM && svgCTM) {
center = center.matrixTransform(svgCTM.inverse().multiply(roomCTM));
}
return center;
}
export function addIconTo(roomId: number, iconSrc: string) {
const center = getCenterOf(roomId);
if (!center) return;
const labels = getLabelsFor(roomId);
if (labels) {
for (const label of labels) {
label.style.display = "none";
}
}
let iconContainer = getElmWhere("icon-for", roomId);
if (!iconContainer) {
iconContainer = svg.appendChild(document.createElementNS(SVG_NS, "g"));
iconContainer.dataset.iconFor = roomId.toString();
}
const icon = document.createElementNS(SVG_NS, "image");
icon.href.baseVal = iconSrc;
icon.setAttribute("width", ICON_SIZE.toString());
icon.setAttribute("height", ICON_SIZE.toString());
iconContainer.appendChild(icon);
const iconContainerBBox = iconContainer.getBBox();
center.x -= iconContainerBBox.width / 2;
center.y -= iconContainerBBox.height / 2;
iconContainer.setAttribute(
"transform",
`translate(${center.x}, ${center.y})`,
);
return icon;
}
export let mapData: string | undefined;
export let onSuccess = () => {};
export let onError = (message: string) => {
(container || document.body).appendChild(
document.createTextNode("Error: "+message),
);
};
export let onClickRoom: ((clickedRoom: number) => void) | undefined
onMount(() => {
if (mapData) {
const tempMapContainer = document.getElementById("map-container");
if (!tempMapContainer) onError("Failed to get map container");
container = tempMapContainer!;
const tempMapElm = new DOMParser().parseFromString(
mapData,
"image/svg+xml",
).documentElement;
if (tempMapElm instanceof SVGSVGElement) {
svg = container.appendChild(tempMapElm);
svg.addEventListener("click", event => {
if (onClickRoom && event.target instanceof SVGElement) {
let clickedRoom = event.target.dataset.room || event.target.parentElement?.dataset.room;
if (clickedRoom) onClickRoom(+clickedRoom);
}
});
onSuccess();
} else {
onError("Invalid map! Must be SVG.");
}
} else {
onError("Not given any map data");
}
});
</script>

<div id="map-container"></div>

<svelte:head>
<style>
body {
margin: 0;
}
#map-container {
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
[data-room]:hover {
filter: brightness(1.5);
cursor: pointer;
}
[data-label-for],
[data-icon-for] {
pointer-events: none;
}
</style>
</svelte:head>
2 changes: 2 additions & 0 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export const SESSION_COOKIE_KEY = "session";
export const SESSION_DURATION_DAYS = 7;
export const ICON_SIZE = 16;
export const SVG_NS = "http://www.w3.org/2000/svg";
11 changes: 11 additions & 0 deletions src/lib/get-map-for.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import prisma from "$lib/prisma";

export function getMapFor(user: { school_id: number }) {
return prisma.map.findFirst({
where: {
creator: {
school_id: user.school_id,
},
},
});
}
15 changes: 14 additions & 1 deletion src/routes/(app)/+layout.server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import type { LayoutServerLoad } from "./$types";
import type { User } from "@prisma/client";
import { getMapFor } from "$lib/get-map-for";

type props = {
user: User;
map_id?: number;
map?: string;
};
export const load: LayoutServerLoad = async ({ locals }) => {
return {
const data: props = {
user: locals.user,
};
const map = await getMapFor(locals.user);
if (map) {
data.map_id = map.id;
data.map = await (await fetch(map.img_url)).text();
}
return data;
};
18 changes: 0 additions & 18 deletions src/routes/(app)/+page.server.ts

This file was deleted.

Loading

0 comments on commit f2e10b4

Please sign in to comment.