diff --git a/go.work b/go.work index bf3a037c5d..d928918e51 100644 --- a/go.work +++ b/go.work @@ -3,4 +3,5 @@ go 1.21.7 use ( ./go ./web/barf/sapi + ./web/barf/frontend ) diff --git a/web/barf/default.nix b/web/barf/default.nix index 4dd2818984..3b78e5a433 100644 --- a/web/barf/default.nix +++ b/web/barf/default.nix @@ -6,4 +6,5 @@ { sapi = import ./sapi args; + frontend = import ./frontend args; } diff --git a/web/barf/frontend/default.nix b/web/barf/frontend/default.nix new file mode 100644 index 0000000000..972e0bd4cf --- /dev/null +++ b/web/barf/frontend/default.nix @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2024 Luke Granger-Brown +# +# SPDX-License-Identifier: Apache-2.0 + +{ pkgs, lib, ... }: + +pkgs.buildGoModule { + name = "barf-fe"; + src = lib.sourceByRegex ./. [".*\.go$" "go.mod" "go.sum" "static" "static/clipit" ".*/.*\.webm" ".*/.*\.png" ".*/.*\.wav" ".*/.*\.svg" ".*\.html"]; + vendorHash = "sha256:0w1k1ykga70af3643lky701kf27pfmgc3lhznfq1v32ww365w57f"; +} diff --git a/web/barf/frontend/frontend.go b/web/barf/frontend/frontend.go new file mode 100644 index 0000000000..33c2ee590a --- /dev/null +++ b/web/barf/frontend/frontend.go @@ -0,0 +1,173 @@ +package main + +import ( + "database/sql" + "embed" + "encoding/json" + "errors" + "flag" + "fmt" + "html/template" + "io" + "log" + "net/http" + "net/http/httputil" + "net/url" + + _ "github.com/mattn/go-sqlite3" +) + +var ( + serve = flag.String("serve", ":11111", "Port number.") + samBackend = flag.String("sam_backend", "http://localhost:11316", "Sam backend.") + dbPath = flag.String("db_path", "./db.db", "Path to database.") +) + +//go:embed index.html +var indexTmplBytes []byte + +//go:embed static +var staticFS embed.FS + +type application struct { + db *sql.DB + indexTmpl *template.Template +} + +type dataset struct { + CurrentPhase int `json:"currentPhase"` + CurrentPhaseDialog int `json:"currentPhaseDialog"` + AudioEnabled bool `json:"audioEnabled"` + Name string `json:"name"` + DiscordUsername string `json:"discordUsername"` + ReceiveEmail bool `json:"receiveEmail"` + Email string `json:"email"` + DateSat31August string `json:"dateSat31August"` + DateSat7September string `json:"dateSat7September"` + ActivityEscapeRoom string `json:"activityEscapeRoom"` + ActivityPub string `json:"activityPub"` + ActivityMeanGirlsTheMusical string `json:"activityMeanGirlsTheMusical"` + ActivityKaraoke string `json:"activityKaraoke"` + AccommodationRequired bool `json:"accommodationRequired"` + TravelCosts bool `json:"travelCosts"` + Misc string `json:"misc"` +} + +func (a *application) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + rw.WriteHeader(http.StatusNotFound) + fmt.Fprintf(rw, "Sorry, you need a key to access this application.\n") + return + } + + key := r.URL.Path[1:] + if r.Method == "PUT" { + body, err := io.ReadAll(r.Body) + if err != nil { + log.Printf("failed to read PUT body: %v", err) + http.Error(rw, "reading body failed", http.StatusInternalServerError) + return + } + var response dataset + if err := json.Unmarshal(body, &response); err != nil { + log.Printf("failed to unmarshal PUT dataset: %v", err) + http.Error(rw, "unmarshalling body failed", http.StatusBadRequest) + return + } + cleanedBody, err := json.Marshal(response) + if err != nil { + log.Printf("failed to remarshal PUT dataset: %v", err) + http.Error(rw, "remarshalling body failed", http.StatusBadRequest) + return + } + res, err := a.db.ExecContext(r.Context(), `UPDATE responses SET responses = ? WHERE key = ?`, string(cleanedBody), key) + if err != nil { + log.Printf("failed to update DB: %v", err) + http.Error(rw, "updating database failed", http.StatusInternalServerError) + return + } + rowCount, err := res.RowsAffected() + if err != nil { + log.Printf("determining affected rows: %v", err) + http.Error(rw, "updating database failed", http.StatusInternalServerError) + return + } else if rowCount == 0 { + log.Printf("no rows affected for key %v", key) + rw.WriteHeader(http.StatusNotFound) + fmt.Fprintf(rw, "Sorry, you need a key to access this application.\n") + return + } + rw.WriteHeader(http.StatusNoContent) + return + } + + var responseJSON *string + err := a.db.QueryRowContext(r.Context(), `select responses from responses where key = ?`, key).Scan(&responseJSON) + if errors.Is(err, sql.ErrNoRows) { + rw.WriteHeader(http.StatusNotFound) + fmt.Fprintf(rw, "Sorry, you need a key to access this application.\n") + return + } else if err != nil { + log.Printf("getting responses: %v", err) + http.Error(rw, "internal error getting responses", http.StatusInternalServerError) + return + } + + var responseJSONStr string + if responseJSON == nil { + responseJSONStr = "{}" + } else { + var response dataset + if err := json.Unmarshal([]byte(*responseJSON), &response); err != nil { + log.Printf("database key %v corrupt, not valid json?: %v", key, err) + http.Error(rw, "response data corrupt!", http.StatusInternalServerError) + return + } + if response.CurrentPhase >= 5 { + // Make sure people who have saved _completion_ start at the beginning. + response.CurrentPhase = 0 + response.CurrentPhaseDialog = 0 + } + responseJSONBytes, err := json.Marshal(response) + if err != nil { + log.Printf("couldn't reserialise database key %v: %v", key, err) + http.Error(rw, "something went wrong with reserialisation...", http.StatusInternalServerError) + return + } + responseJSONStr = string(responseJSONBytes) + } + + rw.Header().Set("Content-type", "text/html") + a.indexTmpl.Execute(rw, template.JS(responseJSONStr)) +} + +func main() { + flag.Parse() + + indexTmpl, err := template.New("index").Parse(string(indexTmplBytes)) + if err != nil { + log.Fatalf("parsing index template: %w", err) + } + + db, err := sql.Open("sqlite3", *dbPath) + if err != nil { + log.Fatal(err) + } + defer db.Close() + + app := &application{db: db, indexTmpl: indexTmpl} + + http.Handle("/", app) + + http.Handle("/static/", http.FileServer(http.FS(staticFS))) + + samBackendPath, err := url.Parse(*samBackend) + if err != nil { + log.Fatalf("parsing -sam_backend=%q: %w", *samBackend, err) + } + be := httputil.NewSingleHostReverseProxy(samBackendPath) + http.Handle("/sam", be) + + log.Printf("serving on %v", *serve) + log.Fatal(http.ListenAndServe(*serve, nil)) +} diff --git a/web/barf/frontend/go.mod b/web/barf/frontend/go.mod new file mode 100644 index 0000000000..73d6bee655 --- /dev/null +++ b/web/barf/frontend/go.mod @@ -0,0 +1,5 @@ +module hg.lukegb.com/lukegb/depot/web/barf/frontend + +go 1.21.7 + +require github.com/mattn/go-sqlite3 v1.14.22 diff --git a/web/barf/frontend/go.sum b/web/barf/frontend/go.sum new file mode 100644 index 0000000000..e8d092a96f --- /dev/null +++ b/web/barf/frontend/go.sum @@ -0,0 +1,2 @@ +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= diff --git a/web/barf/frontend/index.html b/web/barf/frontend/index.html new file mode 100644 index 0000000000..83e4a08105 --- /dev/null +++ b/web/barf/frontend/index.html @@ -0,0 +1,1435 @@ + + + + + + +BARF | Data Collection + + + + +
+ +
+
+
    +
  1. Introduction
  2. +
  3. Collecting information
  4. +
  5. Availability
  6. +
  7. Proposal
  8. +
  9. Accommodation and travel
  10. +
  11. Finishing up
  12. +
