kaboom (nuke)
This commit is contained in:
parent
c67ac831d6
commit
0687831b92
47 changed files with 1 additions and 14358 deletions
56
.github/workflows/frontend.yml
vendored
56
.github/workflows/frontend.yml
vendored
|
@ -1,56 +0,0 @@
|
|||
name: Deploy frontend
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- frontend/**
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@master
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
cache: npm
|
||||
cache-dependency-path: frontend/package-lock.json
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm --prefix frontend install
|
||||
|
||||
- name: Build
|
||||
run: npm --prefix frontend run build
|
||||
|
||||
- name: Archive Production Artifact
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: frontend_build
|
||||
path: frontend/build
|
||||
|
||||
deploy:
|
||||
name: Deploy
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@master
|
||||
|
||||
- name: Download Artifact
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: frontend_build
|
||||
path: frontend/build
|
||||
|
||||
- name: Deploy to Firebase
|
||||
uses: w9jds/firebase-action@master
|
||||
with:
|
||||
args: deploy --only hosting
|
||||
env:
|
||||
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
|
||||
PROJECT_ID: ${{ secrets.FIREBASE_PROJECT }}
|
45
.github/workflows/functions.yml
vendored
45
.github/workflows/functions.yml
vendored
|
@ -1,45 +0,0 @@
|
|||
name: Deploy functions
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- functions/**
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@master
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
cache: npm
|
||||
cache-dependency-path: functions/package-lock.json
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm --prefix functions install
|
||||
|
||||
- name: Restore secrets
|
||||
run: |
|
||||
echo $SECRET_JSON > ./functions/src/secret.json
|
||||
echo $FIREBASE_ADMINSDK_JSON > ./functions/src/firebase-adminsdk.json
|
||||
shell: bash
|
||||
env:
|
||||
SECRET_JSON: ${{ secrets.SECRET_JSON }}
|
||||
FIREBASE_ADMINSDK_JSON: ${{ secrets.FIREBASE_ADMINSDK_JSON }}
|
||||
|
||||
- name: Build
|
||||
run: npm --prefix functions run build
|
||||
|
||||
- name: Deploy to Firebase
|
||||
uses: w9jds/firebase-action@master
|
||||
with:
|
||||
args: deploy --only functions
|
||||
env:
|
||||
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
|
||||
PROJECT_ID: ${{ secrets.FIREBASE_PROJECT }}
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,6 +0,0 @@
|
|||
/_/
|
||||
|
||||
.firebase/
|
||||
.firebaserc
|
||||
firestore.indexes.json
|
||||
*.log
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"semi": false,
|
||||
"useTabs": true
|
||||
}
|
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"recommendations": ["svelte.svelte-vscode", "esbenp.prettier-vscode"]
|
||||
}
|
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnPaste": true,
|
||||
"editor.formatOnSave": true,
|
||||
"cSpell.words": ["developomp", "firestore", "Sider"]
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
[Go here](https://github.com/llama-bot/llama-bot/blob/master/CONTRIBUTING.md)
|
19
LICENSE
19
LICENSE
|
@ -1,19 +0,0 @@
|
|||
Copyright (c) 2021 developomp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,3 +1,3 @@
|
|||
# llama-bot-web-interface
|
||||
|
||||
## [Documentation](https://llama-bot.github.io/llama-bot-docs/docs/web-interface/overview)
|
||||
**This project is dead.**
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
{
|
||||
"functions": {
|
||||
"source": "functions"
|
||||
},
|
||||
"firestore": {
|
||||
"rules": "firestore.rules",
|
||||
"indexes": "firestore.indexes.json"
|
||||
},
|
||||
"hosting": {
|
||||
"public": "frontend/build/",
|
||||
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "/api/**",
|
||||
"function": "api"
|
||||
},
|
||||
{
|
||||
"source": "**",
|
||||
"destination": "/index.html"
|
||||
}
|
||||
]
|
||||
},
|
||||
"emulators": {
|
||||
"functions": {
|
||||
"port": 5001
|
||||
},
|
||||
"firestore": {
|
||||
"port": 8080
|
||||
},
|
||||
"hosting": {
|
||||
"port": 5000
|
||||
},
|
||||
"ui": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
rules_version = '2';
|
||||
service cloud.firestore {
|
||||
match /databases/{database}/documents {
|
||||
match /{document=**} {
|
||||
allow read, write: if false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
parser: "@typescript-eslint/parser",
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier",
|
||||
],
|
||||
plugins: ["svelte3", "@typescript-eslint"],
|
||||
ignorePatterns: ["*.cjs"],
|
||||
overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }],
|
||||
settings: {
|
||||
"svelte3/typescript": () => require("typescript"),
|
||||
},
|
||||
parserOptions: {
|
||||
sourceType: "module",
|
||||
ecmaVersion: 2020,
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true,
|
||||
},
|
||||
}
|
11
frontend/.gitignore
vendored
11
frontend/.gitignore
vendored
|
@ -1,11 +0,0 @@
|
|||
/build/
|
||||
/.svelte-kit/
|
||||
/package/
|
||||
/node_modules/
|
||||
|
||||
.DS_Store
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
.vercel
|
||||
.output
|
4169
frontend/package-lock.json
generated
4169
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,36 +0,0 @@
|
|||
{
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "svelte-kit dev",
|
||||
"build": "svelte-kit build",
|
||||
"preview": "svelte-kit preview",
|
||||
"check": "svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
|
||||
"format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/noto-sans": "^4.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^1.0.0-next.17",
|
||||
"@sveltejs/adapter-static": "^1.0.0-next.28",
|
||||
"@sveltejs/kit": "^1.0.0-next.278",
|
||||
"@types/cookie": "^0.4.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.12.0",
|
||||
"@typescript-eslint/parser": "^5.12.0",
|
||||
"eslint": "^8.9.0",
|
||||
"eslint-config-prettier": "^8.4.0",
|
||||
"eslint-plugin-svelte3": "^3.4.0",
|
||||
"prettier": "^2.5.1",
|
||||
"prettier-plugin-svelte": "^2.6.0",
|
||||
"sass": "^1.49.8",
|
||||
"svelte": "^3.46.4",
|
||||
"svelte-check": "^2.4.5",
|
||||
"svelte-icons": "^2.1.0",
|
||||
"svelte-loading-spinners": "^0.1.7",
|
||||
"svelte-preprocess": "^4.10.3",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.5.5"
|
||||
}
|
||||
}
|
22
frontend/src/app.d.ts
vendored
22
frontend/src/app.d.ts
vendored
|
@ -1,22 +0,0 @@
|
|||
/// <reference types="@sveltejs/kit" />
|
||||
|
||||
// See https://kit.svelte.dev/docs/typescript
|
||||
// for information about these interfaces
|
||||
declare namespace App {
|
||||
interface Locals {
|
||||
userid: string
|
||||
}
|
||||
|
||||
interface Platform {}
|
||||
|
||||
interface Session {}
|
||||
|
||||
interface Stuff {}
|
||||
}
|
||||
|
||||
interface UserData {
|
||||
id: string // "501277805540147220"
|
||||
avatar: string // "c61056f4f187b6b3658afb68c56f3f87"
|
||||
discriminator: string // "0001"
|
||||
username: string // "developomp"
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="description" content="Llama bot web interface" />
|
||||
<link rel="icon" href="/assets/icon/llama-color.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
%svelte.head%
|
||||
</head>
|
||||
|
||||
<body>
|
||||
%svelte.body%
|
||||
</body>
|
||||
</html>
|
|
@ -1 +0,0 @@
|
|||
export const titlePrefix = "Llama Bot | "
|
|
@ -1,96 +0,0 @@
|
|||
<script lang="ts">
|
||||
import Github from "svelte-icons/fa/FaGithub.svelte"
|
||||
import Discord from "svelte-icons/fa/FaDiscord.svelte"
|
||||
import Heartbeat from "svelte-icons/fa/FaHeartbeat.svelte"
|
||||
import Book from "svelte-icons/fa/FaBook.svelte"
|
||||
</script>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="created-by">
|
||||
Created by <b>developomp</b>
|
||||
</div>
|
||||
|
||||
<!-- right links -->
|
||||
<div class="icons">
|
||||
<a
|
||||
class="icon"
|
||||
alt="Documentation"
|
||||
href="https://llama-bot.github.io/llama-bot-docs/docs/web-interface/overview"
|
||||
target="_"
|
||||
>
|
||||
<Book />
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="icon"
|
||||
alt="Server status"
|
||||
href="https://status.llama.developomp.com"
|
||||
target="_"
|
||||
>
|
||||
<Heartbeat />
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="icon"
|
||||
alt="Discord server"
|
||||
href="https://discord.gg/aQqamSCUcS"
|
||||
target="_"
|
||||
>
|
||||
<Discord />
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="icon"
|
||||
alt="Github repository"
|
||||
href="https://github.com/llama-bot"
|
||||
target="_"
|
||||
>
|
||||
<Github />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<style lang="scss">
|
||||
footer {
|
||||
--height: 8rem;
|
||||
|
||||
background-color: var(--dark);
|
||||
|
||||
height: var(--height);
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
padding: 0 var(--h-padding);
|
||||
|
||||
.container {
|
||||
width: min(100%, var(--max-width));
|
||||
height: var(--height);
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between; // spread content
|
||||
align-items: center; // vertically center elements
|
||||
|
||||
.created-by {
|
||||
color: darkgrey;
|
||||
}
|
||||
|
||||
.icons {
|
||||
height: 24px;
|
||||
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
|
||||
.icon {
|
||||
color: lightgrey;
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,156 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { page } from "$app/stores"
|
||||
import { userData } from "../stores"
|
||||
</script>
|
||||
|
||||
<header>
|
||||
<nav>
|
||||
<div class="left-content">
|
||||
<img class="icon" src="assets/icon/llama.png" alt="llama logo" />
|
||||
|
||||
<b>Llama Bot</b>
|
||||
|
||||
<div class="links">
|
||||
<a
|
||||
class:active={$page.url.pathname === "/"}
|
||||
sveltekit:prefetch
|
||||
href="/"
|
||||
>
|
||||
Home
|
||||
</a>
|
||||
<a
|
||||
class:active={$page.url.pathname === "/about"}
|
||||
sveltekit:prefetch
|
||||
href="/about"
|
||||
>
|
||||
About
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="login-logout">
|
||||
{#if $userData}
|
||||
<div class="user">
|
||||
<img
|
||||
alt="user pfp"
|
||||
src={`https://cdn.discordapp.com/avatars/${$userData.id}/${$userData.avatar}.png`}
|
||||
/>
|
||||
{$userData.username}#{$userData.discriminator}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="login-logout-button">
|
||||
<a href={$userData ? "/api/logout" : "/api/login"}>
|
||||
{$userData ? "Logout" : "Login"}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<style lang="scss">
|
||||
header {
|
||||
--height: 4rem;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
height: var(--height);
|
||||
|
||||
padding: 0 var(--h-padding);
|
||||
|
||||
background-color: var(--dark);
|
||||
color: var(--light);
|
||||
|
||||
nav {
|
||||
width: min(100%, var(--max-width)); // cap width
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
height: var(--height);
|
||||
|
||||
.left-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
img.icon {
|
||||
width: 48px;
|
||||
}
|
||||
|
||||
b {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.links {
|
||||
display: flex;
|
||||
gap: 0.8rem;
|
||||
margin-left: 2rem;
|
||||
|
||||
a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
|
||||
&.active {
|
||||
border-bottom: 3px solid white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-logout {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: right;
|
||||
gap: 0.5rem;
|
||||
|
||||
.user {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding: 0.1rem;
|
||||
gap: 0.2rem;
|
||||
|
||||
align-items: center;
|
||||
|
||||
color: lightgray;
|
||||
|
||||
img {
|
||||
height: 80%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logout-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
height: 100%;
|
||||
|
||||
background-color: indianred;
|
||||
|
||||
&:hover {
|
||||
background-color: firebrick !important;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: darkred !important;
|
||||
}
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
padding: 0 1rem;
|
||||
align-items: center;
|
||||
|
||||
color: white;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,29 +0,0 @@
|
|||
<script lang="ts">
|
||||
import Heart from "svelte-icons/fa/FaHeart.svelte"
|
||||
import List from "svelte-icons/fa/FaList.svelte"
|
||||
import History from "svelte-icons/fa/FaHistory.svelte"
|
||||
import Issue from "svelte-icons/fa/FaExclamationCircle.svelte"
|
||||
|
||||
const entries = [
|
||||
{
|
||||
title: "Favorites",
|
||||
url: "/favorites",
|
||||
icon: Heart,
|
||||
},
|
||||
{
|
||||
title: "Modules",
|
||||
url: "/modules",
|
||||
icon: List,
|
||||
},
|
||||
{
|
||||
title: "Logs",
|
||||
url: "/logs",
|
||||
icon: History,
|
||||
},
|
||||
{
|
||||
title: "Incidents",
|
||||
url: "/incidents",
|
||||
icon: Issue,
|
||||
},
|
||||
]
|
||||
</script>
|
|
@ -1,84 +0,0 @@
|
|||
/**
|
||||
* Code taken from https://github.com/joshnuss/svelte-local-storage-store
|
||||
*/
|
||||
|
||||
import { writable as internal, get } from "svelte/store"
|
||||
import type { Writable } from "svelte/store"
|
||||
|
||||
declare type Updater<T> = (value: T) => T
|
||||
declare type StoreDict<T> = { [key: string]: Writable<T> }
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
const stores: StoreDict<any> = {}
|
||||
|
||||
function stringify(value: any): string {
|
||||
switch (value) {
|
||||
case undefined: {
|
||||
return "undefined"
|
||||
}
|
||||
|
||||
case null: {
|
||||
return "null"
|
||||
}
|
||||
|
||||
default: {
|
||||
return JSON.stringify(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parse<T>(value: string) {
|
||||
switch (value) {
|
||||
case "undefined": {
|
||||
return undefined
|
||||
}
|
||||
|
||||
case "null": {
|
||||
return null
|
||||
}
|
||||
|
||||
default: {
|
||||
return <T>JSON.parse(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function writable<T>(key: string, initialValue: T): Writable<T> {
|
||||
if (!stores[key]) {
|
||||
const store = internal(initialValue, (set) => {
|
||||
const json = localStorage.getItem(key)
|
||||
|
||||
if (json) set(parse<T>(json))
|
||||
|
||||
const handleStorage = (event: StorageEvent) => {
|
||||
if (event.key === key) {
|
||||
set(event.newValue ? <T>parse(event.newValue) : null)
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("storage", handleStorage)
|
||||
|
||||
return () => window.removeEventListener("storage", handleStorage)
|
||||
})
|
||||
|
||||
const { subscribe, set } = store
|
||||
|
||||
stores[key] = {
|
||||
set(value: T) {
|
||||
localStorage.setItem(key, stringify(value))
|
||||
set(value)
|
||||
},
|
||||
|
||||
update(updater: Updater<T>) {
|
||||
const value = updater(get(store))
|
||||
|
||||
localStorage.setItem(key, stringify(value))
|
||||
set(value)
|
||||
},
|
||||
|
||||
subscribe,
|
||||
}
|
||||
}
|
||||
|
||||
return stores[key]
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { updateUserData } from "../stores"
|
||||
import { onMount } from "svelte"
|
||||
|
||||
import Header from "$lib/Header.svelte"
|
||||
import Footer from "$lib/Footer.svelte"
|
||||
|
||||
// load user data on page load
|
||||
onMount(() => {
|
||||
updateUserData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<Header />
|
||||
<main>
|
||||
<slot />
|
||||
</main>
|
||||
<Footer />
|
||||
|
||||
<style lang="scss" global>
|
||||
@import "@fontsource/noto-sans/index.css";
|
||||
|
||||
:root {
|
||||
/* global CSS variables */
|
||||
--dark: #001529;
|
||||
--light: #f0f2f5;
|
||||
--max-width: 1500px;
|
||||
--h-padding: 2rem;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
font-family: "Noto Sans";
|
||||
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
background-color: var(--light);
|
||||
}
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
align-self: center;
|
||||
|
||||
width: min(100%, var(--max-width)); // cap width
|
||||
}
|
||||
</style>
|
|
@ -1,12 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { titlePrefix } from "../constants"
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{titlePrefix}About</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1>About</h1>
|
||||
|
||||
<style>
|
||||
</style>
|
|
@ -1,12 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { titlePrefix } from "../constants"
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{titlePrefix}Home</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1>Home</h1>
|
||||
|
||||
<style>
|
||||
</style>
|
|
@ -1,14 +0,0 @@
|
|||
import { writable } from "./local-storage-store"
|
||||
|
||||
export const userData = writable<UserData>("userData", undefined)
|
||||
|
||||
export async function updateUserData() {
|
||||
fetch("/api/user-data", { credentials: "same-origin" })
|
||||
.then((data) => data.json())
|
||||
.then((data) => {
|
||||
userData.set(data)
|
||||
})
|
||||
.catch(() => {
|
||||
userData.set(undefined)
|
||||
})
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 17 KiB |
Binary file not shown.
Before Width: | Height: | Size: 20 KiB |
Binary file not shown.
Before Width: | Height: | Size: 20 KiB |
|
@ -1 +0,0 @@
|
|||
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>
|
Before Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
|
@ -1,2 +0,0 @@
|
|||
User-agent: *
|
||||
Disallow:
|
|
@ -1,18 +0,0 @@
|
|||
import adapter from "@sveltejs/adapter-static"
|
||||
import preprocess from "svelte-preprocess"
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
preprocess: preprocess(),
|
||||
|
||||
kit: {
|
||||
adapter: adapter({
|
||||
pages: "build",
|
||||
assets: "build",
|
||||
fallback: "index.html",
|
||||
precompress: true,
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
|
@ -1,36 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"module": "es2020",
|
||||
"lib": ["es2020", "DOM"],
|
||||
"target": "es2020",
|
||||
/**
|
||||
svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript
|
||||
to enforce using \`import type\` instead of \`import\` for Types.
|
||||
*/
|
||||
"importsNotUsedAsValues": "error",
|
||||
/**
|
||||
TypeScript doesn't know about import usages in the template because it only sees the
|
||||
script of a Svelte file. Therefore preserve all value imports. Requires TS 4.5 or higher.
|
||||
*/
|
||||
"preserveValueImports": true,
|
||||
"isolatedModules": true,
|
||||
"resolveJsonModule": true,
|
||||
/**
|
||||
To have warnings/errors of the Svelte compiler at the correct position,
|
||||
enable source maps by default.
|
||||
*/
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"baseUrl": ".",
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"paths": {
|
||||
"$lib": ["src/lib"],
|
||||
"$lib/*": ["src/lib/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.ts", "src/**/*.svelte"]
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
es6: true,
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:import/errors",
|
||||
"plugin:import/warnings",
|
||||
"plugin:import/typescript",
|
||||
"google",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier",
|
||||
],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
project: ["tsconfig.json", "tsconfig.dev.json"],
|
||||
tsconfigRootDir: __dirname,
|
||||
sourceType: "module",
|
||||
},
|
||||
ignorePatterns: [
|
||||
"/lib/**/*", // Ignore built files.
|
||||
],
|
||||
plugins: ["@typescript-eslint", "import"],
|
||||
rules: {
|
||||
quotes: ["error", "double"],
|
||||
"import/no-unresolved": 0,
|
||||
},
|
||||
}
|
8
functions/.gitignore
vendored
8
functions/.gitignore
vendored
|
@ -1,8 +0,0 @@
|
|||
/node_modules/
|
||||
|
||||
# Compiled JavaScript files
|
||||
/lib/
|
||||
|
||||
# secrets
|
||||
/src/secret.json
|
||||
/src/firebase-adminsdk.json
|
9008
functions/package-lock.json
generated
9008
functions/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,42 +0,0 @@
|
|||
{
|
||||
"name": "functions",
|
||||
"private": true,
|
||||
"main": "lib/index.js",
|
||||
"engines": {
|
||||
"node": "16"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint --ext .js,.ts .",
|
||||
"build": "tsc",
|
||||
"serve": "npm run build && firebase emulators:start --only functions",
|
||||
"shell": "npm run build && firebase functions:shell",
|
||||
"start": "npm run shell",
|
||||
"deploy": "firebase deploy --only functions",
|
||||
"logs": "firebase functions:log"
|
||||
},
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.17.3",
|
||||
"express-session": "^1.17.2",
|
||||
"firebase": "^9.6.7",
|
||||
"firebase-admin": "^10.0.2",
|
||||
"firebase-functions": "^3.18.1",
|
||||
"passport": "^0.5.2",
|
||||
"passport-discord": "^0.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/express-session": "^1.17.4",
|
||||
"@types/passport": "^1.0.7",
|
||||
"@types/passport-discord": "^0.1.5",
|
||||
"@typescript-eslint/eslint-plugin": "^5.12.1",
|
||||
"@typescript-eslint/parser": "^5.12.1",
|
||||
"eslint": "^8.9.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-config-prettier": "^8.4.0",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"firebase-functions-test": "^0.3.3",
|
||||
"typescript": "^4.5.5"
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
import admin, { firestore } from "firebase-admin"
|
||||
import { logger } from "firebase-functions"
|
||||
|
||||
interface DatabaseResult {
|
||||
success: boolean
|
||||
error?: string
|
||||
}
|
||||
|
||||
export default {
|
||||
/**
|
||||
* Checks if a user exists in the database
|
||||
*
|
||||
* @param {string} uid - discord user id
|
||||
*/
|
||||
async findUser(uid: string): Promise<DatabaseResult> {
|
||||
try {
|
||||
const user = await admin.firestore().collection("users").doc(uid).get()
|
||||
if (!user.exists) {
|
||||
return {
|
||||
success: false,
|
||||
error: `user with uid ${uid} does not exist`,
|
||||
}
|
||||
}
|
||||
|
||||
return { success: true }
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message }
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Reads user data from the database
|
||||
*
|
||||
* @param {string} uid - discord user id
|
||||
*/
|
||||
async getUser(uid: string): Promise<DBUser> {
|
||||
const result = await admin.firestore().collection("users").doc(uid).get()
|
||||
if (!result.exists) throw new Error(`user with uid ${uid} does not exist`)
|
||||
|
||||
const data = result.data()
|
||||
if (!data) throw new Error("User was found but failed to read the data.")
|
||||
|
||||
return data as DBUser
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new entry in the database
|
||||
*
|
||||
* @param {DBUser} data - User data to create
|
||||
*/
|
||||
async newUser(data: DBUser): Promise<DatabaseResult> {
|
||||
try {
|
||||
await firestore().doc(`/users/${data.id}`).set(data)
|
||||
|
||||
return { success: true }
|
||||
} catch (error) {
|
||||
logger.error("Error creating user", error)
|
||||
|
||||
return { success: false, error: error.message }
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update user data
|
||||
*
|
||||
* @param {Partial<DBUser>} data - Data to update
|
||||
*/
|
||||
async updateUser(data: Partial<DBUser>): Promise<DatabaseResult> {
|
||||
await firestore().doc(`/users/${data.id}`).update(data)
|
||||
|
||||
return { success: true }
|
||||
},
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"pathPrefix": "/api",
|
||||
"scopes": ["identify"]
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
import admin from "firebase-admin"
|
||||
import { https } from "firebase-functions"
|
||||
|
||||
import express from "express"
|
||||
import cors from "cors"
|
||||
import session, { SessionOptions } from "express-session"
|
||||
import passport from "passport"
|
||||
|
||||
import authRoutes from "./routes/authRoutes"
|
||||
import dataRoutes from "./routes/dataRoutes"
|
||||
|
||||
import "./services/discordOauth"
|
||||
|
||||
import secret from "./secret.json"
|
||||
import serviceAccountKey from "./firebase-adminsdk.json"
|
||||
|
||||
admin.initializeApp({
|
||||
credential: admin.credential.cert(serviceAccountKey as admin.ServiceAccount),
|
||||
})
|
||||
|
||||
const sessionOption: SessionOptions = {
|
||||
secret: secret.session,
|
||||
name: "__session", // https://stackoverflow.com/a/44935288/12979111
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
cookie: {
|
||||
maxAge: 1000 * 60 * 60 * 24 * 7, // 1 week
|
||||
},
|
||||
}
|
||||
|
||||
const app = express()
|
||||
|
||||
if (process.env.FUNCTIONS_EMULATOR !== "true") {
|
||||
app.set("trust proxy", 1)
|
||||
sessionOption.cookie = {
|
||||
...sessionOption.cookie,
|
||||
}
|
||||
}
|
||||
|
||||
app.use(
|
||||
cors({
|
||||
origin: ["https://llama.developomp.com", "http://localhost:5000"],
|
||||
credentials: true,
|
||||
})
|
||||
)
|
||||
app.use(session(sessionOption))
|
||||
app.use(passport.initialize())
|
||||
app.use(passport.session())
|
||||
|
||||
dataRoutes(app)
|
||||
authRoutes(app)
|
||||
|
||||
export const api = https.onRequest(app)
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Handle authentication
|
||||
*/
|
||||
|
||||
import { Express } from "express"
|
||||
import passport from "passport"
|
||||
|
||||
import config from "../config.json"
|
||||
|
||||
export default (app: Express): void => {
|
||||
// start login (redirects to /api/auth)
|
||||
app.get(
|
||||
config.pathPrefix + "/login",
|
||||
passport.authenticate("discord", { scope: config.scopes })
|
||||
)
|
||||
|
||||
// authenticates login (redirects to /)
|
||||
app.get(
|
||||
config.pathPrefix + "/auth",
|
||||
passport.authenticate("discord", { successRedirect: "/" })
|
||||
)
|
||||
|
||||
// logs out the user
|
||||
app.get(config.pathPrefix + "/logout", (req, res) => {
|
||||
req.logout()
|
||||
res.redirect("/")
|
||||
})
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Handle firestore read/writes related to discord bot
|
||||
*/
|
||||
|
||||
import { Express, Request, Response, NextFunction } from "express"
|
||||
import database from "../API/database"
|
||||
|
||||
import config from "../config.json"
|
||||
|
||||
const checkIfLoggedIn = (req: Request, res: Response, next: NextFunction) => {
|
||||
if (req.isAuthenticated()) return next()
|
||||
res.status(401).send("Not authenticated")
|
||||
}
|
||||
|
||||
export default (app: Express): void => {
|
||||
/**
|
||||
* Get user data from google firebase firestore
|
||||
*/
|
||||
app.get(
|
||||
config.pathPrefix + "/user-data",
|
||||
checkIfLoggedIn,
|
||||
async (req, res) => {
|
||||
res.setHeader("Cache-Control", "private")
|
||||
|
||||
req.user
|
||||
? res.status(200).send(await database.getUser(req.user.id))
|
||||
: res.status(500).send("Failed to get user")
|
||||
}
|
||||
)
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
import { logger } from "firebase-functions"
|
||||
|
||||
import passport from "passport"
|
||||
import PassportDiscord from "passport-discord"
|
||||
|
||||
import database from "../API/database"
|
||||
|
||||
import secret from "../secret.json"
|
||||
import config from "../config.json"
|
||||
|
||||
passport.serializeUser((user, done) => {
|
||||
// `user.id` will be used in `passport.deserializeUser`
|
||||
done(null, user.id)
|
||||
})
|
||||
|
||||
passport.deserializeUser(async (id: string, done) => {
|
||||
try {
|
||||
const result = await database.findUser(id)
|
||||
|
||||
if (result.success) {
|
||||
done(null, { id })
|
||||
} else {
|
||||
done(new Error("Failed to get user from database"))
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Error deserializing user", error.message)
|
||||
done(error)
|
||||
}
|
||||
})
|
||||
|
||||
passport.use(
|
||||
new PassportDiscord.Strategy(
|
||||
{
|
||||
clientID: secret.clientID,
|
||||
clientSecret: secret.clientSecret,
|
||||
callbackURL:
|
||||
(process.env.FUNCTIONS_EMULATOR === "true"
|
||||
? "http://localhost:5000"
|
||||
: "https://llama.developomp.com") +
|
||||
config.pathPrefix +
|
||||
"/auth",
|
||||
scope: config.scopes,
|
||||
},
|
||||
|
||||
async (_accessToken, _refreshToken, profile, done) => {
|
||||
try {
|
||||
const result = await database.findUser(profile.id)
|
||||
|
||||
const data = {
|
||||
avatar: profile.avatar || undefined,
|
||||
discriminator: profile.discriminator,
|
||||
id: profile.id,
|
||||
username: profile.username,
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
await database.updateUser(data)
|
||||
} else {
|
||||
database.newUser(data)
|
||||
}
|
||||
|
||||
done(null, { id: profile.id })
|
||||
} catch (error) {
|
||||
logger.error("Error creating a user", error)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
18
functions/src/types/express.d.ts
vendored
18
functions/src/types/express.d.ts
vendored
|
@ -1,18 +0,0 @@
|
|||
declare global {
|
||||
namespace Express {
|
||||
// user data for the express server
|
||||
export interface User {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
// user data in the google firebase firestore DB
|
||||
export interface DBUser {
|
||||
id: string // discord user id
|
||||
avatar?: string // discord avatar hash
|
||||
discriminator: string // 4 digit discord discriminator
|
||||
username: string // discord username
|
||||
}
|
||||
}
|
||||
|
||||
export {}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"include": [".eslintrc.js"]
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedLocals": true,
|
||||
"outDir": "lib",
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"target": "es2017",
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"useUnknownInCatchVariables": false
|
||||
},
|
||||
"compileOnSave": true,
|
||||
"include": ["src"]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue