1
0
Fork 0

moved llama-bot-web-api to this repo and made basic login logic

This commit is contained in:
Kim, Jimin 2021-09-12 19:21:03 +09:00
parent f4aed45ed5
commit 9b521e901a
42 changed files with 11397 additions and 112 deletions

143
.gitignore vendored
View file

@ -1,21 +1,136 @@
# dependencies _/
/node_modules
/.pnp
.pnp.js
# testing # Unmodified
/coverage # Created by https://www.toptal.com/developers/gitignore/api/firebase,node
# Edit at https://www.toptal.com/developers/gitignore?templates=firebase,node
# production ### Firebase ###
/build .idea
**/node_modules/*
**/.firebaserc
# misc ### Firebase Patch ###
.DS_Store .runtimeconfig.json
.env.local .firebase/
.env.development.local
.env.test.local
.env.production.local
### Node ###
# Logs
logs
*.log
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
.env.production
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# End of https://www.toptal.com/developers/gitignore/api/firebase,node

View file

@ -1,5 +1,6 @@
{ {
"semi": false, "semi": false,
"useTabs": true, "useTabs": true,
"tabWidth": 4 "tabWidth": 4,
"singleQuote": false
} }

View file

@ -1,8 +1,6 @@
{ {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnPaste": true, "editor.formatOnPaste": true,
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode", "cSpell.words": ["firestore", "Sider"]
"editor.insertSpaces": false,
"editor.detectIndentation": false,
"cSpell.words": ["Sider"]
} }

View file

@ -1,3 +1,6 @@
# llama-bot-web-interface # llama-bot-web-interface
![License: MIT](https://img.shields.io/github/license/llama-bot/llama-bot-web-api?style=flat-square)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
[Documentation](https://llama-bot.github.io/llama-bot-docs/docs/web-interface/overview) [Documentation](https://llama-bot.github.io/llama-bot-docs/docs/web-interface/overview)

41
firebase.json Normal file
View file

@ -0,0 +1,41 @@
{
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint",
"npm --prefix \"$RESOURCE_DIR\" run build"
],
"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
}
}
}

4
firestore.indexes.json Normal file
View file

@ -0,0 +1,4 @@
{
"indexes": [],
"fieldOverrides": []
}

8
firestore.rules Normal file
View file

@ -0,0 +1,8 @@
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}

21
frontend/.gitignore vendored Normal file
View file

@ -0,0 +1,21 @@
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View file