+ +

Setup will complete in approximately:
3 minutes

+
+
+
+

Experience the ultimate in Birthday Shenanigans

+

Building on the success of Birthday® 2022, BARF XP Professional provides the latest technologies to help plan another birthday party, while keeping your data safe from unauthorized access.

+

BARF Assistant helps keep you informed and entertained while filling in boring information. Built-in animations keep you aggravated and annoyed throughout the process.

+

If you need to encrypt your data, BARF XP Professional uses the latest in Transport Layer Security version 1.3, which has been improved to be better than the previous version in some way.

+
+
+ + +
+
+
+
BARF XP Professional Edition
+
+
+
+

Feck, lorem ipsum dolor sit amet. Quis custodies ipsos lorem ipsum dolor sit amet.

+
+
+
+
+
BARF XP Professional Edition
+
+

Introduction

+

You can customize various aspects of BARF before we get started.

+
interactive_space
+
+
+
+
+

You seem to be on a mobile device, or with a window that I arbitrarily decided was 'too small'. You might be better off using this application from a desktop or laptop, for the full BARF™ experience.

+
+

You can choose whether to have audio turned on, for the real BARF™ eXPerience. I won't force you to, but it'll be slightly funnier. Probably.

+
+
+

Note that the URL you were given is unique to you, so please don't share it.

+
+
+ +
+
+
+
+
BARF XP Professional Edition
+
+

Collecting information

+

Let's learn more about who you are.

+
interactive_space
+
+
+
+
+
+

Welcome to BARF, the Birthday Activities Registration Form.

+

Your responses will be saved as we go through, so you should be able to reload the page and resume from where you left off if something goes wrong.

+

Some user data is required, which will be deleted after the event:

+
+
+

BARF has suggested a name. If you wish to be called something else, you can correct it now.

+ +
+

To get in contact before and during the event, Discord will be used.

+
+

Provide a Discord username.

+ +
+
+
+ + +
+
+
+
+
BARF XP Professional Edition
+
+

Collecting information

+

Let's learn more about who you are.

+
interactive_space
+
+
+
+
+
+
+

Would you like to receive calendar invites to the events you're interested in?

+ +
+

If you want calendar invites, an email address must be provided.

+ +
+
+
+ + +
+
+
+
+
BARF XP Professional Edition
+
+

Availability

+

Check your calendar to ascertain your availability.

+
interactive_space
+
+
+
+
+
+
+

The following weekends are proposed - the main festivities will be on the Saturday until late.

+
+

Saturday 31st August/Sunday 1st September

+

+ + + +

+
+

Saturday 7th September/Sunday 8th September

+

+ + + +

+ +
+
+
+ + +
+
+
+
+
BARF XP Professional Edition
+
+

Proposal

+

Select the activities of interest.

+
interactive_space
+
+
+
+
+
+
+

The festivities will likely include the following activities. Select the ones you would be interested to attend:

+
+

Escape Room (2pmish-4:30pmish)

+

+ + + +

+
+

Pub/Socialising (4:30pmish-7pmish)

+

+ + + +

+
+

Mean Girls: The Musical (7:30pm-10pm)

+

+ + + +

+
+

Karaoke (10:30pm-12:30am)

+

+ + + +

+
+
+
+ + +
+
+
+
+
BARF XP Professional Edition
+
+

Accommodation & Travel

+

Room and board, or board to a room.

+
interactive_space
+
+
+
+
+
+
+

Will you need a hotel room on the Saturday night?

+ +
+

Do you need help covering travel costs into London?

+ +
+
+
+ + +
+
+
+
+
BARF XP Professional Edition
+
+

Final Comments

+

Free text to express yourself in. Go nuts.

+
interactive_space
+
+
+
+
+
+
+

Anything else that needs mentioning?

+ +
+
+
+ + +
+
+
+
+
+
Hello, I am the barf barf barf. Hello, I am the barf barf barf. Hello, I am the barf barf barf. Hello, I am the barf barf barf. Hello, I am the barf barf barf.
+ +
+

