feat(backend): add DELETE /members/{id}

This commit is contained in:
Sam 2022-11-22 13:31:42 +01:00
parent 3aefe4fa88
commit 3b64ba33f6
4 changed files with 65 additions and 3 deletions

View File

@ -47,6 +47,7 @@ func (db *DB) Member(ctx context.Context, id xid.ID) (m Member, err error) {
return m, nil return m, nil
} }
// UserMember returns a member scoped by user.
func (db *DB) UserMember(ctx context.Context, userID xid.ID, memberRef string) (m Member, err error) { func (db *DB) UserMember(ctx context.Context, userID xid.ID, memberRef string) (m Member, err error) {
sql, args, err := sq.Select("*").From("members"). sql, args, err := sq.Select("*").From("members").
Where("user_id = ? and (id = ? or name = ?)", userID, memberRef, memberRef).ToSql() Where("user_id = ? and (id = ? or name = ?)", userID, memberRef, memberRef).ToSql()
@ -65,6 +66,7 @@ func (db *DB) UserMember(ctx context.Context, userID xid.ID, memberRef string) (
return m, nil return m, nil
} }
// UserMembers returns all of a user's members, sorted by name.
func (db *DB) UserMembers(ctx context.Context, userID xid.ID) (ms []Member, err error) { func (db *DB) UserMembers(ctx context.Context, userID xid.ID) (ms []Member, err error) {
sql, args, err := sq.Select("*").From("members").Where("user_id = ?", userID).OrderBy("name", "id").ToSql() sql, args, err := sq.Select("*").From("members").Where("user_id = ?", userID).OrderBy("name", "id").ToSql()
if err != nil { if err != nil {
@ -107,6 +109,20 @@ func (db *DB) CreateMember(ctx context.Context, tx pgx.Tx, userID xid.ID, name s
return m, nil return m, nil
} }
// DeleteMember deletes a member by the given ID. This is irreversible.
func (db *DB) DeleteMember(ctx context.Context, id xid.ID) (err error) {
sql, args, err := sq.Delete("members").Where("id = ?", id).ToSql()
if err != nil {
return errors.Wrap(err, "building sql")
}
_, err = db.Exec(ctx, sql, args...)
if err != nil {
return errors.Wrap(err, "deleting member")
}
return nil
}
// MemberCount returns the number of members that the given user has. // MemberCount returns the number of members that the given user has.
func (db *DB) MemberCount(ctx context.Context, userID xid.ID) (n int64, err error) { func (db *DB) MemberCount(ctx context.Context, userID xid.ID) (n int64, err error) {
sql, args, err := sq.Select("count(id)").From("members").Where("user_id = ?", userID).ToSql() sql, args, err := sq.Select("count(id)").From("members").Where("user_id = ?", userID).ToSql()

View File

@ -0,0 +1,45 @@
package member
import (
"net/http"
"emperror.dev/errors"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
"github.com/rs/xid"
"codeberg.org/u1f320/pronouns.cc/backend/db"
"codeberg.org/u1f320/pronouns.cc/backend/server"
)
func (s *Server) deleteMember(w http.ResponseWriter, r *http.Request) error {
ctx := r.Context()
claims, _ := server.ClaimsFromContext(ctx)
id, err := xid.FromString(chi.URLParam(r, "memberRef"))
if err != nil {
return server.APIError{Code: server.ErrMemberNotFound}
}
m, err := s.DB.Member(ctx, id)
if err != nil {
if err == db.ErrMemberNotFound {
return server.APIError{Code: server.ErrMemberNotFound}
}
return errors.Wrap(err, "getting member")
}
if m.UserID != claims.UserID {
return server.APIError{Code: server.ErrNotOwnMember}
}
err = s.DB.DeleteMember(ctx, m.ID)
if err != nil {
return errors.Wrap(err, "deleting member")
}
render.NoContent(w, r)
return nil
}

View File

@ -1,8 +1,9 @@
package member package member
import ( import (
"codeberg.org/u1f320/pronouns.cc/backend/server"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"codeberg.org/u1f320/pronouns.cc/backend/server"
) )
type Server struct { type Server struct {
@ -26,6 +27,6 @@ func Mount(srv *server.Server, r chi.Router) {
// create, edit, and delete members // create, edit, and delete members
r.With(server.MustAuth).Post("/", server.WrapHandler(s.createMember)) r.With(server.MustAuth).Post("/", server.WrapHandler(s.createMember))
r.With(server.MustAuth).Patch("/{memberRef}", server.WrapHandler(s.patchMember)) r.With(server.MustAuth).Patch("/{memberRef}", server.WrapHandler(s.patchMember))
r.With(server.MustAuth).Delete("/{memberRef}", nil) r.With(server.MustAuth).Delete("/{memberRef}", server.WrapHandler(s.deleteMember))
}) })
} }

View File

@ -27,6 +27,6 @@ export default async function fetchAPI<T>(
}); });
const data = await resp.json(); const data = await resp.json();
if (resp.status !== 200) throw data as APIError; if (resp.status < 200 || resp.status >= 300) throw data as APIError;
return data as T; return data as T;
} }