mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-27 13:48:49 +08:00

* MF-1240 - Return to service transport layer only service errors Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Remove unecessary errors Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Rm duplicated errors and fix transport Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Revert http endpoint_test Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix conflict Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> Co-authored-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
320 lines
7.8 KiB
Go
320 lines
7.8 KiB
Go
// Copyright (c) Mainflux
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package mocks
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/mainflux/mainflux/auth"
|
|
"github.com/mainflux/mainflux/pkg/errors"
|
|
)
|
|
|
|
var _ auth.GroupRepository = (*groupRepositoryMock)(nil)
|
|
|
|
type groupRepositoryMock struct {
|
|
mu sync.Mutex
|
|
// Map of groups, group id as a key.
|
|
// groups map[GroupID]auth.Group
|
|
groups map[string]auth.Group
|
|
// Map of groups with group id as key that are
|
|
// children (i.e. has same parent id) is element
|
|
// in children's map where parent id is key.
|
|
// children map[ParentID]map[GroupID]auth.Group
|
|
children map[string]map[string]auth.Group
|
|
// Map of parents' id with child group id as key.
|
|
// Each child has one parent.
|
|
// parents map[ChildID]ParentID
|
|
parents map[string]string
|
|
// Map of groups (with group id as key) which
|
|
// represent memberships is element in
|
|
// memberships' map where member id is a key.
|
|
// memberships map[MemberID]map[GroupID]auth.Group
|
|
memberships map[string]map[string]auth.Group
|
|
// Map of group members where member id is a key
|
|
// is an element in the map members where group id is a key.
|
|
// members map[type][GroupID]map[MemberID]MemberID
|
|
members map[string]map[string]map[string]string
|
|
}
|
|
|
|
// NewGroupRepository creates in-memory user repository
|
|
func NewGroupRepository() auth.GroupRepository {
|
|
return &groupRepositoryMock{
|
|
groups: make(map[string]auth.Group),
|
|
children: make(map[string]map[string]auth.Group),
|
|
parents: make(map[string]string),
|
|
memberships: make(map[string]map[string]auth.Group),
|
|
members: make(map[string]map[string]map[string]string),
|
|
}
|
|
}
|
|
|
|
func (grm *groupRepositoryMock) Save(ctx context.Context, group auth.Group) (auth.Group, error) {
|
|
grm.mu.Lock()
|
|
defer grm.mu.Unlock()
|
|
if _, ok := grm.groups[group.ID]; ok {
|
|
return auth.Group{}, errors.ErrConflict
|
|
}
|
|
path := group.ID
|
|
|
|
if group.ParentID != "" {
|
|
parent, ok := grm.groups[group.ParentID]
|
|
if !ok {
|
|
return auth.Group{}, errors.ErrCreateEntity
|
|
}
|
|
if _, ok := grm.children[group.ParentID]; !ok {
|
|
grm.children[group.ParentID] = make(map[string]auth.Group)
|
|
}
|
|
grm.children[group.ParentID][group.ID] = group
|
|
grm.parents[group.ID] = group.ParentID
|
|
path = fmt.Sprintf("%s.%s", parent.Path, path)
|
|
}
|
|
|
|
group.Path = path
|
|
group.Level = len(strings.Split(path, "."))
|
|
|
|
grm.groups[group.ID] = group
|
|
return group, nil
|
|
}
|
|
|
|
func (grm *groupRepositoryMock) Update(ctx context.Context, group auth.Group) (auth.Group, error) {
|
|
grm.mu.Lock()
|
|
defer grm.mu.Unlock()
|
|
up, ok := grm.groups[group.ID]
|
|
if !ok {
|
|
return auth.Group{}, errors.ErrNotFound
|
|
}
|
|
up.Name = group.Name
|
|
up.Description = group.Description
|
|
up.Metadata = group.Metadata
|
|
up.UpdatedAt = time.Now()
|
|
|
|
grm.groups[group.ID] = up
|
|
return up, nil
|
|
}
|
|
|
|
func (grm *groupRepositoryMock) Delete(ctx context.Context, id string) error {
|
|
grm.mu.Lock()
|
|
defer grm.mu.Unlock()
|
|
if _, ok := grm.groups[id]; !ok {
|
|
return errors.ErrNotFound
|
|
}
|
|
|
|
if len(grm.members[id]) > 0 {
|
|
return auth.ErrGroupNotEmpty
|
|
}
|
|
|
|
// This is not quite exact, it should go in depth
|
|
for _, ch := range grm.children[id] {
|
|
if len(grm.members[ch.ID]) > 0 {
|
|
return auth.ErrGroupNotEmpty
|
|
}
|
|
}
|
|
|
|
// This is not quite exact, it should go in depth
|
|
delete(grm.groups, id)
|
|
for _, ch := range grm.children[id] {
|
|
delete(grm.members, ch.ID)
|
|
}
|
|
|
|
delete(grm.children, id)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
func (grm *groupRepositoryMock) RetrieveByID(ctx context.Context, id string) (auth.Group, error) {
|
|
grm.mu.Lock()
|
|
defer grm.mu.Unlock()
|
|
|
|
val, ok := grm.groups[id]
|
|
if !ok {
|
|
return auth.Group{}, errors.ErrNotFound
|
|
}
|
|
return val, nil
|
|
}
|
|
|
|
func (grm *groupRepositoryMock) RetrieveAll(ctx context.Context, pm auth.PageMetadata) (auth.GroupPage, error) {
|
|
grm.mu.Lock()
|
|
defer grm.mu.Unlock()
|
|
var items []auth.Group
|
|
for _, g := range grm.groups {
|
|
items = append(items, g)
|
|
}
|
|
return auth.GroupPage{
|
|
Groups: items,
|
|
PageMetadata: auth.PageMetadata{
|
|
Total: uint64(len(items)),
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (grm *groupRepositoryMock) Unassign(ctx context.Context, groupID string, memberIDs ...string) error {
|
|
grm.mu.Lock()
|
|
defer grm.mu.Unlock()
|
|
if _, ok := grm.groups[groupID]; !ok {
|
|
return errors.ErrNotFound
|
|
}
|
|
for _, memberID := range memberIDs {
|
|
for typ, m := range grm.members[groupID] {
|
|
_, ok := m[memberID]
|
|
if !ok {
|
|
return errors.ErrNotFound
|
|
}
|
|
delete(grm.members[groupID][typ], memberID)
|
|
delete(grm.memberships[memberID], groupID)
|
|
}
|
|
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (grm *groupRepositoryMock) Assign(ctx context.Context, groupID, groupType string, memberIDs ...string) error {
|
|
grm.mu.Lock()
|
|
defer grm.mu.Unlock()
|
|
if _, ok := grm.groups[groupID]; !ok {
|
|
return errors.ErrNotFound
|
|
}
|
|
|
|
if _, ok := grm.members[groupID]; !ok {
|
|
grm.members[groupID] = make(map[string]map[string]string)
|
|
}
|
|
|
|
for _, memberID := range memberIDs {
|
|
if _, ok := grm.members[groupID][groupType]; !ok {
|
|
grm.members[groupID][groupType] = make(map[string]string)
|
|
}
|
|
if _, ok := grm.memberships[memberID]; !ok {
|
|
grm.memberships[memberID] = make(map[string]auth.Group)
|
|
}
|
|
|
|
grm.members[groupID][groupType][memberID] = memberID
|
|
grm.memberships[memberID][groupID] = grm.groups[groupID]
|
|
}
|
|
return nil
|
|
|
|
}
|
|
|
|
func (grm *groupRepositoryMock) Memberships(ctx context.Context, memberID string, pm auth.PageMetadata) (auth.GroupPage, error) {
|
|
grm.mu.Lock()
|
|
defer grm.mu.Unlock()
|
|
var items []auth.Group
|
|
|
|
first := uint64(pm.Offset)
|
|
last := first + uint64(pm.Limit)
|
|
|
|
i := uint64(0)
|
|
for _, g := range grm.memberships[memberID] {
|
|
if i >= first && i < last {
|
|
items = append(items, g)
|
|
}
|
|
i++
|
|
}
|
|
|
|
return auth.GroupPage{
|
|
Groups: items,
|
|
PageMetadata: auth.PageMetadata{
|
|
Limit: pm.Limit,
|
|
Offset: pm.Offset,
|
|
Total: uint64(len(items)),
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (grm *groupRepositoryMock) Members(ctx context.Context, groupID, groupType string, pm auth.PageMetadata) (auth.MemberPage, error) {
|
|
grm.mu.Lock()
|
|
defer grm.mu.Unlock()
|
|
var items []auth.Member
|
|
members, ok := grm.members[groupID][groupType]
|
|
if !ok {
|
|
return auth.MemberPage{}, errors.ErrNotFound
|
|
}
|
|
|
|
first := uint64(pm.Offset)
|
|
last := first + uint64(pm.Limit)
|
|
|
|
i := uint64(0)
|
|
for _, g := range members {
|
|
if i >= first && i < last {
|
|
items = append(items, auth.Member{ID: g, Type: groupType})
|
|
}
|
|
i++
|
|
}
|
|
return auth.MemberPage{
|
|
Members: items,
|
|
PageMetadata: auth.PageMetadata{
|
|
Total: uint64(len(items)),
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (grm *groupRepositoryMock) RetrieveAllParents(ctx context.Context, groupID string, pm auth.PageMetadata) (auth.GroupPage, error) {
|
|
grm.mu.Lock()
|
|
defer grm.mu.Unlock()
|
|
if groupID == "" {
|
|
return auth.GroupPage{}, nil
|
|
}
|
|
|
|
group, ok := grm.groups[groupID]
|
|
if !ok {
|
|
return auth.GroupPage{}, errors.ErrNotFound
|
|
}
|
|
|
|
groups := make([]auth.Group, 0)
|
|
groups, err := grm.getParents(groups, group)
|
|
if err != nil {
|
|
return auth.GroupPage{}, err
|
|
}
|
|
|
|
return auth.GroupPage{
|
|
Groups: groups,
|
|
PageMetadata: auth.PageMetadata{
|
|
Total: uint64(len(groups)),
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (grm *groupRepositoryMock) getParents(groups []auth.Group, group auth.Group) ([]auth.Group, error) {
|
|
groups = append(groups, group)
|
|
parentID, ok := grm.parents[group.ID]
|
|
if !ok && parentID == "" {
|
|
return groups, nil
|
|
}
|
|
parent, ok := grm.groups[parentID]
|
|
if !ok {
|
|
panic(fmt.Sprintf("parent with id: %s not found", parentID))
|
|
}
|
|
return grm.getParents(groups, parent)
|
|
}
|
|
|
|
func (grm *groupRepositoryMock) RetrieveAllChildren(ctx context.Context, groupID string, pm auth.PageMetadata) (auth.GroupPage, error) {
|
|
grm.mu.Lock()
|
|
defer grm.mu.Unlock()
|
|
group, ok := grm.groups[groupID]
|
|
if !ok {
|
|
return auth.GroupPage{}, nil
|
|
}
|
|
|
|
groups := make([]auth.Group, 0)
|
|
groups = append(groups, group)
|
|
for ch := range grm.parents {
|
|
g, ok := grm.groups[ch]
|
|
if !ok {
|
|
panic(fmt.Sprintf("child with id %s not found", ch))
|
|
}
|
|
groups = append(groups, g)
|
|
}
|
|
|
|
return auth.GroupPage{
|
|
Groups: groups,
|
|
PageMetadata: auth.PageMetadata{
|
|
Total: uint64(len(groups)),
|
|
Offset: pm.Offset,
|
|
Limit: pm.Limit,
|
|
},
|
|
}, nil
|
|
}
|