It's now safe to close this tab.

+
+ + + diff --git a/web/barf/frontend/static/agenticon.png b/web/barf/frontend/static/agenticon.png new file mode 100644 index 0000000000..009bf07272 Binary files /dev/null and b/web/barf/frontend/static/agenticon.png differ diff --git a/web/barf/frontend/static/audioenabled.wav b/web/barf/frontend/static/audioenabled.wav new file mode 100644 index 0000000000..d719495b0d Binary files /dev/null and b/web/barf/frontend/static/audioenabled.wav differ diff --git a/web/barf/frontend/static/calendaricon.png b/web/barf/frontend/static/calendaricon.png new file mode 100644 index 0000000000..61249bfcbc Binary files /dev/null and b/web/barf/frontend/static/calendaricon.png differ diff --git a/web/barf/frontend/static/check.svg b/web/barf/frontend/static/check.svg new file mode 100644 index 0000000000..1a5bc37ecb --- /dev/null +++ b/web/barf/frontend/static/check.svg @@ -0,0 +1,17 @@ + + + + diff --git a/web/barf/frontend/static/clipit/goodbye.webm b/web/barf/frontend/static/clipit/goodbye.webm new file mode 100644 index 0000000000..b1eef602a3 Binary files /dev/null and b/web/barf/frontend/static/clipit/goodbye.webm differ diff --git a/web/barf/frontend/static/clipit/headphones.webm b/web/barf/frontend/static/clipit/headphones.webm new file mode 100644 index 0000000000..e72f7c4879 Binary files /dev/null and b/web/barf/frontend/static/clipit/headphones.webm differ diff --git a/web/barf/frontend/static/clipit/intro.webm b/web/barf/frontend/static/clipit/intro.webm new file mode 100644 index 0000000000..192973112d Binary files /dev/null and b/web/barf/frontend/static/clipit/intro.webm differ diff --git a/web/barf/frontend/static/clipit/sleepy.webm b/web/barf/frontend/static/clipit/sleepy.webm new file mode 100644 index 0000000000..999815331a Binary files /dev/null and b/web/barf/frontend/static/clipit/sleepy.webm differ diff --git a/web/barf/frontend/static/clipit/tapscreen.webm b/web/barf/frontend/static/clipit/tapscreen.webm new file mode 100644 index 0000000000..ecee70550a Binary files /dev/null and b/web/barf/frontend/static/clipit/tapscreen.webm differ diff --git a/web/barf/frontend/static/clipit/writing.webm b/web/barf/frontend/static/clipit/writing.webm new file mode 100644 index 0000000000..52599f4f1e Binary files /dev/null and b/web/barf/frontend/static/clipit/writing.webm differ diff --git a/web/barf/frontend/static/emailicon.png b/web/barf/frontend/static/emailicon.png new file mode 100644 index 0000000000..9291ba3853 Binary files /dev/null and b/web/barf/frontend/static/emailicon.png differ diff --git a/web/barf/frontend/static/erroricon.png b/web/barf/frontend/static/erroricon.png new file mode 100644 index 0000000000..fd63ff6812 Binary files /dev/null and b/web/barf/frontend/static/erroricon.png differ diff --git a/web/barf/frontend/static/filmstripicon.png b/web/barf/frontend/static/filmstripicon.png new file mode 100644 index 0000000000..3151bb92a2 Binary files /dev/null and b/web/barf/frontend/static/filmstripicon.png differ diff --git a/web/barf/frontend/static/networkicon.png b/web/barf/frontend/static/networkicon.png new file mode 100644 index 0000000000..cf13cdf487 Binary files /dev/null and b/web/barf/frontend/static/networkicon.png differ diff --git a/web/barf/frontend/static/soundicon.png b/web/barf/frontend/static/soundicon.png new file mode 100644 index 0000000000..75275993e3 Binary files /dev/null and b/web/barf/frontend/static/soundicon.png differ diff --git a/web/barf/frontend/static/speechicon.png b/web/barf/frontend/static/speechicon.png new file mode 100644 index 0000000000..534080865c Binary files /dev/null and b/web/barf/frontend/static/speechicon.png differ