@ -1,15 +1,12 @@
{ {
"name": "llama-bot-web-interface", "name": "llama-bot-web-interface",
"homepage": "https://llama-bot.github.io/llama-bot-web-interface",
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "react-scripts start", "start": "yarn build && firebase serve",
"build": "react-scripts build", "build": "react-scripts build",
"test": "react-scripts test", "test": "react-scripts test",
"analyze": "source-map-explorer 'build/static/js/*.js'", "analyze": "source-map-explorer 'build/static/js/*.js'"
"predeploy": "yarn build",
"deploy": "gh-pages -d build"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.36", "@fortawesome/fontawesome-svg-core": "^1.2.36",
@ -17,6 +14,7 @@
"@fortawesome/free-solid-svg-icons": "^5.15.4", "@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.15", "@fortawesome/react-fontawesome": "^0.1.15",
"antd": "^4.16.13", "antd": "^4.16.13",
"axios": "^0.21.4",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-router-dom": "^5.3.0", "react-router-dom": "^5.3.0",
@ -34,14 +32,9 @@
"@types/react-dom": "^17.0.9", "@types/react-dom": "^17.0.9",
"@types/react-router-dom": "^5.1.8", "@types/react-router-dom": "^5.1.8",
"@types/styled-components": "^5.1.14", "@types/styled-components": "^5.1.14",
"gh-pages": "^3.2.3",
"pre-push": "^0.1.1",
"react-scripts": "^4.0.3", "react-scripts": "^4.0.3",
"source-map-explorer": "^2.5.2" "source-map-explorer": "^2.5.2"
}, },
"pre-push": [
"deploy"
],
"eslintConfig": { "eslintConfig": {
"extends": [ "extends": [
"react-app", "react-app",

View file

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After

View file

@ -1,11 +1,15 @@
import { Layout } from "antd" // import { useState } from "react"
import styled from "styled-components" // import { useHistory } from "react-router-dom"
import { Link } from "react-router-dom" import { useEffect, useState } from "react"
import styled from "styled-components"
import { Layout } from "antd"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons" import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons"
import axios from "axios"
const { Header } = Layout const { Header } = Layout
const StyledHeader = styled(Header)` const StyledHeader = styled(Header)`
@ -44,6 +48,21 @@ const StyledHeader = styled(Header)`
` `
const Navbar = () => { const Navbar = () => {
// const history = useHistory()
const [isLoggedIn, setIsLoggedIn] = useState(false)
const [userName, setUserName] = useState("")
useEffect(() => {
axios
.get("/api/user-data")
.then((data) => {
setIsLoggedIn(true)
setUserName(`${data.data.username}#${data.data.discriminator}`)
})
.catch()
}, [])
return ( return (
<StyledHeader style={{ color: "white", justifyItems: "space-between" }}> <StyledHeader style={{ color: "white", justifyItems: "space-between" }}>
<div> <div>
@ -70,7 +89,9 @@ const Navbar = () => {
<FontAwesomeIcon icon={faExternalLinkAlt} /> <FontAwesomeIcon icon={faExternalLinkAlt} />
</a> </a>
<div className="right"> <div className="right">
<Link to="/login">Login</Link> <a href="/api/login">
{isLoggedIn ? `Logged in as ${userName}` : "Login"}
</a>
</div> </div>
</StyledHeader> </StyledHeader>
) )

View file

@ -1,7 +1,7 @@
import React, { useState, Suspense, lazy } from "react" import React, { useState, Suspense, lazy } from "react"
import ReactDOM from "react-dom" import ReactDOM from "react-dom"
import { HashRouter, Switch, Route } from "react-router-dom" import { BrowserRouter, Switch, Route } from "react-router-dom"
import Loader from "react-spinners/CircleLoader" import Loader from "react-spinners/CircleLoader"
import { Layout } from "antd" import { Layout } from "antd"
@ -21,7 +21,6 @@ const Dashboard = lazy(() => import("./routes/Dashboard"))
const Modules = lazy(() => import("./routes/Modules")) const Modules = lazy(() => import("./routes/Modules"))
const Logs = lazy(() => import("./routes/Logs")) const Logs = lazy(() => import("./routes/Logs"))
const Incidents = lazy(() => import("./routes/Incidents")) const Incidents = lazy(() => import("./routes/Incidents"))
const Login = lazy(() => import("./routes/Login"))
const StyledSpinContainer = styled.div` const StyledSpinContainer = styled.div`
width: 100%; width: 100%;
@ -55,7 +54,7 @@ const App = () => {
<SidebarCollapsedContext.Provider <SidebarCollapsedContext.Provider
value={{ isSidebarCollapsed, setSidebarCollapsed }} value={{ isSidebarCollapsed, setSidebarCollapsed }}
> >
<HashRouter basename="/"> <BrowserRouter basename="/">
<Layout style={{ minHeight: "100vh" }}> <Layout style={{ minHeight: "100vh" }}>
<Layout className="site-layout"> <Layout className="site-layout">
<Navbar /> <Navbar />
@ -98,9 +97,6 @@ const App = () => {
<Route exact path="/incidents"> <Route exact path="/incidents">
<Incidents /> <Incidents />
</Route> </Route>
<Route exact path="/login">
<Login />
</Route>
</Switch> </Switch>
</Suspense> </Suspense>
</div> </div>
@ -109,7 +105,7 @@ const App = () => {
<Footer /> <Footer />
</Layout> </Layout>
</Layout> </Layout>
</HashRouter> </BrowserRouter>
</SidebarCollapsedContext.Provider> </SidebarCollapsedContext.Provider>
</> </>
) )

View file

@ -2884,7 +2884,7 @@ async@0.9.x:
resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=
async@^2.6.1, async@^2.6.2: async@^2.6.2:
version "2.6.3" version "2.6.3"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
@ -2934,6 +2934,13 @@ axe-core@^4.0.2:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.2.tgz#7cf783331320098bfbef620df3b3c770147bc224" resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.2.tgz#7cf783331320098bfbef620df3b3c770147bc224"
integrity sha512-V+Nq70NxKhYt89ArVcaNL9FDryB3vQOd+BFXZIfO3RP6rwtj+2yqqqdHEkacutglPaZLkJeuXKCjCJDMGPtPqg== integrity sha512-V+Nq70NxKhYt89ArVcaNL9FDryB3vQOd+BFXZIfO3RP6rwtj+2yqqqdHEkacutglPaZLkJeuXKCjCJDMGPtPqg==
axios@^0.21.4:
version "0.21.4"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575"
integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==
dependencies:
follow-redirects "^1.14.0"
axobject-query@^2.2.0: axobject-query@^2.2.0:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
@ -3803,7 +3810,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies: dependencies:
delayed-stream "~1.0.0" delayed-stream "~1.0.0"
commander@^2.18.0, commander@^2.20.0: commander@^2.20.0:
version "2.20.3" version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@ -4741,11 +4748,6 @@ elliptic@^6.5.3:
minimalistic-assert "^1.0.1" minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1" minimalistic-crypto-utils "^1.0.1"
email-addresses@^3.0.1:
version "3.1.0"
resolved "https://registry.yarnpkg.com/email-addresses/-/email-addresses-3.1.0.tgz#cabf7e085cbdb63008a70319a74e6136188812fb"
integrity sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==
emittery@^0.7.1: emittery@^0.7.1:
version "0.7.2" version "0.7.2"
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82"
@ -4922,7 +4924,7 @@ escape-string-regexp@2.0.0, escape-string-regexp@^2.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: escape-string-regexp@^1.0.5:
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
@ -5442,20 +5444,6 @@ filelist@^1.0.1:
dependencies: dependencies:
minimatch "^3.0.4" minimatch "^3.0.4"
filename-reserved-regex@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229"
integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik=
filenamify@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-4.3.0.tgz#62391cb58f02b09971c9d4f9d63b3cf9aba03106"
integrity sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==
dependencies:
filename-reserved-regex "^2.0.0"
strip-outer "^1.0.1"
trim-repeated "^1.0.0"
filesize@6.1.0: filesize@6.1.0:
version "6.1.0" version "6.1.0"
resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.1.0.tgz#e81bdaa780e2451d714d71c0d7a4f3238d37ad00" resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.1.0.tgz#e81bdaa780e2451d714d71c0d7a4f3238d37ad00"
@ -5562,6 +5550,11 @@ follow-redirects@^1.0.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.2.tgz#dd73c8effc12728ba5cf4259d760ea5fb83e3147" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.2.tgz#dd73c8effc12728ba5cf4259d760ea5fb83e3147"
integrity sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA== integrity sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==
follow-redirects@^1.14.0:
version "1.14.3"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.3.tgz#6ada78118d8d24caee595595accdc0ac6abd022e"
integrity sha512-3MkHxknWMUtb23apkgz/83fDoe+y+qr0TdgacGIA7bew+QLBo3vdgEN2xEsuXNivpFy4CyDhBBZnNZOtalmenw==
for-in@^1.0.2: for-in@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@ -5747,19 +5740,6 @@ getpass@^0.1.1:
dependencies: dependencies:
assert-plus "^1.0.0" assert-plus "^1.0.0"
gh-pages@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/gh-pages/-/gh-pages-3.2.3.tgz#897e5f15e111f42af57d21d430b83e5cdf29472c"
integrity sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==
dependencies:
async "^2.6.1"
commander "^2.18.0"
email-addresses "^3.0.1"
filenamify "^4.3.0"
find-cache-dir "^3.3.1"
fs-extra "^8.1.0"
globby "^6.1.0"
glob-parent@^3.1.0: glob-parent@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
@ -9326,13 +9306,6 @@ postcss@^8.1.0:
nanoid "^3.1.20" nanoid "^3.1.20"
source-map "^0.6.1" source-map "^0.6.1"
pre-push@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/pre-push/-/pre-push-0.1.1.tgz#2a2a79827d243a76c91089897ac707f45e716aac"
integrity sha1-Kip5gn0kOnbJEImJescH9F5xaqw=
dependencies:
shelljs "0.3.x"
prelude-ls@^1.2.1: prelude-ls@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
@ -10847,11 +10820,6 @@ shell-quote@1.7.2:
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2"
integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==
shelljs@0.3.x:
version "0.3.0"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1"
integrity sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=
shellwords@^0.1.1: shellwords@^0.1.1:
version "0.1.1" version "0.1.1"
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
@ -11341,13 +11309,6 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
strip-outer@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631"
integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==
dependencies:
escape-string-regexp "^1.0.2"
style-loader@1.3.0: style-loader@1.3.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e"
@ -11684,13 +11645,6 @@ tr46@^2.0.2:
dependencies: dependencies:
punycode "^2.1.1" punycode "^2.1.1"
trim-repeated@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21"
integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE=
dependencies:
escape-string-regexp "^1.0.2"
tryer@^1.0.1: tryer@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"

30
functions/.eslintrc.js Normal file
View file

@ -0,0 +1,30 @@
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,
},
}

