comment out friends-related stuff

This commit is contained in:
not-nullptr 2024-03-19 15:23:03 +00:00
parent 558fcb16b6
commit 3e017789f3
18 changed files with 671 additions and 67 deletions

View file

@ -6,6 +6,41 @@
import type { PageData } from "../routes/$types";
import cookie from "cookiejs";
interface AnchorItem {
type: "anchor";
name: string;
href: string;
}
interface ButtonItem {
type: "button";
name: string;
action: () => void;
}
interface DividerItem {
type: "divider";
}
type NavItem = AnchorItem | ButtonItem | DividerItem;
export let navItems: NavItem[] = [
{ type: "anchor", name: "Multiplayer", href: "/account" },
{
type: "anchor",
name: "Profile",
href: "https://gravatar.com/profile",
},
{
type: "divider",
},
{
type: "button",
name: "Sign out",
action: signOut,
},
];
export let user: PageData["user"];
const token = getContext<Writable<string>>("token");
@ -24,7 +59,10 @@
open = !open;
}
let jsEnabled = false;
onMount(() => {
jsEnabled = true;
function closeMenu(e: MouseEvent) {
if (e.target instanceof HTMLElement) {
if (!e.target.closest(".user-profile-menu")) {
@ -48,22 +86,47 @@
style="transition: 360ms {transition}"
class={`${open ? "rotate-0 scale-100 opacity-100" : "-rotate-90 scale-0 opacity-0"} absolute right-0 top-full mt-2 flex h-fit origin-top-right transform-gpu flex-col overflow-hidden rounded-[20px] rounded-tr-none border-2 border-solid border-[#ffffff34] bg-[#110d10] p-[2px] opacity-0 shadow-lg shadow-[rgba(0,0,0,0.25)] motion-reduce:transition-none [&>.nav-btn:first-child]:rounded-tl-[16px] [&>.nav-btn:first-child]:rounded-tr-none [&>.nav-btn:last-child]:rounded-bl-[16px] [&>.nav-btn:last-child]:rounded-br-[16px]`}
>
<div
role="button"
class="nav-btn flex items-center whitespace-nowrap hover:bg-[#1d1d1d] [&>*]:w-full [&>*]:px-4 [&>*]:py-2 [&>*]:text-left"
>
<a href="/account">Multiplayer</a>
</div>
<div
role="separator"
class="-ml-[2px] mb-[2px] mt-[2px] h-[2px] w-[calc(100%+4px)] bg-[#423e41]"
/>
<div
role="button"
class="nav-btn flex items-center whitespace-nowrap hover:bg-[#1d1d1d] [&>*]:w-full [&>*]:px-4 [&>*]:py-2 [&>*]:text-left"
>
<button on:click={signOut}>Sign out</button>
</div>
{#if jsEnabled}
<!-- <div
role="button"
class="nav-btn flex items-center whitespace-nowrap hover:bg-[#1d1d1d] [&>*]:w-full [&>*]:px-4 [&>*]:py-2 [&>*]:text-left"
>
<a href="/account">Multiplayer</a>
</div>
<div
role="button"
class="nav-btn flex items-center whitespace-nowrap hover:bg-[#1d1d1d] [&>*]:w-full [&>*]:px-4 [&>*]:py-2 [&>*]:text-left"
></div>
<div
role="separator"
class="-ml-[2px] mb-[2px] mt-[2px] h-[2px] w-[calc(100%+4px)] bg-[#423e41]"
/>
<div
role="button"
class="nav-btn flex items-center whitespace-nowrap hover:bg-[#1d1d1d] [&>*]:w-full [&>*]:px-4 [&>*]:py-2 [&>*]:text-left"
>
<button on:click={signOut}>Sign out</button>
</div> -->
{#each navItems as navItem}
{#if navItem.type === "divider"}
<div
role="separator"
class="-ml-[2px] mb-[2px] mt-[2px] h-[2px] w-[calc(100%+4px)] bg-[#423e41]"
/>
{:else}
<div
role="button"
class="nav-btn flex items-center whitespace-nowrap hover:bg-[#1d1d1d] [&>*]:w-full [&>*]:px-4 [&>*]:py-2 [&>*]:text-left"
>
{#if navItem.type === "anchor"}
<a href={navItem.href}>{navItem.name}</a>
{:else}
<button on:click={navItem.action}>{navItem.name}</button>
{/if}
</div>
{/if}
{/each}
{/if}
</div>
</button>

View file

@ -0,0 +1,58 @@
<script lang="ts">
import type { SuyuUser } from "$lib/server/schema";
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher<{
delete: {};
accept: {};
}>();
export let user: SuyuUser;
export let accepted: boolean;
export let sent: boolean;
</script>
<!-- <div
class="flex items-center gap-2 rounded-[16px] border-2 border-solid border-[#ffffff34] p-1 py-1"
>
<img
src="{user.avatarUrl}&s=24"
alt="{user.username}'s profile picture"
width="24"
height="24"
class="ml-1 rounded-full"
/>
<p class="min-w-0 flex-grow overflow-hidden text-ellipsis whitespace-nowrap">
{user.username}
</p>
{#if !accepted && !sent}
<button class="button-sm h-8" on:click={() => dispatch("accept", {})}>Accept</button>
{/if}
<button class="button-sm h-8" on:click={() => dispatch("delete", {})}
>{sent ? (accepted ? "Delete" : "Cancel") : "Delete"}</button
>
</div> -->
<div
class="flex aspect-[1/1.5] w-full flex-col overflow-hidden rounded-3xl border-2 border-solid border-[#ffffff34] shadow-2xl shadow-black"
>
<div class="flex flex-grow items-center justify-center">
<img
src="{user.avatarUrl}&s=220"
alt="{user.username}'s profile picture"
class="h-full w-full object-cover"
/>
</div>
<div
class="flex h-[33%] w-full flex-shrink-0 flex-col border-t-2 border-t-[#ffffff34] px-3 py-2"
>
<h3 class="flex-grow text-center text-xl">{user.username}</h3>
<div class="mb-[4px] flex justify-around">
{#if !accepted && !sent}
<button class="button-sm" on:click={() => dispatch("accept", {})}>Accept</button>
{/if}
<button class="button-sm" on:click={() => dispatch("delete", {})}
>{sent ? (accepted ? "Delete" : "Cancel") : "Delete"}</button
>
</div>
</div>
</div>

View file

@ -5,6 +5,7 @@ import type { Handle } from "@sveltejs/kit";
import { WebSocketServer } from "ws";
import { userRepo } from "$lib/server/repo";
import { globalData } from "$lib/server/other";
import type { Assets } from "./routes/api/webhooks/release/+server";
let server: WebSocketServer;
@ -39,12 +40,12 @@ async function setupGames() {
const runAllTheInitFunctions = async () => {
if (!db.isInitialized) await db.initialize();
if (!server)
try {
initServer();
} catch {
console.error("Could not initialize WebSocket server");
}
// if (!server)
// try {
// initServer();
// } catch {
// console.error("Could not initialize WebSocket server");
// }
if (globalData.games.length === 0) {
await setupGames();
}

View file

@ -1,9 +1,15 @@
import type {
CreateAccountRequest,
CreateAccountResponse,
DeleteRelationshipRequest,
DeleteRelationshipResponse,
GetNotificationsResponse,
GetRelationshipsResponse,
GetUserResponse,
LoginRequest,
LoginResponse,
SendFriendRequestRequest,
SendFriendRequestResponse,
} from "$types/api";
const apiUsers = {
@ -24,8 +30,30 @@ const apiUsers = {
},
} as const;
const apiNotifications = {
async getNotifications(): Promise<GetNotificationsResponse> {
return await SuyuAPI.req("GET", "/api/notifications");
},
} as const;
const apiFriendship = {
async sendFriendRequest(body: SendFriendRequestRequest): Promise<SendFriendRequestResponse> {
return await SuyuAPI.req("POST", "/api/relationship", body);
},
async getRelationships(): Promise<GetRelationshipsResponse> {
return await SuyuAPI.req("GET", "/api/relationship");
},
async deleteRelationship(body: DeleteRelationshipRequest): Promise<DeleteRelationshipResponse> {
return await SuyuAPI.req("DELETE", "/api/relationship", body);
},
} as const;
export class SuyuAPI {
static users = apiUsers;
static notifications = apiNotifications;
static friendship = apiFriendship;
static async req(method: string, path: string, body?: any) {
const res = await fetch(path, {

View file

@ -1,10 +1,10 @@
import { DataSource } from "typeorm";
import { SuyuUser } from "../schema";
import { Friendship, SuyuUser } from "../schema";
export const db = new DataSource({
type: "better-sqlite3",
database: "db.sqlite",
entities: [SuyuUser],
entities: [SuyuUser, Friendship],
synchronize: true,
subscribers: [],
migrations: [],

View file

@ -1,3 +1,5 @@
import type { Assets } from "../../../routes/api/webhooks/release/+server";
export interface SwitchGame {
bannerUrl: string;
category: string[];
@ -23,6 +25,8 @@ export interface SwitchGame {
size: number;
// version: null;
}
export const globalData: {
games: SwitchGame[];
} = { games: [] };
assets: Assets | null;
} = { games: [], assets: null };

View file

@ -1,5 +1,5 @@
import { db } from "../db";
import { FriendshipRequest, SuyuUser } from "../schema";
import { Friendship, SuyuUser } from "../schema";
export const userRepo = db.getRepository(SuyuUser);
export const friendshipRepo = db.getRepository(FriendshipRequest);
export const friendshipRepo = db.getRepository(Friendship);

View file

@ -1,5 +1,15 @@
import type { Role } from "$types/db";
import { BaseEntity, Column, Entity, ManyToMany, OneToOne, PrimaryGeneratedColumn } from "typeorm";
import {
BaseEntity,
Column,
Entity,
JoinColumn,
ManyToMany,
ManyToOne,
OneToMany,
OneToOne,
PrimaryGeneratedColumn,
} from "typeorm";
@Entity()
export class SuyuUser extends BaseEntity {
@ -33,17 +43,59 @@ export class SuyuUser extends BaseEntity {
})
password: string;
@ManyToMany(() => SuyuUser)
friends: SuyuUser[];
@OneToMany(() => Friendship, (friendship) => friendship.from, {
eager: true,
})
sentFriendRequests: Friendship[];
@OneToMany(() => Friendship, (friendship) => friendship.to, {
eager: true,
})
receivedFriendRequests: Friendship[];
async getFriendRequests() {
return await Friendship.find({
where: {
to: {
id: this.id,
},
accepted: false,
},
loadEagerRelations: true,
relations: ["from", "to"],
});
}
async getFriends() {
const sent = await Friendship.find({
where: {
from: this,
accepted: true,
},
});
const received = await Friendship.find({
where: {
to: this,
accepted: true,
},
});
return sent.map((f) => f.to).concat(received.map((f) => f.from));
}
}
export class FriendshipRequest extends BaseEntity {
@Entity()
export class Friendship extends BaseEntity {
@PrimaryGeneratedColumn("uuid")
id: string;
@OneToOne(() => SuyuUser)
@ManyToOne(() => SuyuUser, (user) => user.sentFriendRequests)
@JoinColumn()
from: SuyuUser;
@OneToOne(() => SuyuUser)
@ManyToOne(() => SuyuUser, (user) => user.receivedFriendRequests)
@JoinColumn()
to: SuyuUser;
@Column("boolean")
accepted: boolean;
}

View file

@ -3,11 +3,12 @@ import type { Role } from "$types/db";
import { PUBLIC_KEY } from "../secrets/secrets.json";
import jwt from "jsonwebtoken";
export function json<T>(body: T): Response {
export function json<T>(body: T, status?: number): Response {
return new Response(JSON.stringify(body), {
headers: {
"content-type": "application/json;charset=UTF-8",
},
status: status || 200,
});
}

View file

@ -5,7 +5,10 @@ import type { IJwtData } from "$types/auth";
import cookie from "cookie";
import jwt from "jsonwebtoken";
export async function useAuth(request: Request | string): Promise<SuyuUser | null> {
export async function useAuth(
request: Request | string,
eager?: boolean,
): Promise<SuyuUser | null> {
const cookies = cookie.parse(
typeof request !== "string" ? request.headers.get("cookie") || "" : "",
);
@ -22,6 +25,8 @@ export async function useAuth(request: Request | string): Promise<SuyuUser | nul
where: {
apiKey: decoded.apiKey,
},
loadEagerRelations: eager || false,
relations: eager ? ["sentFriendRequests", "receivedFriendRequests"] : [],
});
return user;
}
@ -29,6 +34,8 @@ export async function useAuth(request: Request | string): Promise<SuyuUser | nul
where: {
apiKey,
},
loadEagerRelations: eager || false,
relations: eager ? ["sentFriendRequests", "receivedFriendRequests"] : [],
});
return user;
}

View file

@ -149,10 +149,28 @@
name: "GitLab",
href: "https://gitlab.com/suyu-emu/suyu",
},
{
name: $token || data.tokenCookie ? "Account" : "Sign up",
href: $token || data.tokenCookie ? "/account" : "/signup",
},
// {
// name: $token || data.tokenCookie ? "Account" : "Sign up",
// href: $token || data.tokenCookie ? "/account" : "/signup",
// },
$token || data.tokenCookie
? {
name: "Account",
href: "/account",
}
: {
name: "Sign up",
href: "/signup",
},
$token || data.tokenCookie
? {
name: "Log out",
href: "/logout",
}
: {
name: "Log in",
href: "/login",
},
] as NavItem[];
$: {
@ -227,13 +245,15 @@
</div>
{/if}
<div
style="background: radial-gradient(50% 50%, rgba(255,0,0,0.05), transparent); z-index: -1; width: 800px ;height: 800px; position: fixed; top: -50%; left: calc(25% - 400px);"
/>
<div class="bg">
<div
style="background: radial-gradient(50% 50%, rgba(255,0,0,0.05), transparent); z-index: -1; width: 800px ;height: 800px; position: fixed; top: -50%; left: calc(25% - 400px);"
/>
<div
style="background: radial-gradient(50% 50%, rgba(0,128,255,0.05), transparent); z-index: -1; width: 800px ;height: 800px; position: fixed; top: -50%; right: calc(25% - 400px);"
/>
<div
style="background: radial-gradient(50% 50%, rgba(0,128,255,0.05), transparent); z-index: -1; width: 800px ;height: 800px; position: fixed; top: -50%; right: calc(25% - 400px);"
/>
</div>
<main
class={`min-h-full w-full ${dropdownOpen || !dropdownCloseFinished ? "overflow-hidden" : ""}`}

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { browser } from "$app/environment";
import { transition } from "$lib/util/animation";
import { onMount } from "svelte";
import { onMount, tick } from "svelte";
import type { PageData } from "./$types";
import { page } from "$app/stores";
import { writable } from "svelte/store";
@ -29,10 +29,10 @@
name: "Public Game Lobby",
href: "/account/lobby",
},
{
name: "Friends",
href: "/account/friends",
},
// {
// name: "Friends",
// href: "/account/friends",
// },
];
function navClick(e: MouseEvent | HTMLAnchorElement) {
@ -141,7 +141,7 @@
beforeNavigate(({ to }) => {
if (!to) return;
if (!to.url.pathname.startsWith("/account")) {
if (!to.url.pathname.startsWith("/account") && to.url.hostname === location.hostname) {
if (navBar.style.opacity === "0") return;
navBar.animate(
[
@ -168,12 +168,11 @@
}
});
onMount(() => {
setTimeout(() => {
const items = Array.from(document.querySelectorAll(".navitem")) as HTMLAnchorElement[];
const item = items.find((i) => new URL(i.href).pathname === data.url);
navClick({ target: item } as unknown as MouseEvent);
}, 10);
onMount(async () => {
await tick(); // if this doesn't work, do setTimeout on 10ms or so
const items = Array.from(document.querySelectorAll(".navitem")) as HTMLAnchorElement[];
const item = items.find((i) => new URL(i.href).pathname === data.url);
navClick({ target: item } as unknown as MouseEvent);
});
</script>

View file

@ -1,10 +1,117 @@
<!-- <script lang="ts">
import { SuyuAPI } from "$lib/client/api";
import type { GetNotificationsResponseSuccess } from "$types/api";
import { onMount } from "svelte";
import type { PageData } from "./$types";
import { dev } from "$app/environment";
import UserDisplay from "$components/UserDisplay.svelte";
import { fly } from "svelte/transition";
let input = "";
let relationships: GetNotificationsResponseSuccess["notifications"] = [];
async function sendFq() {
const res = await SuyuAPI.friendship.sendFriendRequest({
to: input,
});
if (!res.success) return alert(res.error);
await refresh();
}
async function refresh() {
const res = await SuyuAPI.friendship.getRelationships();
if (!res.success) return alert(res.error);
relationships = res.friendships || [];
}
async function deleteRelationship(
relationship: GetNotificationsResponseSuccess["notifications"][0],
) {
const res = await SuyuAPI.friendship.deleteRelationship({
id: relationship.id,
});
if (!res.success) return alert(res.error);
await refresh();
}
async function acceptFq(relationship: GetNotificationsResponseSuccess["notifications"][0]) {
const res = await SuyuAPI.friendship.sendFriendRequest({
to: relationship.from?.username,
});
if (!res.success) return alert(res.error);
await refresh();
}
onMount(() => {
refresh();
const interval = setInterval(refresh, dev ? 500 : 30000);
return () => clearInterval(interval);
});
export let data: PageData;
</script>
<div class="relative h-[calc(100vh-200px)] flex-col gap-6 overflow-hidden">
<div
class="relative flex w-full flex-col gap-6 overflow-hidden rounded-[2.25rem] bg-[#110d10] p-8 md:p-12"
>
<h2 class=" text-[36px] leading-[1.41] md:text-[48px] md:leading-[1.1]">Friends</h2>
<p class="text-md text-wrap leading-relaxed text-[#4e4e4e]">
TBD: madeline has no friends :( ~maddie/null
<p class="text-md text-wrap leading-relaxed text-gray-400">
As of right now, friends are just a way to keep track of who you know. In the future, we
will add more features to this, such as inviting to rooms.
</p>
<div class="input-container text-md flex gap-4 text-wrap leading-relaxed">
<input class="input !w-[250px]" placeholder="Username" type="text" bind:value={input} />
<div class="flex gap-4">
<button on:click={sendFq} class="cta-button">Send</button>
<button on:click={refresh} class="button-sm">Refresh</button>
</div>
</div>
<div class="relationship-grid">
{#each relationships as relationship}
<div
in:fly|global={{ duration: 360 }}
out:fly|global={{
duration: 360,
}}
>
<UserDisplay
sent={relationship.to.id !== data.user.id}
accepted={relationship.accepted}
user={relationship.to.id === data.user.id
? relationship.from
: relationship.to}
on:delete={() => deleteRelationship(relationship)}
on:accept={() => acceptFq(relationship)}
/>
</div>
{/each}
</div>
</div>
</div>
<style>
.relationship-grid {
grid-template-columns: repeat(5, 1fr);
display: grid;
gap: 8px;
}
@media (max-width: 1000px) {
.relationship-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 650px) {
.relationship-grid {
grid-template-columns: 2fr;
}
}
@media (max-width: 600px) {
.input-container {
flex-direction: column;
}
}
</style> -->

View file

@ -0,0 +1,18 @@
// import { json } from "$lib/server/util/index.js";
// import { useAuth } from "$lib/util/api/index.js";
// import type { GetNotificationsResponse } from "$types/api";
// export async function GET({ request }) {
// const user = await useAuth(request);
// if (!user)
// return json<GetNotificationsResponse>({
// success: false,
// error: "Not logged in",
// });
// const requests = await user.getFriendRequests();
// console.log(requests);
// return json<GetNotificationsResponse>({
// success: true,
// notifications: requests,
// });
// }

View file

@ -0,0 +1,149 @@
// import { friendshipRepo, userRepo } from "$lib/server/repo";
// import { json } from "$lib/server/util/index.js";
// import { useAuth } from "$lib/util/api/index.js";
// import type {
// GetRelationshipsResponse,
// DeleteAccountResponse,
// DeleteRelationshipRequest,
// DeleteRelationshipResponse,
// SendFriendRequestRequest,
// } from "$types/api.js";
// export async function POST({ request }) {
// const body: SendFriendRequestRequest = await request.json();
// const user = await useAuth(request, true);
// if (!user)
// return json({
// success: false,
// error: "Not logged in",
// });
// const to = await userRepo.findOne({
// where: {
// username: body.to,
// },
// });
// if (!to)
// return json({
// success: false,
// error: "User not found",
// });
// if (to.id === user.id)
// return json({
// success: false,
// error: "Cannot send friend request to self",
// });
// if (user.sentFriendRequests.some((frq) => frq.to.id === to.id))
// return json({
// success: false,
// error: "Friend request already sent",
// });
// const foundFrq = await friendshipRepo.findOne({
// where: {
// to: {
// id: user.id,
// },
// from: {
// id: to.id,
// },
// },
// });
// if (foundFrq) {
// foundFrq.accepted = true;
// await friendshipRepo.save(foundFrq);
// return json({
// success: true,
// });
// }
// const frq = friendshipRepo.create({
// to,
// from: user,
// accepted: false,
// });
// await friendshipRepo.save(frq);
// return json({
// success: true,
// });
// }
// export async function DELETE({ request }) {
// const body: DeleteRelationshipRequest = await request.json();
// const user = await useAuth(request, true);
// if (!user)
// return json<DeleteRelationshipResponse>(
// {
// success: false,
// error: "Not logged in",
// },
// 401,
// );
// const relationship = await friendshipRepo.findOne({
// where: {
// id: body.id,
// },
// relations: ["to", "from"],
// });
// if (!relationship)
// return json<DeleteRelationshipResponse>(
// {
// success: false,
// error: "Relationship not found",
// },
// 404,
// );
// if (relationship.to.id !== user.id && relationship.from.id !== user.id)
// return json<DeleteRelationshipResponse>(
// {
// success: false,
// error: "Not authorized",
// },
// 403,
// );
// await friendshipRepo.remove(relationship);
// return json<DeleteRelationshipResponse>({
// success: true,
// friendships: user.sentFriendRequests.concat(user.receivedFriendRequests),
// });
// }
// export async function GET({ request }) {
// const auth = await useAuth(request, true);
// if (!auth) {
// return json<GetRelationshipsResponse>(
// {
// success: false,
// error: "Not logged in",
// },
// 401,
// );
// }
// const user = await userRepo.findOne({
// where: {
// id: auth.id,
// },
// relations: [
// "sentFriendRequests",
// "sentFriendRequests.from",
// "sentFriendRequests.to",
// "receivedFriendRequests",
// "receivedFriendRequests.from",
// "receivedFriendRequests.to",
// ],
// loadEagerRelations: true,
// });
// if (!user) {
// return json<GetRelationshipsResponse>(
// {
// success: false,
// error: "you don't exist?",
// },
// 404,
// );
// }
// return json<GetRelationshipsResponse>({
// success: true,
// friendships: user.sentFriendRequests.concat(user.receivedFriendRequests),
// });
// }

View file

@ -3,14 +3,7 @@ import { RateLimiter, json } from "$lib/server/util/index.js";
import type { LoginResponse, LoginRequest } from "$types/api";
import bcrypt from "bcrypt";
const rateLimit = new RateLimiter();
export async function POST({ request, getClientAddress }) {
if (rateLimit.isLimited(getClientAddress()))
return json<LoginResponse>({
success: false,
error: "rate limited",
});
const body: LoginRequest = await request.json();
if (
!body.email ||
@ -29,6 +22,7 @@ export async function POST({ request, getClientAddress }) {
email: body.email,
},
select: ["password", "apiKey"],
loadEagerRelations: false,
});
if (!user)
return json<LoginResponse>({

View file

@ -0,0 +1,68 @@
import { json } from "$lib/server/util/index.js";
import { GITLAB_WEBHOOK_TOKEN } from "$env/static/private";
export interface Release {
id: number;
created_at: string;
description: string;
name: string;
released_at: string;
tag: string;
object_kind: string;
project: Project;
url: string;
action: string;
assets: Assets;
commit: Commit;
}
export interface Assets {
count: number;
links: Array<(string | null)[]>;
sources: Array<(string | null)[]>;
}
export interface Commit {
id: string;
message: string;
title: string;
timestamp: Date;
url: string;
author: Author;
}
export interface Author {
name: string;
email: string;
}
export interface Project {
id: number;
name: string;
description: null;
web_url: string;
avatar_url: null;
git_ssh_url: string;
git_http_url: string;
namespace: string;
visibility_level: number;
path_with_namespace: string;
default_branch: string;
ci_config_path: string;
homepage: string;
url: string;
ssh_url: string;
http_url: string;
}
export async function POST({ request }) {
const body: Release = await request.json();
const headers = request.headers;
if (headers.get("X-Gitlab-Token") !== GITLAB_WEBHOOK_TOKEN)
return json({
success: false,
message: "Nice try!",
});
return json({ success: true, message: "Ok, you win. For now." });
}

37
src/types/api.d.ts vendored
View file

@ -1,6 +1,6 @@
/* api types */
import type { SuyuUser } from "$lib/server/schema";
import type { Friendship, SuyuUser } from "$lib/server/schema";
export interface GenericFailureResponse {
success: false;
@ -45,3 +45,38 @@ export interface LoginResponseSuccess {
}
export type LoginResponse = LoginResponseSuccess | GenericFailureResponse;
export interface GetNotificationsResponseSuccess {
success: true;
notifications: Friendship[];
}
export type GetNotificationsResponse = GetNotificationsResponseSuccess | GenericFailureResponse;
export interface SendFriendRequestRequest {
to: string;
}
export interface SendFriendRequestResponseSuccess {
success: true;
}
export type SendFriendRequestResponse = SendFriendRequestResponseSuccess | GenericFailureResponse;
export interface DeleteRelationshipRequest {
id: string;
}
export interface DeleteRelationshipResponseSuccess {
success: true;
friendships: Friendship[];
}
export type DeleteRelationshipResponse = DeleteRelationshipResponseSuccess | GenericFailureResponse;
export interface GetRelationshipsResponseSuccess {
success: true;
friendships: Friendship[];
}
export type GetRelationshipsResponse = GetRelationshipsResponseSuccess | GenericFailureResponse;