the shrimplest admin api you've ever seen
Signed-off-by: ari melody <ari@arimelody.me>
This commit is contained in:
parent
1cbcece3d2
commit
c5a2491627
20
api/api.go
Normal file
20
api/api.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"html/template"
|
||||||
|
|
||||||
|
"arimelody.me/arimelody.me/api/v1/admin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Handle(writer http.ResponseWriter, req *http.Request, root *template.Template) int {
|
||||||
|
code := 404;
|
||||||
|
if req.URL.Path == "/api/v1/admin/login" {
|
||||||
|
code = admin.HandleLogin(writer, req, root)
|
||||||
|
}
|
||||||
|
|
||||||
|
if code == 404 {
|
||||||
|
writer.Write([]byte("404 not found"))
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
43
api/v1/admin/admin.go
Normal file
43
api/v1/admin/admin.go
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
State struct {
|
||||||
|
Token string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateState() *State {
|
||||||
|
return &State{
|
||||||
|
Token: "you are the WINRAR!!",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleLogin(writer http.ResponseWriter, req *http.Request, root *template.Template) int {
|
||||||
|
if req.Method != "POST" {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("failed to parse request body!\n");
|
||||||
|
return 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(body) != "super epic mega gaming password" {
|
||||||
|
return 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
state := CreateState();
|
||||||
|
|
||||||
|
writer.WriteHeader(200);
|
||||||
|
writer.Write([]byte(state.Token))
|
||||||
|
|
||||||
|
return 200;
|
||||||
|
}
|
43
main.go
43
main.go
|
@ -1,20 +1,21 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"arimelody.me/arimelody.me/api/v1/music"
|
"arimelody.me/arimelody.me/api"
|
||||||
|
"arimelody.me/arimelody.me/api/v1/music"
|
||||||
|
|
||||||
"github.com/gomarkdown/markdown"
|
"github.com/gomarkdown/markdown"
|
||||||
"github.com/gomarkdown/markdown/html"
|
"github.com/gomarkdown/markdown/html"
|
||||||
"github.com/gomarkdown/markdown/parser"
|
"github.com/gomarkdown/markdown/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
const PORT int = 8080
|
const PORT int = 8080
|
||||||
|
@ -94,6 +95,14 @@ func handle_request(writer http.ResponseWriter, req *http.Request) {
|
||||||
return music_gateway_handler(writer, req, root)
|
return music_gateway_handler(writer, req, root)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(uri, "/admin") {
|
||||||
|
return admin_handler(writer, req, root)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(uri, "/api") {
|
||||||
|
return api.Handle(writer, req, root)
|
||||||
|
}
|
||||||
|
|
||||||
return static_handler(writer, req, root)
|
return static_handler(writer, req, root)
|
||||||
}(writer, req)
|
}(writer, req)
|
||||||
|
|
||||||
|
@ -138,6 +147,16 @@ func music_gateway_handler(writer http.ResponseWriter, req *http.Request, root *
|
||||||
return 200
|
return 200
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func admin_handler(writer http.ResponseWriter, req *http.Request, root *template.Template) int {
|
||||||
|
admin_template := template.Must(root.ParseFiles("views/admin.html"))
|
||||||
|
err := admin_template.Execute(writer, nil)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
||||||
|
return 500
|
||||||
|
}
|
||||||
|
return 200
|
||||||
|
}
|
||||||
|
|
||||||
func static_handler(writer http.ResponseWriter, req *http.Request, root *template.Template) int {
|
func static_handler(writer http.ResponseWriter, req *http.Request, root *template.Template) int {
|
||||||
filename := "public/" + req.URL.Path[1:]
|
filename := "public/" + req.URL.Path[1:]
|
||||||
|
|
||||||
|
|
152
public/style/admin.css
Normal file
152
public/style/admin.css
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
@import url("/style/main.css");
|
||||||
|
|
||||||
|
main {
|
||||||
|
width: min(calc(100% - 4rem), 720px);
|
||||||
|
min-height: calc(100vh - 10.3rem);
|
||||||
|
margin: 0 auto 2rem auto;
|
||||||
|
padding-top: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
main h1 {
|
||||||
|
line-height: 3rem;
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
main h2 {
|
||||||
|
color: var(--secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
main h3 {
|
||||||
|
color: var(--tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
div#me_irl {
|
||||||
|
width: fit-content;
|
||||||
|
height: fit-content;
|
||||||
|
border: 2px solid white;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#me_irl img {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#me_irl::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 104px;
|
||||||
|
height: 104px;
|
||||||
|
transform: translate(2px, 2px);
|
||||||
|
background-image: linear-gradient(to top right,
|
||||||
|
var(--primary),
|
||||||
|
var(--secondary));
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
p,
|
||||||
|
small,
|
||||||
|
blockquote {
|
||||||
|
transition: background-color 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 a,
|
||||||
|
h2 a,
|
||||||
|
h3 a,
|
||||||
|
h4 a,
|
||||||
|
h5 a,
|
||||||
|
h6 a {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 a:hover,
|
||||||
|
h2 a:hover,
|
||||||
|
h3 a:hover,
|
||||||
|
h4 a:hover,
|
||||||
|
h5 a:hover,
|
||||||
|
h6 a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
main h1:hover,
|
||||||
|
main h2:hover,
|
||||||
|
main h3:hover,
|
||||||
|
main h4:hover,
|
||||||
|
main h5:hover,
|
||||||
|
main h6:hover,
|
||||||
|
main p:hover,
|
||||||
|
main small:hover,
|
||||||
|
main blockquote:hover {
|
||||||
|
background-color: #fff1;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin: 1rem 0;
|
||||||
|
padding: 0 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
text-align: center;
|
||||||
|
line-height: 0px;
|
||||||
|
border-width: 1px 0 0 0;
|
||||||
|
border-color: #888f;
|
||||||
|
margin: 1.5em 0;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.links {
|
||||||
|
display: flex;
|
||||||
|
gap: 1em .5em;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.links li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.links li a {
|
||||||
|
padding: .2em .5em;
|
||||||
|
border: 1px solid var(--links);
|
||||||
|
color: var(--links);
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: transparent;
|
||||||
|
transition-property: color, border-color, background-color;
|
||||||
|
transition-duration: .2s;
|
||||||
|
animation-delay: 0s;
|
||||||
|
animation: list-item-fadein .2s forwards;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.links li a:hover {
|
||||||
|
color: #eee;
|
||||||
|
border-color: #eee;
|
||||||
|
background-color: var(--links) !important;
|
||||||
|
text-decoration: none;
|
||||||
|
box-shadow: 0 0 1em var(--links);
|
||||||
|
}
|
||||||
|
|
||||||
|
div#web-buttons {
|
||||||
|
margin: 2rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#web-buttons a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#web-buttons img {
|
||||||
|
image-rendering: auto;
|
||||||
|
image-rendering: crisp-edges;
|
||||||
|
image-rendering: pixelated;
|
||||||
|
}
|
||||||
|
|
||||||
|
#web-buttons img:hover {
|
||||||
|
margin: -1px;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
transform: translate(-2px, -2px);
|
||||||
|
box-shadow: 1px 1px 0 #eee, 2px 2px 0 #eee;
|
||||||
|
}
|
||||||
|
|
20
views/admin.html
Normal file
20
views/admin.html
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{{define "head"}}
|
||||||
|
<title>admin - ari melody 💫</title>
|
||||||
|
<link rel="shortcut icon" href="/img/favicon.png" type="image/x-icon">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/style/admin.css">
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "content"}}
|
||||||
|
<main>
|
||||||
|
<script type="module" src="/script/admin.js" defer></script>
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
# admin panel
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
bappity boopity
|
||||||
|
</p>
|
||||||
|
</main>
|
||||||
|
{{end}}
|
Loading…
Reference in a new issue