6
functions/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
# Compiled JavaScript files
/lib
# sevrets
/src/secret.json
/src/firebase-adminsdk.json

10811
functions/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

44
functions/package.json Normal file
View file

@ -0,0 +1,44 @@
{
"name": "functions",
"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"
},
"engines": {
"node": "14"
},
"main": "lib/index.js",
"dependencies": {
"cookie-session": "^1.4.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-session": "^1.17.2",
"firebase": "^9.0.2",
"firebase-admin": "^9.11.1",
"firebase-functions": "^3.15.5",
"passport": "^0.4.1",
"passport-discord": "^0.1.4"
},
"devDependencies": {
"@types/cookie-session": "^2.0.43",
"@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": "^4.31.0",
"@typescript-eslint/parser": "^4.31.0",
"eslint": "^7.32.0",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.24.2",
"firebase-functions-test": "^0.3.2",
"typescript": "^4.4.3"
},
"private": true
}

View file

@ -0,0 +1,47 @@
import admin, { firestore } from "firebase-admin"
import { logger } from "firebase-functions"
interface DatabaseResult {
success: boolean
error?: string
}
interface UserResult extends DatabaseResult {
user?: Express.User | FirebaseFirestore.DocumentData
}
export default {
findUser: async (uid: string): Promise<UserResult> => {
let result
try {
const user = await admin.firestore().collection("users").doc(uid).get()
result = user.exists
? { success: true, user: user.data() }
: { success: false, error: `user with uid ${uid} does not exist` }
} catch (error) {
logger.error("Error finding user", error)
result = { success: false, error: error.message }
}
return result
},
newUser: async (profile: Express.User): Promise<UserResult> => {
let result
try {
const newUserData = {
avatar: profile.avatar,
discriminator: profile.discriminator,
email: profile.email,
id: profile.id,
username: profile.username,
}
await firestore().doc(`/users/${profile.id}`).set(newUserData)
result = { success: true, user: newUserData }
} catch (error) {
logger.error("Error creating user", error)
result = { success: false, error: error.message }
}
return result
},
}

