diff --git a/README.md b/README.md index 7ac1702..64266ec 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,11 @@ easy! just `git clone` this repo and `go build` from the root. `arimelody-web(.e the webserver depends on some environment variables (don't worry about forgetting some; it'll be sure to bug you about them): -- `HTTP_DOMAIN`: the domain the webserver will use for generating oauth redirect URIs (default `https://arimelody.me`) +- `ARIMELODY_HTTP_DOMAIN`: the domain the webserver will use for generating oauth redirect URIs (default `https://arimelody.me`) +- `ARIMELODY_DB_HOST`: the host address of a postgres database. +- `ARIMELODY_DB_NAME`: the name of the database. +- `ARIMELODY_DB_USER`: the username for the database. +- `ARIMELODY_DB_PASS`: the password for the database. - `DISCORD_ADMIN`[^1]: the user ID of your discord account (discord auth is intended to be temporary, and will be replaced with its own auth system later) - `DISCORD_CLIENT`[^1]: the client ID of your discord OAuth application. - `DISCORD_SECRET`[^1]: the client secret of your discord OAuth application. diff --git a/api/uploads.go b/api/uploads.go index f2fe297..6e348d0 100644 --- a/api/uploads.go +++ b/api/uploads.go @@ -1,6 +1,7 @@ package api import ( + "arimelody-web/global" "bufio" "encoding/base64" "errors" @@ -15,6 +16,7 @@ func HandleImageUpload(data *string, directory string, filename string) (string, header := split[0] imageData, err := base64.StdEncoding.DecodeString(split[1]) ext, _ := strings.CutPrefix(header, "data:image/") + directory = filepath.Join(global.DATA_DIR, directory) switch ext { case "png": diff --git a/docker-compose.yml b/docker-compose.yml index e29b006..3f3e4a4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,8 +7,12 @@ services: volumes: - ./uploads:/app/uploads environment: - HTTP_DOMAIN: "https://arimelody.me" + ARIMELODY_PORT: 8080 + ARIMELODY_HTTP_DOMAIN: "https://arimelody.me" ARIMELODY_DB_HOST: db + ARIMELODY_DB_NAME: arimelody + ARIMELODY_DB_USER: arimelody + ARIMELODY_DB_PASS: fuckingpassword DISCORD_ADMIN: # your discord user ID. DISCORD_CLIENT: # your discord OAuth client ID. DISCORD_SECRET: # your discord OAuth secret. diff --git a/global/data.go b/global/data.go index fb641fc..f88d25f 100644 --- a/global/data.go +++ b/global/data.go @@ -3,6 +3,7 @@ package global import ( "fmt" "os" + "path/filepath" "strings" "github.com/jmoiron/sqlx" @@ -34,12 +35,31 @@ var Args = func() map[string]string { return args }() -var HTTP_DOMAIN = func() string { - domain := os.Getenv("HTTP_DOMAIN") +var HTTP_DOMAIN = func() string { + domain := os.Getenv("ARIMELODY_HTTP_DOMAIN") if domain == "" { return "https://arimelody.me" } return domain }() +var DATA_DIR = func() string { + dir, err := filepath.Abs(os.Getenv("ARIMELODY_DATA_DIR")) + if err != nil { + fmt.Printf("FATAL: Failed to get working directory: %s\n", err.Error()) + os.Exit(1) + } + if dir != "" { + os.MkdirAll(dir, os.ModePerm) + } else { + var err error + dir, err = os.Getwd() + if err != nil { + fmt.Printf("FATAL: Failed to get working directory: %s\n", err.Error()) + os.Exit(1) + } + } + return dir +}() + var DB *sqlx.DB diff --git a/main.go b/main.go index f87d36e..901dcbb 100644 --- a/main.go +++ b/main.go @@ -7,27 +7,46 @@ import ( "net/http" "os" "path/filepath" + "strconv" "time" "arimelody-web/admin" "arimelody-web/api" "arimelody-web/global" - "arimelody-web/view" "arimelody-web/templates" + "arimelody-web/view" "github.com/jmoiron/sqlx" _ "github.com/lib/pq" ) -const DEFAULT_PORT int = 8080 +const DEFAULT_PORT int64 = 8080 func main() { // initialise database connection var dbHost = os.Getenv("ARIMELODY_DB_HOST") - if dbHost == "" { dbHost = "127.0.0.1" } + var dbName = os.Getenv("ARIMELODY_DB_NAME") + var dbUser = os.Getenv("ARIMELODY_DB_USER") + var dbPass = os.Getenv("ARIMELODY_DB_PASS") + if dbHost == "" { + fmt.Fprintf(os.Stderr, "FATAL: ARIMELODY_DB_HOST not provided! Exiting...\n") + os.Exit(1) + } + if dbName == "" { + fmt.Fprintf(os.Stderr, "FATAL: ARIMELODY_DB_NAME not provided! Exiting...\n") + os.Exit(1) + } + if dbUser == "" { + fmt.Fprintf(os.Stderr, "FATAL: ARIMELODY_DB_USER not provided! Exiting...\n") + os.Exit(1) + } + if dbPass == "" { + fmt.Fprintf(os.Stderr, "FATAL: ARIMELODY_DB_PASS not provided! Exiting...\n") + os.Exit(1) + } var err error - global.DB, err = sqlx.Connect("postgres", "host=" + dbHost + " user=arimelody dbname=arimelody password=fuckingpassword sslmode=disable") + global.DB, err = sqlx.Connect("postgres", fmt.Sprintf("host=%s user=%s dbname=%s password=%s sslmode=disable", dbHost, dbUser, dbName, dbPass)) if err != nil { fmt.Fprintf(os.Stderr, "FATAL: Unable to create database connection pool: %v\n", err) os.Exit(1) @@ -39,7 +58,10 @@ func main() { // start the web server! mux := createServeMux() - port := DEFAULT_PORT + port, err := strconv.ParseInt(os.Getenv("ARIMELODY_PORT"), 10, 0) + if err != nil { + port = DEFAULT_PORT + } fmt.Printf("Now serving at http://127.0.0.1:%d\n", port) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), global.HTTPLog(mux))) } @@ -50,7 +72,7 @@ func createServeMux() *http.ServeMux { mux.Handle("/admin/", http.StripPrefix("/admin", admin.Handler())) mux.Handle("/api/", http.StripPrefix("/api", api.Handler())) mux.Handle("/music/", http.StripPrefix("/music", view.MusicHandler())) - mux.Handle("/uploads/", http.StripPrefix("/uploads", staticHandler("uploads"))) + mux.Handle("/uploads/", http.StripPrefix("/uploads", staticHandler(filepath.Join(global.DATA_DIR, "uploads")))) mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" || r.URL.Path == "/index.html" { err := templates.Pages["index"].Execute(w, nil) diff --git a/schema.sql b/schema.sql index 746511a..b2d48ee 100644 --- a/schema.sql +++ b/schema.sql @@ -1,18 +1,18 @@ -- -- Artists (should be applicable to all art) -- -CREATE TABLE public.artist ( +CREATE TABLE artist ( id character varying(64), name text NOT NULL, website text, avatar text ); -ALTER TABLE public.artist ADD CONSTRAINT artist_pk PRIMARY KEY (id); +ALTER TABLE artist ADD CONSTRAINT artist_pk PRIMARY KEY (id); -- -- Music releases -- -CREATE TABLE public.musicrelease ( +CREATE TABLE musicrelease ( id character varying(64) NOT NULL, visible bool DEFAULT false, title text NOT NULL, @@ -25,56 +25,56 @@ CREATE TABLE public.musicrelease ( copyright text, copyrightURL text ); -ALTER TABLE public.musicrelease ADD CONSTRAINT musicrelease_pk PRIMARY KEY (id); +ALTER TABLE musicrelease ADD CONSTRAINT musicrelease_pk PRIMARY KEY (id); -- -- Music links (external platform links under a release) -- -CREATE TABLE public.musiclink ( +CREATE TABLE musiclink ( release character varying(64) NOT NULL, name text NOT NULL, url text NOT NULL ); -ALTER TABLE public.musiclink ADD CONSTRAINT musiclink_pk PRIMARY KEY (release, name); +ALTER TABLE musiclink ADD CONSTRAINT musiclink_pk PRIMARY KEY (release, name); -- -- Music credits (artist credits under a release) -- -CREATE TABLE public.musiccredit ( +CREATE TABLE musiccredit ( release character varying(64) NOT NULL, artist character varying(64) NOT NULL, role text NOT NULL, is_primary boolean DEFAULT false ); -ALTER TABLE public.musiccredit ADD CONSTRAINT musiccredit_pk PRIMARY KEY (release, artist); +ALTER TABLE musiccredit ADD CONSTRAINT musiccredit_pk PRIMARY KEY (release, artist); -- -- Music tracks (tracks under a release) -- -CREATE TABLE public.musictrack ( +CREATE TABLE musictrack ( id uuid DEFAULT gen_random_uuid(), title text NOT NULL, description text, lyrics text, preview_url text ); -ALTER TABLE public.musictrack ADD CONSTRAINT musictrack_pk PRIMARY KEY (id); +ALTER TABLE musictrack ADD CONSTRAINT musictrack_pk PRIMARY KEY (id); -- -- Music release/track pairs -- -CREATE TABLE public.musicreleasetrack ( +CREATE TABLE musicreleasetrack ( release character varying(64) NOT NULL, track uuid NOT NULL, number integer NOT NULL ); -ALTER TABLE public.musicreleasetrack ADD CONSTRAINT musicreleasetrack_pk PRIMARY KEY (release, track); +ALTER TABLE musicreleasetrack ADD CONSTRAINT musicreleasetrack_pk PRIMARY KEY (release, track); -- -- Foreign keys -- -ALTER TABLE public.musiccredit ADD CONSTRAINT musiccredit_artist_fk FOREIGN KEY (artist) REFERENCES public.artist(id) ON DELETE CASCADE ON UPDATE CASCADE; -ALTER TABLE public.musiccredit ADD CONSTRAINT musiccredit_release_fk FOREIGN KEY (release) REFERENCES public.musicrelease(id) ON DELETE CASCADE; -ALTER TABLE public.musiclink ADD CONSTRAINT musiclink_release_fk FOREIGN KEY (release) REFERENCES public.musicrelease(id) ON UPDATE CASCADE ON DELETE CASCADE; -ALTER TABLE public.musicreleasetrack ADD CONSTRAINT music_pair_trackref_fk FOREIGN KEY (release) REFERENCES public.musicrelease(id) ON DELETE CASCADE; -ALTER TABLE public.musicreleasetrack ADD CONSTRAINT music_pair_releaseref_fk FOREIGN KEY (track) REFERENCES public.musictrack(id) ON DELETE CASCADE; +ALTER TABLE musiccredit ADD CONSTRAINT musiccredit_artist_fk FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE ON UPDATE CASCADE; +ALTER TABLE musiccredit ADD CONSTRAINT musiccredit_release_fk FOREIGN KEY (release) REFERENCES musicrelease(id) ON DELETE CASCADE; +ALTER TABLE musiclink ADD CONSTRAINT musiclink_release_fk FOREIGN KEY (release) REFERENCES musicrelease(id) ON UPDATE CASCADE ON DELETE CASCADE; +ALTER TABLE musicreleasetrack ADD CONSTRAINT music_pair_trackref_fk FOREIGN KEY (release) REFERENCES musicrelease(id) ON DELETE CASCADE; +ALTER TABLE musicreleasetrack ADD CONSTRAINT music_pair_releaseref_fk FOREIGN KEY (track) REFERENCES musictrack(id) ON DELETE CASCADE;