mirror of
https://github.com/kevin-DL/services.git
synced 2026-01-11 19:04:35 +00:00
376 lines
7.7 KiB
Go
376 lines
7.7 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/micro/micro/v3/service/auth"
|
|
"github.com/micro/micro/v3/service/errors"
|
|
"github.com/micro/micro/v3/service/store"
|
|
pb "github.com/micro/services/groups/proto"
|
|
"github.com/micro/services/pkg/tenant"
|
|
)
|
|
|
|
var (
|
|
ErrMissingName = errors.BadRequest("MISSING_NAME", "Missing name")
|
|
ErrMissingID = errors.BadRequest("MISSING_ID", "Missing ID")
|
|
ErrMissingIDs = errors.BadRequest("MISSING_IDS", "One or more IDs are required")
|
|
ErrMissingGroupID = errors.BadRequest("MISSING_GROUP_ID", "Missing Group ID")
|
|
ErrMissingMemberID = errors.BadRequest("MISSING_MEMBER_ID", "Missing Member ID")
|
|
ErrNotFound = errors.BadRequest("NOT_FOUND", "No group found with this ID")
|
|
ErrStore = errors.InternalServerError("STORE_ERROR", "Error connecting to the store")
|
|
)
|
|
|
|
type Group struct {
|
|
ID string
|
|
Name string
|
|
Members []string
|
|
}
|
|
|
|
type Member struct {
|
|
ID string
|
|
Group string
|
|
}
|
|
|
|
func (g *Group) Key(ctx context.Context) string {
|
|
key := fmt.Sprintf("group:%s", g.ID)
|
|
|
|
t, ok := tenant.FromContext(ctx)
|
|
if !ok {
|
|
return key
|
|
}
|
|
|
|
return fmt.Sprintf("%s/%s", t, key)
|
|
}
|
|
|
|
func (m *Member) Key(ctx context.Context) string {
|
|
key := fmt.Sprintf("member:%s:%s", m.ID, m.Group)
|
|
|
|
t, ok := tenant.FromContext(ctx)
|
|
if !ok {
|
|
return key
|
|
}
|
|
|
|
return fmt.Sprintf("%s/%s", t, key)
|
|
|
|
}
|
|
|
|
func (g *Group) Serialize() *pb.Group {
|
|
memberIDs := make([]string, len(g.Members))
|
|
for i, m := range g.Members {
|
|
memberIDs[i] = m
|
|
}
|
|
return &pb.Group{Id: g.ID, Name: g.Name, MemberIds: memberIDs}
|
|
}
|
|
|
|
type Groups struct{}
|
|
|
|
func (g *Groups) Create(ctx context.Context, req *pb.CreateRequest, rsp *pb.CreateResponse) error {
|
|
_, ok := auth.AccountFromContext(ctx)
|
|
if !ok {
|
|
errors.Unauthorized("UNAUTHORIZED", "Unauthorized")
|
|
}
|
|
// validate the request
|
|
if len(req.Name) == 0 {
|
|
return ErrMissingName
|
|
}
|
|
|
|
// create the group object
|
|
group := &Group{ID: uuid.New().String(), Name: req.Name}
|
|
|
|
// write the group record
|
|
if err := store.Write(store.NewRecord(group.Key(ctx), group)); err != nil {
|
|
return ErrStore
|
|
}
|
|
|
|
// return the group
|
|
rsp.Group = group.Serialize()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (g *Groups) Read(ctx context.Context, req *pb.ReadRequest, rsp *pb.ReadResponse) error {
|
|
_, ok := auth.AccountFromContext(ctx)
|
|
if !ok {
|
|
errors.Unauthorized("UNAUTHORIZED", "Unauthorized")
|
|
}
|
|
// validate the request
|
|
if len(req.Ids) == 0 {
|
|
return ErrMissingIDs
|
|
}
|
|
|
|
// serialize the response
|
|
rsp.Groups = make(map[string]*pb.Group)
|
|
|
|
for _, id := range req.Ids {
|
|
group := &Group{
|
|
ID: id,
|
|
}
|
|
recs, err := store.Read(group.Key(ctx), store.ReadLimit(1))
|
|
if err != nil {
|
|
return ErrStore
|
|
}
|
|
if len(recs) == 0 {
|
|
continue
|
|
}
|
|
if err := recs[0].Decode(&group); err != nil {
|
|
continue
|
|
}
|
|
rsp.Groups[group.ID] = group.Serialize()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (g *Groups) Update(ctx context.Context, req *pb.UpdateRequest, rsp *pb.UpdateResponse) error {
|
|
_, ok := auth.AccountFromContext(ctx)
|
|
if !ok {
|
|
errors.Unauthorized("UNAUTHORIZED", "Unauthorized")
|
|
}
|
|
// validate the request
|
|
if len(req.Id) == 0 {
|
|
return ErrMissingID
|
|
}
|
|
if len(req.Name) == 0 {
|
|
return ErrMissingName
|
|
}
|
|
|
|
group := &Group{ID: req.Id}
|
|
|
|
recs, err := store.Read(group.Key(ctx), store.ReadLimit(1))
|
|
if err == store.ErrNotFound {
|
|
return ErrNotFound
|
|
} else if err != nil {
|
|
return ErrStore
|
|
}
|
|
|
|
// decode the record
|
|
recs[0].Decode(&group)
|
|
|
|
// set the name
|
|
group.Name = req.Name
|
|
|
|
// save the record
|
|
if err := store.Write(store.NewRecord(group.Key(ctx), group)); err != nil {
|
|
return ErrStore
|
|
}
|
|
|
|
// serialize the response
|
|
rsp.Group = group.Serialize()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (g *Groups) Delete(ctx context.Context, req *pb.DeleteRequest, rsp *pb.DeleteResponse) error {
|
|
_, ok := auth.AccountFromContext(ctx)
|
|
if !ok {
|
|
errors.Unauthorized("UNAUTHORIZED", "Unauthorized")
|
|
}
|
|
// validate the request
|
|
if len(req.Id) == 0 {
|
|
return ErrMissingID
|
|
}
|
|
|
|
group := &Group{ID: req.Id}
|
|
|
|
// get the group
|
|
recs, err := store.Read(group.Key(ctx), store.ReadLimit(1))
|
|
if err == store.ErrNotFound {
|
|
return nil
|
|
} else if err != nil {
|
|
return ErrStore
|
|
}
|
|
|
|
// decode the record
|
|
recs[0].Decode(&group)
|
|
|
|
// delete the record
|
|
if err := store.Delete(group.Key(ctx)); err == store.ErrNotFound {
|
|
return nil
|
|
} else if err != nil {
|
|
return ErrStore
|
|
}
|
|
|
|
// delete all the members
|
|
for _, memberId := range group.Members {
|
|
m := &Member{
|
|
ID: memberId,
|
|
}
|
|
// delete the member
|
|
store.Delete(m.Key(ctx))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (g *Groups) List(ctx context.Context, req *pb.ListRequest, rsp *pb.ListResponse) error {
|
|
_, ok := auth.AccountFromContext(ctx)
|
|
if !ok {
|
|
errors.Unauthorized("UNAUTHORIZED", "Unauthorized")
|
|
}
|
|
|
|
if len(req.MemberId) > 0 {
|
|
// only list groups the user is a member of
|
|
m := &Member{ID: req.MemberId}
|
|
recs, err := store.Read(m.Key(ctx), store.ReadPrefix())
|
|
if err != nil {
|
|
return ErrStore
|
|
}
|
|
|
|
for _, rec := range recs {
|
|
m := &Member{ID: req.MemberId}
|
|
rec.Decode(&m)
|
|
|
|
// get the group
|
|
group := &Group{ID: m.Group}
|
|
|
|
grecs, err := store.Read(group.Key(ctx), store.ReadLimit(1))
|
|
if err != nil {
|
|
return ErrStore
|
|
}
|
|
grecs[0].Decode(&group)
|
|
|
|
rsp.Groups = append(rsp.Groups, group.Serialize())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
group := &Group{}
|
|
|
|
// read all the prefixes
|
|
recs, err := store.Read(group.Key(ctx), store.ReadPrefix())
|
|
if err != nil {
|
|
return ErrStore
|
|
}
|
|
|
|
// serialize and return response
|
|
for _, rec := range recs {
|
|
group := new(Group)
|
|
rec.Decode(&group)
|
|
rsp.Groups = append(rsp.Groups, group.Serialize())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (g *Groups) AddMember(ctx context.Context, req *pb.AddMemberRequest, rsp *pb.AddMemberResponse) error {
|
|
_, ok := auth.AccountFromContext(ctx)
|
|
if !ok {
|
|
errors.Unauthorized("UNAUTHORIZED", "Unauthorized")
|
|
}
|
|
// validate the request
|
|
if len(req.GroupId) == 0 {
|
|
return ErrMissingGroupID
|
|
}
|
|
if len(req.MemberId) == 0 {
|
|
return ErrMissingMemberID
|
|
}
|
|
|
|
// read the group
|
|
group := &Group{ID: req.GroupId}
|
|
|
|
recs, err := store.Read(group.Key(ctx), store.ReadLimit(1))
|
|
if err == store.ErrNotFound {
|
|
return ErrNotFound
|
|
} else if err != nil {
|
|
return ErrStore
|
|
}
|
|
|
|
// decode the record
|
|
recs[0].Decode(group)
|
|
|
|
var seen bool
|
|
for _, member := range group.Members {
|
|
if member == req.MemberId {
|
|
seen = true
|
|
break
|
|
}
|
|
}
|
|
|
|
// already a member
|
|
if seen {
|
|
return nil
|
|
}
|
|
|
|
// add the member
|
|
group.Members = append(group.Members, req.MemberId)
|
|
|
|
// save the record
|
|
if err := store.Write(store.NewRecord(group.Key(ctx), group)); err != nil {
|
|
return ErrStore
|
|
}
|
|
|
|
// add the member record
|
|
|
|
m := &Member{
|
|
ID: req.MemberId,
|
|
Group: group.ID,
|
|
}
|
|
|
|
// write the record
|
|
if err := store.Write(store.NewRecord(m.Key(ctx), m)); err != nil {
|
|
return ErrStore
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (g *Groups) RemoveMember(ctx context.Context, req *pb.RemoveMemberRequest, rsp *pb.RemoveMemberResponse) error {
|
|
_, ok := auth.AccountFromContext(ctx)
|
|
if !ok {
|
|
errors.Unauthorized("UNAUTHORIZED", "Unauthorized")
|
|
}
|
|
// validate the request
|
|
if len(req.GroupId) == 0 {
|
|
return ErrMissingGroupID
|
|
}
|
|
if len(req.MemberId) == 0 {
|
|
return ErrMissingMemberID
|
|
}
|
|
|
|
// read the group
|
|
group := &Group{ID: req.GroupId}
|
|
|
|
// read the gruop
|
|
recs, err := store.Read(group.Key(ctx), store.ReadLimit(1))
|
|
if err == store.ErrNotFound {
|
|
return ErrNotFound
|
|
} else if err != nil {
|
|
return ErrStore
|
|
}
|
|
|
|
// decode the record
|
|
recs[0].Decode(&group)
|
|
|
|
// new member id list
|
|
var members []string
|
|
|
|
for _, member := range group.Members {
|
|
if member == req.MemberId {
|
|
continue
|
|
}
|
|
members = append(members, member)
|
|
}
|
|
|
|
// update the member
|
|
group.Members = members
|
|
|
|
// save the record
|
|
if err := store.Write(store.NewRecord(group.Key(ctx), group)); err != nil {
|
|
return ErrStore
|
|
}
|
|
|
|
// delete the member
|
|
m := &Member{
|
|
ID: req.MemberId,
|
|
Group: group.ID,
|
|
}
|
|
if err := store.Delete(m.Key(ctx)); err != nil {
|
|
return ErrStore
|
|
}
|
|
|
|
return nil
|
|
}
|