View file

@ -0,0 +1,5 @@
{
"pathPrefix": "/api",
"region": "us-central1",
"scopes": ["identify", "email", "guilds"]
}

40
functions/src/index.ts Normal file
View file

@ -0,0 +1,40 @@
import admin from "firebase-admin"
import { https } from "firebase-functions"
import express from "express"
import expressSession from "express-session"
import passport from "passport"
import cors from "cors"
import authRoutes from "./routes/authRoutes"
import dataRoutes from "./routes/dataRoutes"
import secret from "./secret.json"
import serviceAccountKey from "./firebase-adminsdk.json"
import "./services/discordOauth"
const app = express()
app.use(
cors({ origin: ["https://llama.developomp.com", "http://localhost:5000"] })
)
app.use(
expressSession({
secret: secret.session,
resave: true,
saveUninitialized: false,
})
)
app.use(passport.initialize())
app.use(passport.session())
dataRoutes(app)
authRoutes(app)
admin.initializeApp({
credential: admin.credential.cert(serviceAccountKey as admin.ServiceAccount),
})
export const api = https.onRequest(app)

View file

@ -0,0 +1,29 @@
/*
* Handle authentication
*/
import { Express } from "express"
import passport from "passport"
import config from "../config.json"
export default (app: Express): void => {
app.get(
config.pathPrefix + "/login",
passport.authenticate("discord", { scope: config.scopes })
)
app.get(config.pathPrefix + "/logout", (req, res) => {
req.logout()
res.redirect("/")
})
// OAuth2 callback
app.get(
config.pathPrefix + "/auth",
passport.authenticate("discord"),
(_, res) => {
res.redirect("/")
}
)
}

