diff --git a/api/serve.go b/api/serve.go index ca8142b..2078cdc 100644 --- a/api/serve.go +++ b/api/serve.go @@ -172,10 +172,28 @@ func MakeServer(argv *args.Arguments, dbConn *sql.DB) *http.Server { LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(hcaptcha.CaptchaVerificationContinuation, hcaptcha.CaptchaVerificationContinuation)(guestbook.SignGuestbookContinuation, FailurePassingContinuation)(guestbook.ListGuestbookContinuation, guestbook.ListGuestbookContinuation)(hcaptcha.CaptchaArgsContinuation, hcaptcha.CaptchaArgsContinuation)(template.TemplateContinuation("guestbook.html", true), template.TemplateContinuation("guestbook.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) }) - mux.HandleFunc("GET /{name}", func(w http.ResponseWriter, r *http.Request) { + /* + mux.HandleFunc("GET /kennel", func(w http.ResponseWriter, r *http.Request) { + requestContext := makeRequestContext() + LogRequestContinuation(requestContext, r, w)(kennel.GetKennelStateContinuation, kennel.GetKennelStateContinuation)(template.TemplateContinuation("kennel.json", true), template.TemplateContinuation("kennel.json", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) + }) + + mux.HandleFunc("GET /kennel/cats", func(w http.ResponseWriter, r *http.Request) { + requestContext := makeRequestContext() + LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(kennel.ListUserCats, auth.GoLoginContinuation)(template.TemplateContinuation("kennel_cats.html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) + }) + + + mux.HandleFunc("POST /kennel", func(w http.ResponseWriter, r *http.Request) { + requestContext := makeRequestContext() + LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(hcaptcha.CaptchaVerificationContinuation, hcaptcha.CaptchaVerificationContinuation)(guestbook.SignGuestbookContinuation, FailurePassingContinuation)(guestbook.ListGuestbookContinuation, guestbook.ListGuestbookContinuation)(hcaptcha.CaptchaArgsContinuation, hcaptcha.CaptchaArgsContinuation)(template.TemplateContinuation("guestbook.html", true), template.TemplateContinuation("guestbook.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) + }) + */ + + mux.HandleFunc("GET /{template}", func(w http.ResponseWriter, r *http.Request) { requestContext := makeRequestContext() - name := r.PathValue("name") - LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(IdContinuation, IdContinuation)(template.TemplateContinuation(name+".html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) + templateFile := r.PathValue("template") + LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(IdContinuation, IdContinuation)(template.TemplateContinuation(templateFile+".html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) }) return &http.Server{ diff --git a/database/kennel.go b/database/kennel.go new file mode 100644 index 0000000..39d664c --- /dev/null +++ b/database/kennel.go @@ -0,0 +1,137 @@ +package database + +import ( + "database/sql" + _ "github.com/mattn/go-sqlite3" + "log" + "time" +) + +type KennelCat struct { + ID string `json:"id"` + UserID string `json:"user_id"` + Link string `json:"link"` + Description string `json:"description"` + Spritesheet string `json:"spritesheet"` + CreatedAt time.Time `json:"created_at"` +} + +type KennelState struct { + At time.Time `json:"at"` + EncodedState string `json:"state"` +} + +func CountUserKennelCats(db *sql.DB, userID string) (int, error) { + log.Println("counting kennel cats for user", userID) + + row := db.QueryRow("SELECT COUNT(*) FROM kennel_cat WHERE user_id = ?", userID) + var count int + err := row.Scan(&count) + if err != nil { + return 0, err + } + return count, nil +} + +func GetUserKennelCats(db *sql.DB, userID string) ([]KennelCat, error) { + log.Println("getting kennel cats for user", userID) + + rows, err := db.Query("SELECT * FROM kennel_cat WHERE user_id = ?", userID) + if err != nil { + return nil, err + } + defer rows.Close() + + var cats []KennelCat + for rows.Next() { + var cat KennelCat + err := rows.Scan(&cat.ID, &cat.UserID, &cat.Link, &cat.Description, &cat.Spritesheet, &cat.CreatedAt) + if err != nil { + return nil, err + } + cats = append(cats, cat) + } + + return cats, nil +} + +func SaveKennelCat(db *sql.DB, cat *KennelCat) (*KennelCat, error) { + log.Println("saving kennel cat", cat.ID) + + if (cat.CreatedAt == time.Time{}) { + cat.CreatedAt = time.Now() + } + + _, err := db.Exec("INSERT OR REPLACE INTO kennel_cat (id, user_id, link, description, spritesheet, created_at) VALUES (?, ?, ?, ?, ?, ?)", cat.ID, cat.UserID, cat.Link, cat.Description, cat.Spritesheet, cat.CreatedAt) + + if err != nil { + return nil, err + } + return cat, nil +} + +func GetKennelCat(db *sql.DB, catID string) (*KennelCat, error) { + log.Println("getting kennel cat", catID) + + row := db.QueryRow("SELECT * FROM kennel_cat WHERE id = ?", catID) + var cat KennelCat + err := row.Scan(&cat.ID, &cat.UserID, &cat.Link, &cat.Description, &cat.Spritesheet, &cat.CreatedAt) + if err != nil { + return nil, err + } + return &cat, nil +} + +func DeleteKennelCat(db *sql.DB, catID string) error { + log.Println("deleting kennel cat", catID) + + _, err := db.Exec("DELETE FROM kennel_cat WHERE id = ?", catID) + if err != nil { + return err + } + return nil +} + +func GetKennel(dbConn *sql.DB) ([]KennelCat, error) { + log.Println("getting kennel") + + rows, err := dbConn.Query("SELECT * FROM kennel_cat") + if err != nil { + return nil, err + } + defer rows.Close() + + var cats []KennelCat + for rows.Next() { + var cat KennelCat + err := rows.Scan(&cat.ID, &cat.UserID, &cat.Link, &cat.Description, &cat.Spritesheet, &cat.CreatedAt) + if err != nil { + return nil, err + } + cats = append(cats, cat) + } + + return cats, nil +} + +func GetKennelState(dbConn *sql.DB) (*KennelState, error) { + log.Println("getting kennel state") + + row := dbConn.QueryRow("SELECT * FROM kennel_state") + var state KennelState + err := row.Scan(&state.At, &state.EncodedState) + if err != nil { + return nil, err + } + return &state, nil +} + +func SaveKennelState(dbConn *sql.DB, state *KennelState) (*KennelState, error) { + log.Println("saving kennel state") + + _, err := dbConn.Exec("INSERT OR REPLACE INTO kennel_state (at, state) VALUES (?, ?)", state.At, state.EncodedState) + if err != nil { + return nil, err + } + return state, nil +} diff --git a/database/migrate.go b/database/migrate.go index e9e21b7..363f022 100644 --- a/database/migrate.go +++ b/database/migrate.go @@ -162,6 +162,33 @@ func MigrateProfiles(dbConn *sql.DB) (*sql.DB, error) { return dbConn, nil } +func MigrateKennel(dbConn *sql.DB) (*sql.DB, error) { + log.Println("migrating kennel tables") + + _, err := dbConn.Exec(`CREATE TABLE IF NOT EXISTS kennel_cat ( + id TEXT PRIMARY KEY, + user_id INTEGER NOT NULL, + link TEXT NOT NULL, + description TEXT NOT NULL, + spritesheet TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE + );`) + if err != nil { + return dbConn, err + } + + _, err = dbConn.Exec(`CREATE TABLE IF NOT EXISTS kennel_state ( + at LONG INTEGER PRIMARY KEY, + encoded_state TEXT NOT NULL + );`) + if err != nil { + return dbConn, err + } + + return dbConn, nil +} + func Migrate(dbConn *sql.DB) (*sql.DB, error) { log.Println("migrating database") @@ -173,6 +200,7 @@ func Migrate(dbConn *sql.DB) (*sql.DB, error) { MigrateDNSRecords, MigrateGuestBook, MigrateProfiles, + MigrateKennel, } for _, migration := range migrations { diff --git a/static/css/styles.css b/static/css/styles.css index 886052e..24a76b9 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -18,32 +18,6 @@ font-family: "ComicSans", sans-serif; cursor: url("/static/img/cursor-1.png"), auto; - -webkit-animation: cursor 400ms infinite; - animation: cursor 400ms infinite; -} - -@-webkit-keyframes cursor { - 0% { - cursor: url("/static/img/cursor-2.png"), auto; - } - 50% { - cursor: url("/static/img/cursor-1.png"), auto; - } - 100% { - cursor: url("/static/img/cursor-2.png"), auto; - } -} - -@keyframes cursor { - 0% { - cursor: url("/static/img/cursor-2.png"), auto; - } - 50% { - cursor: url("/static/img/cursor-1.png"), auto; - } - 100% { - cursor: url("/static/img/cursor-2.png"), auto; - } } body { diff --git a/templates/about.html b/templates/about.html index 3c4c265..9e96bfd 100644 --- a/templates/about.html +++ b/templates/about.html @@ -2,18 +2,16 @@
hatecomputers.club is a club for those that, well, hate computers!
we maintain a little homelab mesh for our own little computing community! as a member you'll have access to split-zone dns for our intranet as well as ownership to "*.USER.hatecomputers.club." for which you can do almost anything. we host, and plan to host, all kinds of stuff for each other :).
+we maintain a little homelab mesh for our own little computing community! as a member you'll have access to split-zone dns for our intranet as well as ownership to "*.USER.hatecomputers.club." for which you can do almost anything. we host, and plan to host, all kinds of stuff for each other :)
you may align with us if you believe any (or all) of the following:
type. | +name. | +content. | +ttl. | +internal. | +created. | +delete. | +
---|---|---|---|---|---|---|
no dns records found. | +||||||
{{ $record.Type }} | +{{ $record.Name }} | +{{ $record.Content }} | +{{ $record.TTL }} | +{{ $record.Internal }} | +{{ $record.CreatedAt }} | ++ + | +