Skip to content

Commit

Permalink
Add invites
Browse files Browse the repository at this point in the history
  • Loading branch information
foodelevator committed Jul 13, 2024
1 parent 9d10e59 commit c517eba
Show file tree
Hide file tree
Showing 22 changed files with 1,076 additions and 70 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,8 @@ to `/oidc/kth/callback` that redirects the user further within this system and
then cookies must be sent, but from some local testing it seems they're not
since the user was (indirectly) redirected from KTH. Therefore they're set to
`Lax`.

## Database schema

The schema is defined by the migrations in `./pkg/database/migrations/`. A new
one can be created using `go run ./cmd/manage goose create $NAME sql`.
4 changes: 2 additions & 2 deletions islands/membershipUpload.island.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function MembershipUpload() {

setMessages([]);

let res = await fetch("/admin/upload-sheet", {
let res = await fetch("/admin/members/upload-sheet", {
method: "post",
headers: { "Content-Type": "application/octet-stream; charset=binary" },
body: fileInput.files?.[0],
Expand All @@ -20,7 +20,7 @@ function MembershipUpload() {
setMessages([{ msg: await res.text(), error: true }]);
return
}
let events = new EventSource("/admin/upload-sheet");
let events = new EventSource("/admin/members/upload-sheet");
events.addEventListener("error", () => {
events.close();
setProgress(null);
Expand Down
2 changes: 1 addition & 1 deletion islands/oidcClients.island.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function OidcClients() {
let [secret, setSecret] = createSignal<string | null>(null);

onMount(async () => {
let res = await fetch("/admin/oidc-clients");
let res = await fetch("/admin/list-oidc-clients");
if (res.status != 200) {
setError(await res.text());
return;
Expand Down
113 changes: 113 additions & 0 deletions pkg/database/invite.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions pkg/database/migrations/20240713201626_add_invites.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-- +goose Up
-- +goose StatementBegin
create table invites (
id uuid primary key default gen_random_uuid(),
name text not null,
created_at timestamp not null default now(),
expires_at timestamp not null,
max_uses int null,
current_uses int not null default 0
);
-- +goose StatementEnd

-- +goose Down
-- +goose StatementBegin
drop table invites;
-- +goose StatementEnd
9 changes: 9 additions & 0 deletions pkg/database/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions pkg/database/sql/invite.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-- name: ListInvites :many
select * from invites;

-- name: GetInvite :one
select * from invites where id = $1;

-- name: CreateInvite :one
insert into invites (
name,
expires_at,
max_uses
)
values ($1, $2, $3)
returning *;

-- name: DeleteInvite :exec
delete from invites
where id = $1;

-- name: IncrementInviteUses :exec
update invites
set current_uses = current_uses + 1
where id = $1;
67 changes: 35 additions & 32 deletions pkg/httputil/httputil.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,43 @@ import (

type ToResponse any

func Route(f func(w http.ResponseWriter, r *http.Request) ToResponse) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := f(w, r)
if resp == nil {
return
func Respond(resp ToResponse, w http.ResponseWriter, r *http.Request) {
if resp == nil {
return
}
switch resp.(type) {
case templ.Component:
resp.(templ.Component).Render(r.Context(), w)
case error:
err := resp.(error)
var httpErr HttpError
if errors.As(err, &httpErr) {
httpErr.ServeHTTP(w, r)
} else {
slog.Error("Error serving request", "path", r.URL.Path, "error", err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal server error"))
}
switch resp.(type) {
case templ.Component:
resp.(templ.Component).Render(r.Context(), w)
case error:
err := resp.(error)
var httpErr HttpError
if errors.As(err, &httpErr) {
httpErr.ServeHTTP(w, r)
} else {
slog.Error("Error serving request", "path", r.URL.Path, "error", err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal server error"))
}
case string:
s := resp.(string)
w.Write([]byte(s))
case http.Handler:
h := resp.(http.Handler)
h.ServeHTTP(w, r)
case jsonValue:
j := resp.(jsonValue).any
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(j); err != nil {
slog.Error("Error writing json", "value", j)
}
default:
slog.Error("Got invalid response type when serving request", "url", r.URL.String(), "response", resp)
case string:
s := resp.(string)
w.Write([]byte(s))
case http.Handler:
h := resp.(http.Handler)
h.ServeHTTP(w, r)
case jsonValue:
j := resp.(jsonValue).any
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(j); err != nil {
slog.Error("Error writing json", "value", j)
}
default:
slog.Error("Got invalid response type when serving request", "url", r.URL.String(), "response", resp)
}
}

func Route(f func(w http.ResponseWriter, r *http.Request) ToResponse) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Respond(f(w, r), w, r)
})
}

Expand Down
11 changes: 9 additions & 2 deletions services/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,20 @@ func NewService(db *database.Queries) (*service, error) {
s := &service{db: db}

http.Handle("GET /admin", s.auth(httputil.Route(s.admin)))
http.Handle("POST /admin/upload-sheet", s.auth(httputil.Route(s.uploadSheet)))
http.Handle("GET /admin/upload-sheet", s.auth(httputil.Route(s.processSheet)))

http.Handle("GET /admin/members", s.auth(httputil.Route(s.members)))
http.Handle("POST /admin/members/upload-sheet", s.auth(httputil.Route(s.uploadSheet)))
http.Handle("GET /admin/members/upload-sheet", s.auth(httputil.Route(s.processSheet)))

http.Handle("GET /admin/oidc-clients", s.auth(httputil.Route(s.oidcClients)))
http.Handle("GET /admin/list-oidc-clients", s.auth(httputil.Route(s.listOIDCClients)))
http.Handle("POST /admin/oidc-clients", s.auth(httputil.Route(s.createOIDCClient)))
http.Handle("DELETE /admin/oidc-clients/{id}", s.auth(httputil.Route(s.deleteOIDCClient)))

http.Handle("GET /admin/invites", s.auth(httputil.Route(s.invites)))
http.Handle("POST /admin/invites", s.auth(httputil.Route(s.createInvite)))
http.Handle("DELETE /admin/invites/{id}", s.auth(httputil.Route(s.deleteInvite)))

return s, nil
}

Expand Down
Loading

0 comments on commit c517eba

Please sign in to comment.