mirror of
https://github.com/mainflux/mainflux.git
synced 2025-05-02 22:17:10 +08:00

* add things group Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add things group repository Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add things group repository Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add things group repository Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add parents and children methods Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add parents and children methods Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix logging message and temporary test fix Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix bootstrap test fail Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * move groups to pkg Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * move groups to pkg Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * move groups to pkg Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * move groups to internal Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * move groups to internal Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix import Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix linter errors Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix comments Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * resolve comments, add hierarchy info when retrieving groups Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * code refactor, separate http into multiple files Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * code refactor, separate http into multiple files Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix group update Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * use user id when saving Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * use user id when saving Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * rename methods Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * move code Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * move code Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * remove temporary test Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add groups test Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix comments, fix responses in api for groups Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * revert changes Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> add checks for name length Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> fix validation Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> small change to response Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> add comment for Level Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> add level to limit hierarchy retrieval Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> tidy vendor Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> add level to limit hierarchy retrieval Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> mod tidy Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> revert Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> resolve comments Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> small naming and code organize refactor Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> revert Member type Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> fix typo Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> use ltree Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> use ltree Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> add level for retrieving Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> add level Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> add ltre Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> upgrade postgres version in test Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> add ltre Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> remove test for now Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> minor fixes Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> fix id setting Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> fix tree endpoint Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> minor style changes Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * small changes, adding new lines Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * minor changes Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * change function signature Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * change primary key Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * change function signature Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * simplufy code Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * remove groups test for now Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix tabulation Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix whitespace Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * remove white space, fix grammar Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix sqls so that not additional retrieve is needed Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix sqls so that not additional retrieve is needed Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> fix primary key Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> remove retrive by name Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * remove name and parent update Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix cound sql Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add line Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * simplify sql, fix table name Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add date Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add date Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * add timestamp to api Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix var name Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix var name Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>
338 lines
8.5 KiB
Go
338 lines
8.5 KiB
Go
package groups
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/go-kit/kit/endpoint"
|
|
"github.com/mainflux/mainflux/internal/groups"
|
|
"github.com/mainflux/mainflux/pkg/errors"
|
|
)
|
|
|
|
func CreateGroupEndpoint(svc groups.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
|
req := request.(createGroupReq)
|
|
if err := req.validate(); err != nil {
|
|
return groupRes{}, err
|
|
}
|
|
|
|
group := groups.Group{
|
|
Name: req.Name,
|
|
Description: req.Description,
|
|
ParentID: req.ParentID,
|
|
Metadata: req.Metadata,
|
|
}
|
|
|
|
id, err := svc.CreateGroup(ctx, req.token, group)
|
|
if err != nil {
|
|
return groupRes{}, errors.Wrap(groups.ErrCreateGroup, err)
|
|
}
|
|
|
|
return groupRes{created: true, id: id}, nil
|
|
}
|
|
}
|
|
|
|
func ViewGroupEndpoint(svc groups.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
|
req := request.(groupReq)
|
|
if err := req.validate(); err != nil {
|
|
return viewGroupRes{}, errors.Wrap(groups.ErrMalformedEntity, err)
|
|
}
|
|
|
|
group, err := svc.ViewGroup(ctx, req.token, req.groupID)
|
|
if err != nil {
|
|
return viewGroupRes{}, errors.Wrap(groups.ErrFetchGroups, err)
|
|
}
|
|
|
|
res := viewGroupRes{
|
|
ID: group.ID,
|
|
Name: group.Name,
|
|
Description: group.Description,
|
|
Metadata: group.Metadata,
|
|
ParentID: group.ParentID,
|
|
OwnerID: group.OwnerID,
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
}
|
|
|
|
func UpdateGroupEndpoint(svc groups.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
|
req := request.(updateGroupReq)
|
|
if err := req.validate(); err != nil {
|
|
return groupRes{}, errors.Wrap(groups.ErrMalformedEntity, err)
|
|
}
|
|
|
|
group := groups.Group{
|
|
ID: req.id,
|
|
Name: req.Name,
|
|
Description: req.Description,
|
|
ParentID: req.ParentID,
|
|
Metadata: req.Metadata,
|
|
}
|
|
|
|
_, err := svc.UpdateGroup(ctx, req.token, group)
|
|
if err != nil {
|
|
return groupRes{}, errors.Wrap(groups.ErrUpdateGroup, err)
|
|
}
|
|
|
|
res := groupRes{created: false}
|
|
return res, nil
|
|
}
|
|
}
|
|
|
|
func DeleteGroupEndpoint(svc groups.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
|
req := request.(groupReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(groups.ErrMalformedEntity, err)
|
|
}
|
|
|
|
if err := svc.RemoveGroup(ctx, req.token, req.groupID); err != nil {
|
|
return nil, errors.Wrap(groups.ErrDeleteGroup, err)
|
|
}
|
|
|
|
return groupDeleteRes{}, nil
|
|
}
|
|
}
|
|
|
|
func ListGroupsEndpoint(svc groups.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
|
req := request.(listGroupsReq)
|
|
if err := req.validate(); err != nil {
|
|
return groupPageRes{}, errors.Wrap(groups.ErrMalformedEntity, err)
|
|
}
|
|
|
|
page, err := svc.ListGroups(ctx, req.token, req.level, req.metadata)
|
|
if err != nil {
|
|
return groupPageRes{}, errors.Wrap(groups.ErrFetchGroups, err)
|
|
}
|
|
|
|
if req.tree {
|
|
return buildGroupsResponseTree(page), nil
|
|
}
|
|
|
|
return buildGroupsResponse(page), nil
|
|
}
|
|
}
|
|
|
|
func ListMembership(svc groups.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
|
req := request.(listMemberGroupReq)
|
|
if err := req.validate(); err != nil {
|
|
return memberPageRes{}, err
|
|
}
|
|
|
|
page, err := svc.ListMemberships(ctx, req.token, req.memberID, req.offset, req.limit, req.metadata)
|
|
if err != nil {
|
|
return memberPageRes{}, err
|
|
}
|
|
|
|
if req.tree {
|
|
return buildGroupsResponseTree(page), nil
|
|
}
|
|
|
|
return buildGroupsResponse(page), nil
|
|
}
|
|
}
|
|
|
|
func ListGroupChildrenEndpoint(svc groups.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
|
req := request.(listGroupsReq)
|
|
if err := req.validate(); err != nil {
|
|
return groupPageRes{}, errors.Wrap(groups.ErrMalformedEntity, err)
|
|
}
|
|
|
|
page, err := svc.ListChildren(ctx, req.token, req.groupID, req.level, req.metadata)
|
|
if err != nil {
|
|
return groupPageRes{}, errors.Wrap(groups.ErrFetchGroups, err)
|
|
}
|
|
|
|
if req.tree {
|
|
return buildGroupsResponseTree(page), nil
|
|
}
|
|
|
|
return buildGroupsResponse(page), nil
|
|
}
|
|
}
|
|
|
|
func ListGroupParentsEndpoint(svc groups.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
|
req := request.(listGroupsReq)
|
|
if err := req.validate(); err != nil {
|
|
return groupPageRes{}, errors.Wrap(groups.ErrMalformedEntity, err)
|
|
}
|
|
|
|
page, err := svc.ListParents(ctx, req.token, req.groupID, req.level, req.metadata)
|
|
if err != nil {
|
|
return groupPageRes{}, errors.Wrap(groups.ErrFetchGroups, err)
|
|
}
|
|
|
|
if req.tree {
|
|
return buildGroupsResponseTree(page), nil
|
|
}
|
|
|
|
return buildGroupsResponse(page), nil
|
|
}
|
|
}
|
|
|
|
func AssignEndpoint(svc groups.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
|
req := request.(memberGroupReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(groups.ErrMalformedEntity, err)
|
|
}
|
|
|
|
if err := svc.Assign(ctx, req.token, req.memberID, req.groupID); err != nil {
|
|
return nil, errors.Wrap(groups.ErrAssignToGroup, err)
|
|
}
|
|
|
|
return assignMemberToGroupRes{}, nil
|
|
}
|
|
}
|
|
|
|
func UnassignEndpoint(svc groups.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
|
req := request.(memberGroupReq)
|
|
if err := req.validate(); err != nil {
|
|
return nil, errors.Wrap(groups.ErrMalformedEntity, err)
|
|
}
|
|
|
|
if err := svc.Unassign(ctx, req.token, req.memberID, req.groupID); err != nil {
|
|
return nil, errors.Wrap(groups.ErrUnassignFromGroup, err)
|
|
}
|
|
|
|
return removeMemberFromGroupRes{}, nil
|
|
}
|
|
}
|
|
|
|
func ListMembersEndpoint(svc groups.Service) endpoint.Endpoint {
|
|
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
|
req := request.(listMemberGroupReq)
|
|
if err := req.validate(); err != nil {
|
|
return memberPageRes{}, errors.Wrap(groups.ErrMalformedEntity, err)
|
|
}
|
|
|
|
page, err := svc.ListMembers(ctx, req.token, req.groupID, req.offset, req.limit, req.metadata)
|
|
if err != nil {
|
|
return memberPageRes{}, err
|
|
}
|
|
|
|
return buildUsersResponse(page), nil
|
|
}
|
|
}
|
|
|
|
func buildGroupsResponseTree(page groups.GroupPage) groupPageRes {
|
|
groupsMap := map[string]*groups.Group{}
|
|
// Parents map keeps its array of children.
|
|
parentsMap := map[string][]*groups.Group{}
|
|
for i := range page.Groups {
|
|
if _, ok := groupsMap[page.Groups[i].ID]; !ok {
|
|
groupsMap[page.Groups[i].ID] = &page.Groups[i]
|
|
parentsMap[page.Groups[i].ID] = make([]*groups.Group, 0)
|
|
}
|
|
}
|
|
|
|
for _, group := range groupsMap {
|
|
if ch, ok := parentsMap[group.ParentID]; ok {
|
|
ch = append(ch, group)
|
|
parentsMap[group.ParentID] = ch
|
|
}
|
|
}
|
|
|
|
res := groupPageRes{
|
|
pageRes: pageRes{
|
|
Total: page.Total,
|
|
Offset: page.Offset,
|
|
Limit: page.Limit,
|
|
},
|
|
Groups: []viewGroupRes{},
|
|
}
|
|
|
|
for _, group := range groupsMap {
|
|
if children, ok := parentsMap[group.ID]; ok {
|
|
group.Children = children
|
|
}
|
|
|
|
}
|
|
|
|
for _, group := range groupsMap {
|
|
view := toViewGroupRes(*group)
|
|
if children, ok := parentsMap[group.ParentID]; len(children) == 0 || !ok {
|
|
res.Groups = append(res.Groups, view)
|
|
}
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
func toViewGroupRes(g groups.Group) viewGroupRes {
|
|
view := viewGroupRes{
|
|
ID: g.ID,
|
|
ParentID: g.ParentID,
|
|
OwnerID: g.OwnerID,
|
|
Name: g.Name,
|
|
Description: g.Description,
|
|
Metadata: g.Metadata,
|
|
Level: g.Level,
|
|
Path: g.Path,
|
|
Children: make([]*viewGroupRes, 0),
|
|
CreatedAt: g.CreatedAt,
|
|
UpdatedAt: g.UpdatedAt,
|
|
}
|
|
|
|
for _, ch := range g.Children {
|
|
child := toViewGroupRes(*ch)
|
|
view.Children = append(view.Children, &child)
|
|
}
|
|
|
|
return view
|
|
}
|
|
|
|
func buildGroupsResponse(gp groups.GroupPage) groupPageRes {
|
|
res := groupPageRes{
|
|
pageRes: pageRes{
|
|
Total: gp.Total,
|
|
Offset: gp.Offset,
|
|
Limit: gp.Limit,
|
|
},
|
|
Groups: []viewGroupRes{},
|
|
}
|
|
|
|
for _, group := range gp.Groups {
|
|
view := viewGroupRes{
|
|
ID: group.ID,
|
|
ParentID: group.ParentID,
|
|
OwnerID: group.OwnerID,
|
|
Name: group.Name,
|
|
Description: group.Description,
|
|
Metadata: group.Metadata,
|
|
Level: group.Level,
|
|
Path: group.Path,
|
|
CreatedAt: group.CreatedAt,
|
|
UpdatedAt: group.UpdatedAt,
|
|
}
|
|
res.Groups = append(res.Groups, view)
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
func buildUsersResponse(mp groups.MemberPage) memberPageRes {
|
|
res := memberPageRes{
|
|
pageRes: pageRes{
|
|
Total: mp.Total,
|
|
Offset: mp.Offset,
|
|
Limit: mp.Limit,
|
|
Name: mp.Name,
|
|
},
|
|
Members: []interface{}{},
|
|
}
|
|
|
|
for _, m := range mp.Members {
|
|
res.Members = append(res.Members, m)
|
|
}
|
|
|
|
return res
|
|
}
|