View file

@ -0,0 +1,24 @@
/*
* Handle firestore read/writes related to discord bot
*/
import { Express, Request, Response, NextFunction } from "express"
import config from "../config.json"
const checkIfLoggedIn = (req: Request, res: Response, next: NextFunction) => {
if (req.isAuthenticated() && req.user) return next()
res.status(401).send()
}
export default (app: Express): void => {
app.get(
config.pathPrefix + "/user-data",
checkIfLoggedIn,
async (req, res) => {
req.user
? res.status(200).send(req.user)
: res.status(500).send("Failed to get user")
}
)
}

View file

@ -0,0 +1,73 @@
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) => {
done(null, user.id)
})
passport.deserializeUser(async (id: string, done) => {
try {
const user = await database.findUser(id)
if (user.success === true) {
done(null, user.user as Express.User)
} else {
done(null)
}
} catch (error) {
logger.error("Error deserializing user", error.message)
done(error)
}
database
.findUser(id)
.then((user) => {
done(null, user.user as Express.User)
})
.catch((error) => {
logger.error("Error deserializing user", error.message)
})
})
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 searchUserResult = await database.findUser(profile.id)
// check if user already exists
if (searchUserResult.success && searchUserResult.user) {
done(null, searchUserResult.user as Express.User)
return searchUserResult.user
} else {
const newUser: Express.User = {
...profile,
token: accessToken,
refreshToken: refreshToken,
}
await database.newUser(newUser)
return done(null, newUser)
}
} catch (error) {
return logger.error("Error creating a user", error)
}
}
)
)

13
functions/src/types/express.d.ts vendored Normal file
View file

@ -0,0 +1,13 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import PassportDiscord from "passport-discord"
declare global {
namespace Express {
export interface User extends PassportDiscord.Profile {
token: string
refreshToken: string
}
}
}
export {}

View file

@ -0,0 +1,3 @@
{
"include": [".eslintrc.js"]
}

16
functions/tsconfig.json Normal file
View file

@ -0,0 +1,16 @@
{
"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"]
}

View file

@ -1,11 +0,0 @@
import { Component } from "react"
export default class Login extends Component {
render() {
return (
<>
<h2>Login</h2>
</>
)
}
}