Expand server and invite management, expose invite logs

This commit is contained in:
Gabriel Simmer 2022-07-06 15:09:07 +01:00
parent c15f3f70ab
commit 7f7a601a49
3 changed files with 199 additions and 10 deletions

View file

@ -25,15 +25,19 @@ func main() {
// API endpoints // API endpoints
mux.Group(func(mux *flow.Mux) { mux.Group(func(mux *flow.Mux) {
mux.Use(handlers.Cors) mux.Use(handlers.Cors)
mux.HandleFunc("/api/v1/invite/:id", handlers.GetInvite, "GET", "DELETE") mux.HandleFunc("/api/v1/invite/:id", handlers.GetInvite, "GET")
mux.Use(handlers.SessionAuth) mux.Use(handlers.SessionAuth)
mux.HandleFunc("/api/v1/me", handlers.CurrentUser, "GET") mux.HandleFunc("/api/v1/me", handlers.CurrentUser, "GET")
mux.HandleFunc("/api/v1/invites", handlers.CreateInvite, "POST") mux.HandleFunc("/api/v1/invites", handlers.CreateInvite, "POST")
mux.HandleFunc("/api/v1/invite/:id/accept", handlers.AcceptInvite, "POST") mux.HandleFunc("/api/v1/invite/:id/accept", handlers.AcceptInvite, "POST")
mux.HandleFunc("/api/v1/invite/:id/log", handlers.InviteLog, "GET")
mux.HandleFunc("/api/v1/invite/:id", handlers.DeleteInvite, "DELETE")
mux.HandleFunc("/api/v1/servers", handlers.Server, "GET", "POST") mux.HandleFunc("/api/v1/servers", handlers.Servers, "GET", "POST")
mux.HandleFunc("/api/v1/server/:id", handlers.Server, "GET", "DELETE")
mux.HandleFunc("/api/v1/server/:id/invites", handlers.ServerInvites, "GET")
}) })
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

View file

@ -26,8 +26,10 @@ type Storer interface {
GetServer(id string) (Server, error) GetServer(id string) (Server, error)
SaveServer(server Server) error SaveServer(server Server) error
GetUserServers(user User) ([]Server, error) GetUserServers(user User) ([]Server, error)
DeleteServer(server Server, user User) error
LogInviteUse(user string, invite Invite) error LogInviteUse(user string, invite Invite) error
InviteLog(invite Invite) ([]InviteLog, error) InviteLog(invite Invite) ([]InviteLog, error)
DeleteInvite(invite Invite) error
GetUser(uid string) (User, error) GetUser(uid string) (User, error)
SaveUser(user User) error SaveUser(user User) error
SaveSession(token string, user User) error SaveSession(token string, user User) error
@ -35,6 +37,7 @@ type Storer interface {
SaveOauthState(state OauthState) error SaveOauthState(state OauthState) error
OauthState(id string) (OauthState, error) OauthState(id string) (OauthState, error)
Close() error Close() error
ServerInvites(server Server) ([]Invite, error)
} }
type OauthState struct { type OauthState struct {
@ -78,6 +81,12 @@ type Session struct {
Expiry time.Time Expiry time.Time
} }
type InviteLog struct {
EntryID string `json:"entry_id"`
Invite Invite `json:"invite"`
User User `json:"user"`
}
func Open() (*Store, error) { func Open() (*Store, error) {
database := os.Getenv("WLM_DATABASE_PATH") database := os.Getenv("WLM_DATABASE_PATH")
if database == "" { if database == "" {
@ -165,12 +174,6 @@ func (s *Store) LogInviteUse(user string, invite Invite) error {
return err return err
} }
type InviteLog struct {
EntryID string
Invite string
User string
}
func (s *Store) InviteLog(invite Invite) ([]InviteLog, error) { func (s *Store) InviteLog(invite Invite) ([]InviteLog, error) {
q, err := s.database.Query("SELECT * FROM invite_log WHERE invite=$1", invite.Token) q, err := s.database.Query("SELECT * FROM invite_log WHERE invite=$1", invite.Token)
if err != nil { if err != nil {
@ -180,10 +183,15 @@ func (s *Store) InviteLog(invite Invite) ([]InviteLog, error) {
var log []InviteLog var log []InviteLog
for q.Next() { for q.Next() {
var logEntry InviteLog var logEntry InviteLog
err := q.Scan(&logEntry.EntryID, &logEntry.Invite, &logEntry.User) err := q.Scan(&logEntry.EntryID, &logEntry.Invite.Token, &logEntry.User.Id)
if err != nil { if err != nil {
continue continue
} }
user, err := s.GetUser(logEntry.User.Id)
if err != nil {
continue
}
logEntry.User = user
log = append(log, logEntry) log = append(log, logEntry)
} }
@ -354,3 +362,62 @@ func (s *Store) OauthState(id string) (OauthState, error) {
func (s *Store) Close() error { func (s *Store) Close() error {
return s.database.Close() return s.database.Close()
} }
func (s *Store) ServerInvites(server Server) ([]Invite, error) {
q, err := s.database.Query("SELECT * FROM invites WHERE server=$1", server.Id)
if err != nil {
return []Invite{}, err
}
var invites []Invite
for q.Next() {
var invite Invite
err = q.Scan(&invite.Token, &invite.Creator.Id, &invite.Server.Id, &invite.Uses, &invite.Unlimited)
if err != nil {
continue
}
invites = append(invites, invite)
}
return invites, nil
}
func (s *Store) DeleteInvite(invite Invite) error {
inviteDeleteQuery, err := s.database.Prepare("DELETE FROM invites WHERE token=$1")
if err != nil {
return err
}
_, err = s.database.Exec("DELETE FROM invite_log WHERE invite=$1", invite.Token)
if err != nil {
return err
}
_, err = inviteDeleteQuery.Exec(invite.Token)
if err != nil {
return err
}
return nil
}
func (s *Store) DeleteServer(server Server, user User) error {
serverDeleteQuery, err := s.database.Prepare("DELETE FROM servers WHERE id=$1 AND owner=$2")
if err != nil {
return err
}
serverInvites, err := s.ServerInvites(server)
if err != nil {
return err
}
for _, invite := range serverInvites {
err = s.DeleteInvite(invite)
if err != nil {
continue
}
}
_, err = serverDeleteQuery.Exec(server.Id, user.Id)
if err != nil {
return err
}
return nil
}

View file

@ -29,10 +29,16 @@ type Handle interface {
CurrentUser(w http.ResponseWriter, r *http.Request) CurrentUser(w http.ResponseWriter, r *http.Request)
CreateInvite(w http.ResponseWriter, r *http.Request) CreateInvite(w http.ResponseWriter, r *http.Request)
GetInvite(w http.ResponseWriter, r *http.Request) GetInvite(w http.ResponseWriter, r *http.Request)
DeleteInvite(w http.ResponseWriter, r *http.Request)
AcceptInvite(w http.ResponseWriter, r *http.Request) AcceptInvite(w http.ResponseWriter, r *http.Request)
AuthRedirect(w http.ResponseWriter, r *http.Request) AuthRedirect(w http.ResponseWriter, r *http.Request)
AuthCallback(w http.ResponseWriter, r *http.Request) AuthCallback(w http.ResponseWriter, r *http.Request)
Server(w http.ResponseWriter, r *http.Request)
Servers(w http.ResponseWriter, r *http.Request)
CreateServer(w http.ResponseWriter, r *http.Request) CreateServer(w http.ResponseWriter, r *http.Request)
DeleteServer(w http.ResponseWriter, r *http.Request)
ServerInvites(w http.ResponseWriter, r *http.Request)
InviteLog(w http.ResponseWriter, r *http.Request)
} }
func New(store store.Storer) *Handler { func New(store store.Storer) *Handler {
@ -239,7 +245,7 @@ func generateSessionToken() (string, error) {
return base64.URLEncoding.EncodeToString(b), err return base64.URLEncoding.EncodeToString(b), err
} }
func (h *Handler) Server(w http.ResponseWriter, r *http.Request) { func (h *Handler) Servers(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value("user").(store.User) user := r.Context().Value("user").(store.User)
if r.Method == http.MethodGet { if r.Method == http.MethodGet {
servers, err := h.store.GetUserServers(user) servers, err := h.store.GetUserServers(user)
@ -268,6 +274,49 @@ func (h *Handler) Server(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "created server %s", server.Id) fmt.Fprintf(w, "created server %s", server.Id)
} }
func (h *Handler) Server(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value("user").(store.User)
serverId := flow.Param(r.Context(), "id")
if r.Method == http.MethodGet {
server, err := h.store.GetServer(serverId)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if server.Owner.Id != user.Id {
http.Error(w, "not owner of server", http.StatusForbidden)
return
}
json.NewEncoder(w).Encode(server)
return
}
if r.Method == http.MethodDelete {
serverId := flow.Param(r.Context(), "id")
user := r.Context().Value("user").(store.User)
server, err := h.store.GetServer(serverId)
if err != nil {
http.Error(w, "no such server", http.StatusNotFound)
return
}
if server.Owner.Id != user.Id {
http.Error(w, "user not server owner", http.StatusForbidden)
return
}
err = h.store.DeleteServer(server, user)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write([]byte("deleted"))
}
}
func (h *Handler) CurrentUser(w http.ResponseWriter, r *http.Request) { func (h *Handler) CurrentUser(w http.ResponseWriter, r *http.Request) {
value := r.Context().Value("user") value := r.Context().Value("user")
if value == nil { if value == nil {
@ -277,3 +326,72 @@ func (h *Handler) CurrentUser(w http.ResponseWriter, r *http.Request) {
user := value.(store.User) user := value.(store.User)
w.Write([]byte(user.DisplayName)) w.Write([]byte(user.DisplayName))
} }
func (h *Handler) ServerInvites(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value("user").(store.User)
serverId := flow.Param(r.Context(), "id")
server, err := h.store.GetServer(serverId)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if server.Owner.Id != user.Id {
http.Error(w, "not owner of server", http.StatusForbidden)
return
}
serverInvites, err := h.store.ServerInvites(server)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if server.Owner.Id != user.Id {
http.Error(w, "not owner of server", http.StatusForbidden)
return
}
json.NewEncoder(w).Encode(serverInvites)
return
}
func (h *Handler) InviteLog(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value("user").(store.User)
inviteToken := flow.Param(r.Context(), "id")
invite, err := h.store.GetInvite(inviteToken)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if invite.Creator.Id != user.Id {
http.Error(w, "not owner of invite", http.StatusForbidden)
return
}
logs, err := h.store.InviteLog(invite)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(logs)
}
func (h *Handler) DeleteInvite(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value("user").(store.User)
inviteToken := flow.Param(r.Context(), "id")
invite, err := h.store.GetInvite(inviteToken)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if invite.Creator.Id != user.Id {
http.Error(w, "not owner of invite", http.StatusForbidden)
return
}
err = h.store.DeleteInvite(invite)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write([]byte("deleted"))
}