Expand server and invite management, expose invite logs
This commit is contained in:
parent
c15f3f70ab
commit
7f7a601a49
8
main.go
8
main.go
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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"))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue