MG-2426 - Replace generic Clients in Things service (#2476)

Signed-off-by: Musilah <nataleigh.nk@gmail.com>
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
Co-authored-by: Felix Gateru <felix.gateru@gmail.com>
This commit is contained in:
Nataly Musilah
2024-11-04 13:46:40 +03:00
committed by GitHub
parent ef8631bd1f
commit 87c390da4c
76 changed files with 2454 additions and 4621 deletions
-11
View File
@@ -160,9 +160,6 @@ jobs:
- "logger/**"
- "pkg/events/**"
pkg-clients:
- "pkg/clients/**"
pkg-errors:
- "pkg/errors/**"
@@ -178,7 +175,6 @@ jobs:
pkg-sdk:
- "pkg/sdk/**"
- "pkg/clients/**"
- "pkg/errors/**"
- "pkg/groups/**"
- "auth/**"
@@ -226,7 +222,6 @@ jobs:
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/clients/**"
- "pkg/ulid/**"
- "pkg/uuid/**"
- "pkg/events/**"
@@ -237,7 +232,6 @@ jobs:
- "auth.pb.go"
- "auth_grpc.pb.go"
- "auth/**"
- "pkg/clients/**"
- "pkg/ulid/**"
- "pkg/uuid/**"
- "pkg/events/**"
@@ -314,11 +308,6 @@ jobs:
run: |
go test --race -v -count=1 -coverprofile=coverage/mqtt.out ./mqtt/...
- name: Run pkg clients tests
if: steps.changes.outputs.pkg-clients == 'true' || steps.changes.outputs.workflow == 'true'
run: |
go test --race -v -count=1 -coverprofile=coverage/pkg-clients.out ./pkg/clients/...
- name: Run pkg errors tests
if: steps.changes.outputs.pkg-errors == 'true' || steps.changes.outputs.workflow == 'true'
run: |
+1 -2
View File
@@ -8,7 +8,6 @@ import (
"github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/pkg/apiutil"
"github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
"github.com/go-kit/kit/endpoint"
)
@@ -72,7 +71,7 @@ func updateDomainEndpoint(svc auth.Service) endpoint.Endpoint {
return nil, err
}
var metadata clients.Metadata
var metadata auth.Metadata
if req.Metadata != nil {
metadata = *req.Metadata
}
+18 -19
View File
@@ -19,7 +19,6 @@ import (
"github.com/absmach/magistrala/internal/testsutil"
mglog "github.com/absmach/magistrala/logger"
"github.com/absmach/magistrala/pkg/apiutil"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
policies "github.com/absmach/magistrala/pkg/policies"
@@ -29,7 +28,7 @@ import (
)
var (
validCMetadata = mgclients.Metadata{"role": "client"}
validCMetadata = auth.Metadata{"role": "client"}
ID = testsutil.GenerateUUID(&testing.T{})
domain = auth.Domain{
ID: ID,
@@ -114,7 +113,7 @@ func TestCreateDomain(t *testing.T) {
domain: auth.Domain{
ID: ID,
Name: "test",
Metadata: mgclients.Metadata{"role": "domain"},
Metadata: auth.Metadata{"role": "domain"},
Tags: []string{"tag1", "tag2"},
Alias: "test",
},
@@ -128,7 +127,7 @@ func TestCreateDomain(t *testing.T) {
domain: auth.Domain{
ID: ID,
Name: "test",
Metadata: mgclients.Metadata{"role": "domain"},
Metadata: auth.Metadata{"role": "domain"},
Tags: []string{"tag1", "tag2"},
Alias: "test",
},
@@ -142,7 +141,7 @@ func TestCreateDomain(t *testing.T) {
domain: auth.Domain{
ID: ID,
Name: "test",
Metadata: mgclients.Metadata{"role": "domain"},
Metadata: auth.Metadata{"role": "domain"},
Tags: []string{"tag1", "tag2"},
Alias: "test",
},
@@ -157,7 +156,7 @@ func TestCreateDomain(t *testing.T) {
domain: auth.Domain{
ID: ID,
Name: "",
Metadata: mgclients.Metadata{"role": "domain"},
Metadata: auth.Metadata{"role": "domain"},
Tags: []string{"tag1", "tag2"},
Alias: "test",
},
@@ -171,7 +170,7 @@ func TestCreateDomain(t *testing.T) {
domain: auth.Domain{
ID: ID,
Name: "test",
Metadata: mgclients.Metadata{"role": "domain"},
Metadata: auth.Metadata{"role": "domain"},
Tags: []string{"tag1", "tag2"},
Alias: "",
},
@@ -185,7 +184,7 @@ func TestCreateDomain(t *testing.T) {
domain: auth.Domain{
ID: ID,
Name: "test",
Metadata: mgclients.Metadata{"role": "domain"},
Metadata: auth.Metadata{"role": "domain"},
Tags: []string{"tag1", "tag2"},
Alias: "test",
},
@@ -646,7 +645,7 @@ func TestUpdateDomain(t *testing.T) {
domain: auth.Domain{
ID: ID,
Name: "test",
Metadata: mgclients.Metadata{"role": "domain"},
Metadata: auth.Metadata{"role": "domain"},
Tags: []string{"tag1", "tag2"},
Alias: "test",
},
@@ -660,7 +659,7 @@ func TestUpdateDomain(t *testing.T) {
domain: auth.Domain{
ID: ID,
Name: "test",
Metadata: mgclients.Metadata{"role": "domain"},
Metadata: auth.Metadata{"role": "domain"},
Tags: []string{"tag1", "tag2"},
Alias: "test",
},
@@ -674,7 +673,7 @@ func TestUpdateDomain(t *testing.T) {
domain: auth.Domain{
ID: ID,
Name: "test",
Metadata: mgclients.Metadata{"role": "domain"},
Metadata: auth.Metadata{"role": "domain"},
Tags: []string{"tag1", "tag2"},
Alias: "test",
},
@@ -689,7 +688,7 @@ func TestUpdateDomain(t *testing.T) {
domain: auth.Domain{
ID: ID,
Name: "test",
Metadata: mgclients.Metadata{"role": "domain"},
Metadata: auth.Metadata{"role": "domain"},
Tags: []string{"tag1", "tag2"},
Alias: "test",
},
@@ -1301,11 +1300,11 @@ func TestListDomainsByUserID(t *testing.T) {
}
type respBody struct {
Err string `json:"error"`
Message string `json:"message"`
Total int `json:"total"`
Permissions []string `json:"permissions"`
ID string `json:"id"`
Tags []string `json:"tags"`
Status mgclients.Status `json:"status"`
Err string `json:"error"`
Message string `json:"message"`
Total int `json:"total"`
Permissions []string `json:"permissions"`
ID string `json:"id"`
Tags []string `json:"tags"`
Status auth.Status `json:"status"`
}
+33 -31
View File
@@ -9,7 +9,6 @@ import (
"strings"
"time"
"github.com/absmach/magistrala/pkg/clients"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/pkg/policies"
)
@@ -87,41 +86,44 @@ func (s *Status) UnmarshalJSON(data []byte) error {
}
type DomainReq struct {
Name *string `json:"name,omitempty"`
Metadata *clients.Metadata `json:"metadata,omitempty"`
Tags *[]string `json:"tags,omitempty"`
Alias *string `json:"alias,omitempty"`
Status *Status `json:"status,omitempty"`
Name *string `json:"name,omitempty"`
Metadata *Metadata `json:"metadata,omitempty"`
Tags *[]string `json:"tags,omitempty"`
Alias *string `json:"alias,omitempty"`
Status *Status `json:"status,omitempty"`
}
type Domain struct {
ID string `json:"id"`
Name string `json:"name"`
Metadata clients.Metadata `json:"metadata,omitempty"`
Tags []string `json:"tags,omitempty"`
Alias string `json:"alias,omitempty"`
Status Status `json:"status"`
Permission string `json:"permission,omitempty"`
CreatedBy string `json:"created_by,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedBy string `json:"updated_by,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
ID string `json:"id"`
Name string `json:"name"`
Metadata Metadata `json:"metadata,omitempty"`
Tags []string `json:"tags,omitempty"`
Alias string `json:"alias,omitempty"`
Status Status `json:"status"`
Permission string `json:"permission,omitempty"`
CreatedBy string `json:"created_by,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedBy string `json:"updated_by,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
}
// Metadata represents arbitrary JSON.
type Metadata map[string]interface{}
type Page struct {
Total uint64 `json:"total"`
Offset uint64 `json:"offset"`
Limit uint64 `json:"limit"`
Name string `json:"name,omitempty"`
Order string `json:"-"`
Dir string `json:"-"`
Metadata clients.Metadata `json:"metadata,omitempty"`
Tag string `json:"tag,omitempty"`
Permission string `json:"permission,omitempty"`
Status Status `json:"status,omitempty"`
ID string `json:"id,omitempty"`
IDs []string `json:"-"`
Identity string `json:"identity,omitempty"`
SubjectID string `json:"-"`
Total uint64 `json:"total"`
Offset uint64 `json:"offset"`
Limit uint64 `json:"limit"`
Name string `json:"name,omitempty"`
Order string `json:"-"`
Dir string `json:"-"`
Metadata Metadata `json:"metadata,omitempty"`
Tag string `json:"tag,omitempty"`
Permission string `json:"permission,omitempty"`
Status Status `json:"status,omitempty"`
ID string `json:"id,omitempty"`
IDs []string `json:"-"`
Identity string `json:"identity,omitempty"`
SubjectID string `json:"-"`
}
type DomainsPage struct {
+1 -2
View File
@@ -13,7 +13,6 @@ import (
"github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/pkg/apiutil"
"github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
"github.com/absmach/magistrala/pkg/postgres"
@@ -473,7 +472,7 @@ func toDBDomain(d auth.Domain) (dbDomain, error) {
}
func toDomain(d dbDomain) (auth.Domain, error) {
var metadata clients.Metadata
var metadata auth.Metadata
if d.Metadata != nil {
if err := json.Unmarshal([]byte(d.Metadata), &metadata); err != nil {
return auth.Domain{}, errors.Wrap(errors.ErrMalformedEntity, err)
+2 -3
View File
@@ -12,7 +12,6 @@ import (
"github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/auth/postgres"
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
"github.com/absmach/magistrala/pkg/policies"
@@ -813,7 +812,7 @@ func TestUpdate(t *testing.T) {
})
updatedName := "test1"
updatedMetadata := clients.Metadata{
updatedMetadata := auth.Metadata{
"test1": "test1",
}
updatedTags := []string{"test1"}
@@ -917,7 +916,7 @@ func TestUpdate(t *testing.T) {
domainID: domainID,
d: auth.DomainReq{
Name: &updatedName,
Metadata: &clients.Metadata{"key": make(chan int)},
Metadata: &auth.Metadata{"key": make(chan int)},
},
response: auth.Domain{},
err: repoerr.ErrUpdateEntity,
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"context"
"time"
"github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/things"
)
// Config represents Configuration entity. It wraps information about external entity
@@ -41,7 +41,7 @@ type Channel struct {
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
UpdatedBy string `json:"updated_by,omitempty"`
Status clients.Status `json:"status"`
Status things.Status `json:"status"`
}
// Filter is used for the search filters.
+2 -2
View File
@@ -13,10 +13,10 @@ import (
"time"
"github.com/absmach/magistrala/bootstrap"
"github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
"github.com/absmach/magistrala/pkg/postgres"
"github.com/absmach/magistrala/things"
"github.com/jackc/pgerrcode"
"github.com/jackc/pgtype"
"github.com/jackc/pgx/v5/pgconn"
@@ -715,7 +715,7 @@ type dbChannel struct {
CreatedAt time.Time `db:"created_at"`
UpdatedAt sql.NullTime `db:"updated_at,omitempty"`
UpdatedBy sql.NullString `db:"updated_by,omitempty"`
Status clients.Status `db:"status"`
Status things.Status `db:"status"`
}
func toDBChannel(domainID string, ch bootstrap.Channel) (dbChannel, error) {
+2 -2
View File
@@ -6,7 +6,7 @@ package cli
import (
"encoding/json"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/internal/groups"
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/spf13/cobra"
)
@@ -28,7 +28,7 @@ var cmdGroups = []cobra.Command{
logErrorCmd(*cmd, err)
return
}
group.Status = mgclients.EnabledStatus.String()
group.Status = groups.EnabledStatus.String()
group, err := sdk.CreateGroup(group, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
+2 -2
View File
@@ -6,8 +6,8 @@ package cli
import (
"encoding/json"
mgclients "github.com/absmach/magistrala/pkg/clients"
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/absmach/magistrala/things"
"github.com/spf13/cobra"
)
@@ -29,7 +29,7 @@ var cmdThings = []cobra.Command{
logErrorCmd(*cmd, err)
return
}
thing.Status = mgclients.EnabledStatus.String()
thing.Status = things.EnabledStatus.String()
thing, err := sdk.CreateThing(thing, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
+2 -2
View File
@@ -13,11 +13,11 @@ import (
"github.com/absmach/magistrala/cli"
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/apiutil"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
sdk "github.com/absmach/magistrala/pkg/sdk/go"
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
"github.com/absmach/magistrala/things"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
@@ -37,7 +37,7 @@ var thing = sdk.Thing{
Secret: "secret",
},
DomainID: testsutil.GenerateUUID(&testing.T{}),
Status: mgclients.EnabledStatus.String(),
Status: things.EnabledStatus.String(),
}
func TestCreateThingsCmd(t *testing.T) {
+2 -2
View File
@@ -12,11 +12,11 @@ import (
"github.com/absmach/magistrala/cli"
"github.com/absmach/magistrala/internal/testsutil"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
mgsdk "github.com/absmach/magistrala/pkg/sdk/go"
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
"github.com/absmach/magistrala/users"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
@@ -29,7 +29,7 @@ var user = mgsdk.User{
Secret: "testpassword",
Username: "testusername",
},
Status: mgclients.EnabledStatus.String(),
Status: users.EnabledStatus.String(),
}
var (
+2 -2
View File
@@ -15,7 +15,6 @@ import (
chclient "github.com/absmach/callhome/pkg/client"
"github.com/absmach/magistrala"
mglog "github.com/absmach/magistrala/logger"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
mggroups "github.com/absmach/magistrala/pkg/groups"
mgsdk "github.com/absmach/magistrala/pkg/sdk/go"
@@ -24,6 +23,7 @@ import (
"github.com/absmach/magistrala/pkg/uuid"
"github.com/absmach/magistrala/provision"
"github.com/absmach/magistrala/provision/api"
"github.com/absmach/magistrala/things"
"github.com/caarlos0/env/v11"
"golang.org/x/sync/errgroup"
)
@@ -147,7 +147,7 @@ func loadConfig() (provision.Config, error) {
Metadata: map[string]interface{}{"type": "data"},
},
}
cfg.Things = []mgclients.Client{
cfg.Things = []things.Client{
{
Name: "thing",
Metadata: map[string]interface{}{"external_id": "xxxxxx"},
+1 -1
View File
@@ -246,7 +246,7 @@ func newService(ctx context.Context, db *sqlx.DB, dbConfig pgclient.Config, auth
thingCache := thcache.NewCache(cacheClient, keyDuration)
csvc := things.NewService(pe, ps, cRepo, gRepo, thingCache, idp)
csvc := things.NewService(pe, ps, cRepo, thingCache, idp)
gsvc := mggroups.NewService(gRepo, idp, ps)
csvc, err := thevents.NewEventStoreMiddleware(ctx, csvc, esURL)
+2 -1
View File
@@ -51,7 +51,6 @@ require (
go.opentelemetry.io/otel/sdk v1.31.0
go.opentelemetry.io/otel/trace v1.31.0
golang.org/x/crypto v0.28.0
golang.org/x/net v0.30.0
golang.org/x/oauth2 v0.23.0
golang.org/x/sync v0.8.0
gonum.org/v1/gonum v0.15.1
@@ -110,6 +109,7 @@ require (
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v4 v4.18.3 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jtolds/gls v4.20.0+incompatible // indirect
github.com/jzelinskie/stringz v0.0.3 // indirect
@@ -164,6 +164,7 @@ require (
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/time v0.6.0 // indirect
+2 -1
View File
@@ -233,8 +233,9 @@ github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU=
github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA=
github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+6 -3
View File
@@ -11,10 +11,12 @@ import (
"github.com/absmach/magistrala"
"github.com/absmach/magistrala/bootstrap"
"github.com/absmach/magistrala/certs"
"github.com/absmach/magistrala/internal/groups"
"github.com/absmach/magistrala/pkg/apiutil"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/things"
"github.com/absmach/magistrala/users"
"github.com/gofrs/uuid/v5"
)
@@ -56,8 +58,9 @@ const (
DefLimit = 10
DefLevel = 0
DefStatus = "enabled"
DefClientStatus = mgclients.Enabled
DefGroupStatus = mgclients.Enabled
DefClientStatus = things.Enabled
DefUserStatus = users.Enabled
DefGroupStatus = groups.Enabled
DefListPerms = false
SharedVisibility = "shared"
MyVisibility = "mine"
+1 -2
View File
@@ -11,7 +11,6 @@ import (
"github.com/absmach/magistrala/internal/api"
"github.com/absmach/magistrala/pkg/apiutil"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
mggroups "github.com/absmach/magistrala/pkg/groups"
"github.com/go-chi/chi/v5"
@@ -245,7 +244,7 @@ func decodePageMeta(r *http.Request) (mggroups.PageMeta, error) {
if err != nil {
return mggroups.PageMeta{}, errors.Wrap(apiutil.ErrValidation, err)
}
st, err := mgclients.ToStatus(s)
st, err := mggroups.ToStatus(s)
if err != nil {
return mggroups.PageMeta{}, errors.Wrap(apiutil.ErrValidation, err)
}
+8 -9
View File
@@ -13,7 +13,6 @@ import (
"github.com/absmach/magistrala/internal/api"
"github.com/absmach/magistrala/pkg/apiutil"
"github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
"github.com/absmach/magistrala/pkg/groups"
"github.com/stretchr/testify/assert"
@@ -51,11 +50,11 @@ func TestDecodeListGroupsRequest(t *testing.T) {
resp: listGroupsReq{
Page: groups.Page{
PageMeta: groups.PageMeta{
Status: clients.EnabledStatus,
Status: groups.EnabledStatus,
Offset: 10,
Limit: 10,
Name: "random",
Metadata: clients.Metadata{
Metadata: groups.Metadata{
"test": "test",
},
},
@@ -166,11 +165,11 @@ func TestDecodeListParentsRequest(t *testing.T) {
resp: listGroupsReq{
Page: groups.Page{
PageMeta: groups.PageMeta{
Status: clients.EnabledStatus,
Status: groups.EnabledStatus,
Offset: 10,
Limit: 10,
Name: "random",
Metadata: clients.Metadata{
Metadata: groups.Metadata{
"test": "test",
},
},
@@ -261,11 +260,11 @@ func TestDecodeListChildrenRequest(t *testing.T) {
resp: listGroupsReq{
Page: groups.Page{
PageMeta: groups.PageMeta{
Status: clients.EnabledStatus,
Status: groups.EnabledStatus,
Offset: 10,
Limit: 10,
Name: "random",
Metadata: clients.Metadata{
Metadata: groups.Metadata{
"test": "test",
},
},
@@ -400,11 +399,11 @@ func TestDecodePageMeta(t *testing.T) {
desc: "valid request with all parameters",
url: "http://localhost:8080?status=enabled&offset=10&limit=10&name=random&metadata={\"test\":\"test\"}",
resp: groups.PageMeta{
Status: clients.EnabledStatus,
Status: groups.EnabledStatus,
Offset: 10,
Limit: 10,
Name: "random",
Metadata: clients.Metadata{
Metadata: groups.Metadata{
"test": "test",
},
},
+6 -7
View File
@@ -14,7 +14,6 @@ import (
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/apiutil"
mgauthn "github.com/absmach/magistrala/pkg/authn"
"github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/pkg/groups"
@@ -31,14 +30,14 @@ var (
Description: valid,
Domain: testsutil.GenerateUUID(&testing.T{}),
Parent: testsutil.GenerateUUID(&testing.T{}),
Metadata: clients.Metadata{
Metadata: groups.Metadata{
"name": "test",
},
Children: []*groups.Group{},
CreatedAt: time.Now().Add(-1 * time.Second),
UpdatedAt: time.Now(),
UpdatedBy: testsutil.GenerateUUID(&testing.T{}),
Status: clients.EnabledStatus,
Status: groups.EnabledStatus,
}
validID = testsutil.GenerateUUID(&testing.T{})
)
@@ -564,7 +563,7 @@ func TestListGroupsEndpoint(t *testing.T) {
Description: valid,
Domain: testsutil.GenerateUUID(t),
Parent: validGroupResp.ID,
Metadata: clients.Metadata{
Metadata: groups.Metadata{
"name": "test",
},
Level: -1,
@@ -572,14 +571,14 @@ func TestListGroupsEndpoint(t *testing.T) {
CreatedAt: time.Now().Add(-1 * time.Second),
UpdatedAt: time.Now(),
UpdatedBy: testsutil.GenerateUUID(t),
Status: clients.EnabledStatus,
Status: groups.EnabledStatus,
}
parentGroup := groups.Group{
ID: testsutil.GenerateUUID(t),
Name: valid,
Description: valid,
Domain: testsutil.GenerateUUID(t),
Metadata: clients.Metadata{
Metadata: groups.Metadata{
"name": "test",
},
Level: 1,
@@ -587,7 +586,7 @@ func TestListGroupsEndpoint(t *testing.T) {
CreatedAt: time.Now().Add(-1 * time.Second),
UpdatedAt: time.Now(),
UpdatedBy: testsutil.GenerateUUID(t),
Status: clients.EnabledStatus,
Status: groups.EnabledStatus,
}
validGroupResp.Children = append(validGroupResp.Children, &childGroup)
+30 -30
View File
@@ -11,9 +11,9 @@ import (
"strings"
"time"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
"github.com/absmach/magistrala/pkg/groups"
mggroups "github.com/absmach/magistrala/pkg/groups"
"github.com/absmach/magistrala/pkg/postgres"
"github.com/jmoiron/sqlx"
@@ -71,7 +71,7 @@ func (repo groupRepository) Update(ctx context.Context, g mggroups.Group) (mggro
if len(query) > 0 {
upq = strings.Join(query, " ")
}
g.Status = mgclients.EnabledStatus
g.Status = mggroups.EnabledStatus
q := fmt.Sprintf(`UPDATE groups SET %s updated_at = :updated_at, updated_by = :updated_by
WHERE id = :id AND status = :status
RETURNING id, name, description, domain_id, COALESCE(parent_id, '') AS parent_id, metadata, created_at, updated_at, updated_by, status`, upq)
@@ -337,7 +337,7 @@ func buildQuery(gm mggroups.Page, ids ...string) string {
if gm.PageMeta.ID != "" {
queries = append(queries, "g.id ILIKE '%' || :id || '%'")
}
if gm.Status != mgclients.AllStatus {
if gm.Status != mggroups.AllStatus {
queries = append(queries, "g.status = :status")
}
if gm.DomainID != "" {
@@ -354,18 +354,18 @@ func buildQuery(gm mggroups.Page, ids ...string) string {
}
type dbGroup struct {
ID string `db:"id"`
ParentID *string `db:"parent_id,omitempty"`
DomainID string `db:"domain_id,omitempty"`
Name string `db:"name"`
Description string `db:"description,omitempty"`
Level int `db:"level"`
Path string `db:"path,omitempty"`
Metadata []byte `db:"metadata,omitempty"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt sql.NullTime `db:"updated_at,omitempty"`
UpdatedBy *string `db:"updated_by,omitempty"`
Status mgclients.Status `db:"status"`
ID string `db:"id"`
ParentID *string `db:"parent_id,omitempty"`
DomainID string `db:"domain_id,omitempty"`
Name string `db:"name"`
Description string `db:"description,omitempty"`
Level int `db:"level"`
Path string `db:"path,omitempty"`
Metadata []byte `db:"metadata,omitempty"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt sql.NullTime `db:"updated_at,omitempty"`
UpdatedBy *string `db:"updated_by,omitempty"`
Status mggroups.Status `db:"status"`
}
func toDBGroup(g mggroups.Group) (dbGroup, error) {
@@ -405,7 +405,7 @@ func toDBGroup(g mggroups.Group) (dbGroup, error) {
}
func toGroup(g dbGroup) (mggroups.Group, error) {
var metadata mgclients.Metadata
var metadata groups.Metadata
if g.Metadata != nil {
if err := json.Unmarshal(g.Metadata, &metadata); err != nil {
return mggroups.Group{}, errors.Wrap(repoerr.ErrMalformedEntity, err)
@@ -469,20 +469,20 @@ func toDBGroupPage(pm mggroups.Page) (dbGroupPage, error) {
}
type dbGroupPage struct {
ClientID string `db:"client_id"`
ID string `db:"id"`
Name string `db:"name"`
ParentID string `db:"parent_id"`
DomainID string `db:"domain_id"`
Metadata []byte `db:"metadata"`
Path string `db:"path"`
Level uint64 `db:"level"`
Total uint64 `db:"total"`
Limit uint64 `db:"limit"`
Offset uint64 `db:"offset"`
Subject string `db:"subject"`
Action string `db:"action"`
Status mgclients.Status `db:"status"`
ClientID string `db:"client_id"`
ID string `db:"id"`
Name string `db:"name"`
ParentID string `db:"parent_id"`
DomainID string `db:"domain_id"`
Metadata []byte `db:"metadata"`
Path string `db:"path"`
Level uint64 `db:"level"`
Total uint64 `db:"total"`
Limit uint64 `db:"limit"`
Offset uint64 `db:"offset"`
Subject string `db:"subject"`
Action string `db:"action"`
Status mggroups.Status `db:"status"`
}
func (repo groupRepository) processRows(rows *sqlx.Rows) ([]mggroups.Group, error) {
+16 -17
View File
@@ -13,7 +13,6 @@ import (
"github.com/0x6flab/namegenerator"
"github.com/absmach/magistrala/internal/groups/postgres"
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
mggroups "github.com/absmach/magistrala/pkg/groups"
@@ -31,7 +30,7 @@ var (
Description: strings.Repeat("a", 64),
Metadata: map[string]interface{}{"key": "value"},
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
Status: clients.EnabledStatus,
Status: mggroups.EnabledStatus,
}
)
@@ -67,7 +66,7 @@ func TestSave(t *testing.T) {
Description: strings.Repeat("a", 64),
Metadata: map[string]interface{}{"key": "value"},
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
Status: clients.EnabledStatus,
Status: mggroups.EnabledStatus,
},
err: repoerr.ErrMalformedEntity,
},
@@ -80,7 +79,7 @@ func TestSave(t *testing.T) {
Description: strings.Repeat("a", 64),
Metadata: map[string]interface{}{"key": "value"},
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
Status: clients.EnabledStatus,
Status: mggroups.EnabledStatus,
},
err: repoerr.ErrMalformedEntity,
},
@@ -93,7 +92,7 @@ func TestSave(t *testing.T) {
Description: strings.Repeat("a", 64),
Metadata: map[string]interface{}{"key": "value"},
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
Status: clients.EnabledStatus,
Status: mggroups.EnabledStatus,
},
err: repoerr.ErrMalformedEntity,
},
@@ -106,7 +105,7 @@ func TestSave(t *testing.T) {
Description: strings.Repeat("a", 64),
Metadata: map[string]interface{}{"key": "value"},
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
Status: clients.EnabledStatus,
Status: mggroups.EnabledStatus,
},
err: repoerr.ErrMalformedEntity,
},
@@ -119,7 +118,7 @@ func TestSave(t *testing.T) {
Description: strings.Repeat("a", 1025),
Metadata: map[string]interface{}{"key": "value"},
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
Status: clients.EnabledStatus,
Status: mggroups.EnabledStatus,
},
err: repoerr.ErrMalformedEntity,
},
@@ -134,7 +133,7 @@ func TestSave(t *testing.T) {
"key": make(chan int),
},
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
Status: clients.EnabledStatus,
Status: mggroups.EnabledStatus,
},
err: repoerr.ErrMalformedEntity,
},
@@ -146,7 +145,7 @@ func TestSave(t *testing.T) {
Description: strings.Repeat("a", 64),
Metadata: map[string]interface{}{"key": "value"},
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
Status: clients.EnabledStatus,
Status: mggroups.EnabledStatus,
},
err: repoerr.ErrMalformedEntity,
},
@@ -158,7 +157,7 @@ func TestSave(t *testing.T) {
Description: strings.Repeat("a", 64),
Metadata: map[string]interface{}{"key": "value"},
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
Status: clients.EnabledStatus,
Status: mggroups.EnabledStatus,
},
err: repoerr.ErrMalformedEntity,
},
@@ -291,7 +290,7 @@ func TestChangeStatus(t *testing.T) {
desc: "change status group successfully",
group: mggroups.Group{
ID: group.ID,
Status: clients.DisabledStatus,
Status: mggroups.DisabledStatus,
UpdatedAt: time.Now().UTC().Truncate(time.Microsecond),
UpdatedBy: testsutil.GenerateUUID(t),
},
@@ -301,7 +300,7 @@ func TestChangeStatus(t *testing.T) {
desc: "change status group with invalid ID",
group: mggroups.Group{
ID: testsutil.GenerateUUID(t),
Status: clients.DisabledStatus,
Status: mggroups.DisabledStatus,
UpdatedAt: time.Now().UTC().Truncate(time.Microsecond),
UpdatedBy: testsutil.GenerateUUID(t),
},
@@ -310,7 +309,7 @@ func TestChangeStatus(t *testing.T) {
{
desc: "change status group with empty ID",
group: mggroups.Group{
Status: clients.DisabledStatus,
Status: mggroups.DisabledStatus,
UpdatedAt: time.Now().UTC().Truncate(time.Microsecond),
UpdatedBy: testsutil.GenerateUUID(t),
},
@@ -400,7 +399,7 @@ func TestRetrieveAll(t *testing.T) {
Description: strings.Repeat("a", 64),
Metadata: map[string]interface{}{"name": name},
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
Status: clients.EnabledStatus,
Status: mggroups.EnabledStatus,
}
_, err := repo.Save(context.Background(), group)
require.Nil(t, err, fmt.Sprintf("create invitation unexpected error: %s", err))
@@ -712,7 +711,7 @@ func TestRetrieveByIDs(t *testing.T) {
Description: strings.Repeat("a", 64),
Metadata: map[string]interface{}{"name": name},
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
Status: clients.EnabledStatus,
Status: mggroups.EnabledStatus,
}
_, err := repo.Save(context.Background(), group)
require.Nil(t, err, fmt.Sprintf("create invitation unexpected error: %s", err))
@@ -1069,7 +1068,7 @@ func TestAssignParentGroup(t *testing.T) {
Description: strings.Repeat("a", 64),
Metadata: map[string]interface{}{"name": name},
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
Status: clients.EnabledStatus,
Status: mggroups.EnabledStatus,
}
_, err := repo.Save(context.Background(), group)
require.Nil(t, err, fmt.Sprintf("create invitation unexpected error: %s", err))
@@ -1147,7 +1146,7 @@ func TestUnassignParentGroup(t *testing.T) {
Description: strings.Repeat("a", 64),
Metadata: map[string]interface{}{"name": name},
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
Status: clients.EnabledStatus,
Status: mggroups.EnabledStatus,
}
_, err := repo.Save(context.Background(), group)
require.Nil(t, err, fmt.Sprintf("create invitation unexpected error: %s", err))
+3 -4
View File
@@ -12,7 +12,6 @@ import (
mgauth "github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/pkg/apiutil"
"github.com/absmach/magistrala/pkg/authn"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/pkg/groups"
@@ -45,7 +44,7 @@ func (svc service) CreateGroup(ctx context.Context, session authn.Session, kind
if err != nil {
return groups.Group{}, err
}
if g.Status != mgclients.EnabledStatus && g.Status != mgclients.DisabledStatus {
if g.Status != groups.EnabledStatus && g.Status != groups.DisabledStatus {
return groups.Group{}, svcerr.ErrInvalidStatus
}
@@ -282,7 +281,7 @@ func (svc service) UpdateGroup(ctx context.Context, session authn.Session, g gro
func (svc service) EnableGroup(ctx context.Context, session authn.Session, id string) (groups.Group, error) {
group := groups.Group{
ID: id,
Status: mgclients.EnabledStatus,
Status: groups.EnabledStatus,
UpdatedAt: time.Now(),
}
group, err := svc.changeGroupStatus(ctx, session, group)
@@ -295,7 +294,7 @@ func (svc service) EnableGroup(ctx context.Context, session authn.Session, id st
func (svc service) DisableGroup(ctx context.Context, session authn.Session, id string) (groups.Group, error) {
group := groups.Group{
ID: id,
Status: mgclients.DisabledStatus,
Status: groups.DisabledStatus,
UpdatedAt: time.Now(),
}
group, err := svc.changeGroupStatus(ctx, session, group)
+8 -9
View File
@@ -16,7 +16,6 @@ import (
"github.com/absmach/magistrala/pkg/apiutil"
"github.com/absmach/magistrala/pkg/authn"
mgauthn "github.com/absmach/magistrala/pkg/authn"
"github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
@@ -38,7 +37,7 @@ var (
Metadata: map[string]interface{}{
"key": "value",
},
Status: clients.Status(groups.EnabledStatus),
Status: mggroups.EnabledStatus,
}
allowedIDs = []string{
testsutil.GenerateUUID(&testing.T{}),
@@ -83,7 +82,7 @@ func TestCreateGroup(t *testing.T) {
group: mggroups.Group{
Name: namegen.Generate(),
Description: namegen.Generate(),
Status: clients.Status(100),
Status: mggroups.Status(100),
},
err: svcerr.ErrInvalidStatus,
},
@@ -94,7 +93,7 @@ func TestCreateGroup(t *testing.T) {
group: mggroups.Group{
Name: namegen.Generate(),
Description: namegen.Generate(),
Status: clients.Status(groups.EnabledStatus),
Status: mggroups.EnabledStatus,
Parent: testsutil.GenerateUUID(t),
},
repoResp: mggroups.Group{
@@ -131,7 +130,7 @@ func TestCreateGroup(t *testing.T) {
group: mggroups.Group{
Name: namegen.Generate(),
Description: namegen.Generate(),
Status: clients.Status(groups.EnabledStatus),
Status: mggroups.EnabledStatus,
Parent: testsutil.GenerateUUID(t),
},
repoErr: errors.ErrMalformedEntity,
@@ -327,7 +326,7 @@ func TestEnableGroup(t *testing.T) {
session: authn.Session{UserID: validID, DomainID: validID, DomainUserID: validID},
id: testsutil.GenerateUUID(t),
retrieveResp: mggroups.Group{
Status: clients.Status(groups.DisabledStatus),
Status: mggroups.DisabledStatus,
},
changeResp: validGroup,
},
@@ -336,7 +335,7 @@ func TestEnableGroup(t *testing.T) {
session: authn.Session{UserID: validID, DomainID: validID, DomainUserID: validID},
id: testsutil.GenerateUUID(t),
retrieveResp: mggroups.Group{
Status: clients.Status(groups.EnabledStatus),
Status: mggroups.EnabledStatus,
},
err: errors.ErrStatusAlreadyAssigned,
},
@@ -387,7 +386,7 @@ func TestDisableGroup(t *testing.T) {
session: authn.Session{UserID: validID, DomainID: validID, DomainUserID: validID},
id: testsutil.GenerateUUID(t),
retrieveResp: mggroups.Group{
Status: clients.Status(groups.EnabledStatus),
Status: mggroups.EnabledStatus,
},
changeResp: validGroup,
},
@@ -396,7 +395,7 @@ func TestDisableGroup(t *testing.T) {
session: authn.Session{UserID: validID, DomainID: validID, DomainUserID: validID},
id: testsutil.GenerateUUID(t),
retrieveResp: mggroups.Group{
Status: clients.Status(groups.DisabledStatus),
Status: mggroups.DisabledStatus,
},
err: errors.ErrStatusAlreadyAssigned,
},
-175
View File
@@ -1,175 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package clients
import (
"context"
"fmt"
"regexp"
"strings"
"time"
"github.com/absmach/magistrala/pkg/errors"
"golang.org/x/net/idna"
)
const (
maxLocalLen = 64
maxDomainLen = 255
maxTLDLen = 24 // longest TLD currently in existence
atSeparator = "@"
dotSeparator = "."
)
var (
userRegexp = regexp.MustCompile("^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+$")
hostRegexp = regexp.MustCompile(`^[^\s]+\.[^\s]+$`)
userDotRegexp = regexp.MustCompile("(^[.]{1})|([.]{1}$)|([.]{2,})")
)
// Credentials represent client credentials: its
// "identity" which can be a username, email, generated name;
// and "secret" which can be a password or access token.
type Credentials struct {
Identity string `json:"identity,omitempty"` // username or generated login ID
Secret string `json:"secret,omitempty"` // password or token
}
// Client represents generic Client.
type Client struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Tags []string `json:"tags,omitempty"`
Domain string `json:"domain_id,omitempty"`
Credentials Credentials `json:"credentials,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
UpdatedBy string `json:"updated_by,omitempty"`
Status Status `json:"status,omitempty"` // 1 for enabled, 0 for disabled
Permissions []string `json:"permissions,omitempty"`
}
// ClientsPage contains page related metadata as well as list
// of Clients that belong to the page.
type ClientsPage struct {
Page
Clients []Client
}
// MembersPage contains page related metadata as well as list of members that
// belong to this page.
type MembersPage struct {
Page
Members []Client
}
// Repository specifies an account persistence API.
type Repository interface {
// RetrieveByID retrieves client by its unique ID.
RetrieveByID(ctx context.Context, id string) (Client, error)
// RetrieveByIdentity retrieves client by its unique credentials
RetrieveByIdentity(ctx context.Context, identity string) (Client, error)
// RetrieveAll retrieves all clients.
RetrieveAll(ctx context.Context, pm Page) (ClientsPage, error)
// SearchClients retrieves clients based on search criteria.
SearchClients(ctx context.Context, pm Page) (ClientsPage, error)
// RetrieveAllByIDs retrieves for given client IDs .
RetrieveAllByIDs(ctx context.Context, pm Page) (ClientsPage, error)
// Update updates the client name and metadata.
Update(ctx context.Context, client Client) (Client, error)
// UpdateTags updates the client tags.
UpdateTags(ctx context.Context, client Client) (Client, error)
// UpdateIdentity updates identity for client with given id.
UpdateIdentity(ctx context.Context, client Client) (Client, error)
// UpdateSecret updates secret for client with given identity.
UpdateSecret(ctx context.Context, client Client) (Client, error)
// UpdateRole updates role for client with given id.
UpdateRole(ctx context.Context, client Client) (Client, error)
// ChangeStatus changes client status to enabled or disabled
ChangeStatus(ctx context.Context, client Client) (Client, error)
// Delete deletes client with given id
Delete(ctx context.Context, id string) error
}
// Validate returns an error if client representation is invalid.
func (u Client) Validate() error {
if !isEmail(u.Credentials.Identity) {
return errors.ErrMalformedEntity
}
return nil
}
func isEmail(email string) bool {
if email == "" {
return false
}
es := strings.Split(email, atSeparator)
if len(es) != 2 {
return false
}
local, host := es[0], es[1]
if local == "" || len(local) > maxLocalLen {
return false
}
hs := strings.Split(host, dotSeparator)
if len(hs) < 2 {
return false
}
domain, ext := hs[0], hs[1]
// Check subdomain and validate
if len(hs) > 2 {
if domain == "" {
return false
}
for i := 1; i < len(hs)-1; i++ {
sub := hs[i]
if sub == "" {
return false
}
domain = fmt.Sprintf("%s.%s", domain, sub)
}
ext = hs[len(hs)-1]
}
if domain == "" || len(domain) > maxDomainLen {
return false
}
if ext == "" || len(ext) > maxTLDLen {
return false
}
punyLocal, err := idna.ToASCII(local)
if err != nil {
return false
}
punyHost, err := idna.ToASCII(host)
if err != nil {
return false
}
if userDotRegexp.MatchString(punyLocal) || !userRegexp.MatchString(punyLocal) || !hostRegexp.MatchString(punyHost) {
return false
}
return true
}
-157
View File
@@ -1,157 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package clients
import (
"testing"
"github.com/absmach/magistrala/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestValidateClient(t *testing.T) {
cases := []struct {
desc string
identity string
err error
}{
{
desc: "valid identity",
identity: "user@example.com",
err: nil,
},
{
desc: "invalid identity",
identity: "user@example",
err: errors.ErrMalformedEntity,
},
{
desc: "empty identity",
err: errors.ErrMalformedEntity,
},
}
for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
client := Client{
Credentials: Credentials{
Identity: c.identity,
},
}
err := client.Validate()
assert.Equal(t, c.err, err, "ValidateClient() error = %v, expected %v", err, c.err)
})
}
}
func TestIsEmail(t *testing.T) {
cases := []struct {
email string
expected bool
}{
{
email: "test@example.com",
expected: true,
},
{
email: "test-test@example.com",
expected: true,
},
{
email: "test.test@example.com",
expected: true,
},
{
email: "test_test@example.com",
expected: true,
},
{
email: "test@",
expected: false,
},
{
email: "@",
expected: false,
},
{
email: "test.example.com",
expected: false,
},
{
email: "@example.com",
expected: false,
},
{
email: "test@example",
expected: false,
},
{
email: "test@example.",
expected: false,
},
{
email: "test@.com",
expected: false,
},
{
email: "test@.example.com",
expected: false,
},
{
email: "test@example.com.",
expected: false,
},
{
email: "test@example.",
expected: false,
},
{
email: "test@subdomain.example.com",
expected: true,
},
{
email: "test@subdomain-example.com",
expected: true,
},
{
email: "test@subdomain_example.com",
expected: true,
},
{
email: "@subdomain.example.com",
expected: false,
},
{
email: "test@subdomain.subdomain.example.com",
expected: true,
},
{
email: "test@subdomain..com",
expected: false,
},
{
email: "test@subdomain..example.com",
expected: false,
},
{
email: "test@subdomain.example..com",
expected: false,
},
{
email: "test@subdomain.example.com.",
expected: false,
},
{
email: "test@subdomain.example.com..",
expected: false,
},
}
for _, c := range cases {
isValid := isEmail(c.email)
if isValid != c.expected {
t.Errorf("Expected isEmail(%s) to be %v, but got %v", c.email, c.expected, isValid)
}
}
}
-6
View File
@@ -1,6 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
// Package clients contains the domain concept definitions needed to support
// Magistrala clients functionality.
package clients
-27
View File
@@ -1,27 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package clients
// Page contains page metadata that helps navigation.
type Page struct {
Total uint64 `json:"total"`
Offset uint64 `json:"offset"`
Limit uint64 `json:"limit"`
Name string `json:"name,omitempty"`
Id string `json:"id,omitempty"`
Order string `json:"order,omitempty"`
Dir string `json:"dir,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
Domain string `json:"domain,omitempty"`
Tag string `json:"tag,omitempty"`
Permission string `json:"permission,omitempty"`
Status Status `json:"status,omitempty"`
IDs []string `json:"ids,omitempty"`
Identity string `json:"identity,omitempty"`
Role Role `json:"-"`
ListPerms bool `json:"-"`
Username string `json:"username,omitempty"`
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
}
-525
View File
@@ -1,525 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package postgres
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/absmach/magistrala/internal/api"
"github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
"github.com/absmach/magistrala/pkg/groups"
"github.com/absmach/magistrala/pkg/postgres"
"github.com/jackc/pgtype"
)
type Repository struct {
DB postgres.Database
}
func (repo *Repository) Update(ctx context.Context, client clients.Client) (clients.Client, error) {
var query []string
var upq string
if client.Name != "" {
query = append(query, "name = :name,")
}
if client.Metadata != nil {
query = append(query, "metadata = :metadata,")
}
if len(query) > 0 {
upq = strings.Join(query, " ")
}
q := fmt.Sprintf(`UPDATE clients SET %s updated_at = :updated_at, updated_by = :updated_by
WHERE id = :id AND status = :status
RETURNING id, name, tags, identity, secret, metadata, COALESCE(domain_id, '') AS domain_id, status, created_at, updated_at, updated_by`,
upq)
client.Status = clients.EnabledStatus
return repo.update(ctx, client, q)
}
func (repo *Repository) UpdateTags(ctx context.Context, client clients.Client) (clients.Client, error) {
q := `UPDATE clients SET tags = :tags, updated_at = :updated_at, updated_by = :updated_by
WHERE id = :id AND status = :status
RETURNING id, name, tags, identity, metadata, COALESCE(domain_id, '') AS domain_id, status, created_at, updated_at, updated_by`
client.Status = clients.EnabledStatus
return repo.update(ctx, client, q)
}
func (repo *Repository) UpdateIdentity(ctx context.Context, client clients.Client) (clients.Client, error) {
q := `UPDATE clients SET identity = :identity, updated_at = :updated_at, updated_by = :updated_by
WHERE id = :id AND status = :status
RETURNING id, name, tags, identity, metadata, COALESCE(domain_id, '') AS domain_id, status, created_at, updated_at, updated_by`
client.Status = clients.EnabledStatus
return repo.update(ctx, client, q)
}
func (repo *Repository) UpdateSecret(ctx context.Context, client clients.Client) (clients.Client, error) {
q := `UPDATE clients SET secret = :secret, updated_at = :updated_at, updated_by = :updated_by
WHERE id = :id AND status = :status
RETURNING id, name, tags, identity, metadata, COALESCE(domain_id, '') AS domain_id, status, created_at, updated_at, updated_by`
client.Status = clients.EnabledStatus
return repo.update(ctx, client, q)
}
func (repo *Repository) UpdateRole(ctx context.Context, client clients.Client) (clients.Client, error) {
q := `UPDATE clients SET role = :role, updated_at = :updated_at, updated_by = :updated_by
WHERE id = :id AND status = :status
RETURNING id, name, tags, identity, metadata, COALESCE(domain_id, '') AS domain_id, status, role, created_at, updated_at, updated_by`
client.Status = clients.EnabledStatus
return repo.update(ctx, client, q)
}
func (repo *Repository) ChangeStatus(ctx context.Context, client clients.Client) (clients.Client, error) {
q := `UPDATE clients SET status = :status, updated_at = :updated_at, updated_by = :updated_by
WHERE id = :id
RETURNING id, name, tags, identity, metadata, COALESCE(domain_id, '') AS domain_id, status, created_at, updated_at, updated_by`
return repo.update(ctx, client, q)
}
func (repo *Repository) RetrieveByID(ctx context.Context, id string) (clients.Client, error) {
q := `SELECT id, name, tags, COALESCE(domain_id, '') AS domain_id, identity, secret, metadata, created_at, updated_at, updated_by, status
FROM clients WHERE id = :id`
dbc := DBClient{
ID: id,
}
row, err := repo.DB.NamedQueryContext(ctx, q, dbc)
if err != nil {
return clients.Client{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
defer row.Close()
dbc = DBClient{}
if row.Next() {
if err := row.StructScan(&dbc); err != nil {
return clients.Client{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
return ToClient(dbc)
}
return clients.Client{}, repoerr.ErrNotFound
}
func (repo *Repository) RetrieveByIdentity(ctx context.Context, identity string) (clients.Client, error) {
q := `SELECT id, name, tags, COALESCE(domain_id, '') AS domain_id, identity, secret, metadata, created_at, updated_at, updated_by, status
FROM clients WHERE identity = :identity AND status = :status`
dbc := DBClient{
Identity: identity,
Status: clients.EnabledStatus,
}
row, err := repo.DB.NamedQueryContext(ctx, q, dbc)
if err != nil {
return clients.Client{}, postgres.HandleError(repoerr.ErrViewEntity, err)
}
defer row.Close()
dbc = DBClient{}
if row.Next() {
if err := row.StructScan(&dbc); err != nil {
return clients.Client{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
return ToClient(dbc)
}
return clients.Client{}, repoerr.ErrNotFound
}
func (repo *Repository) RetrieveAll(ctx context.Context, pm clients.Page) (clients.ClientsPage, error) {
query, err := PageQuery(pm)
if err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
query = applyOrdering(query, pm)
q := fmt.Sprintf(`SELECT c.id, c.name, c.tags, c.identity, c.metadata, COALESCE(c.domain_id, '') AS domain_id, c.status,
c.created_at, c.updated_at, COALESCE(c.updated_by, '') AS updated_by FROM clients c %s ORDER BY c.created_at LIMIT :limit OFFSET :offset;`, query)
dbPage, err := ToDBClientsPage(pm)
if err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrFailedToRetrieveAllGroups, err)
}
rows, err := repo.DB.NamedQueryContext(ctx, q, dbPage)
if err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrFailedToRetrieveAllGroups, err)
}
defer rows.Close()
var items []clients.Client
for rows.Next() {
dbc := DBClient{}
if err := rows.StructScan(&dbc); err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
c, err := ToClient(dbc)
if err != nil {
return clients.ClientsPage{}, err
}
items = append(items, c)
}
cq := fmt.Sprintf(`SELECT COUNT(*) FROM clients c %s;`, query)
total, err := postgres.Total(ctx, repo.DB, cq, dbPage)
if err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
page := clients.ClientsPage{
Clients: items,
Page: clients.Page{
Total: total,
Offset: pm.Offset,
Limit: pm.Limit,
},
}
return page, nil
}
func (repo *Repository) SearchClients(ctx context.Context, pm clients.Page) (clients.ClientsPage, error) {
query, err := PageQuery(pm)
if err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
tq := query
query = applyOrdering(query, pm)
q := fmt.Sprintf(`SELECT c.id, c.name, c.created_at, c.updated_at FROM clients c %s LIMIT :limit OFFSET :offset;`, query)
dbPage, err := ToDBClientsPage(pm)
if err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrFailedToRetrieveAllGroups, err)
}
rows, err := repo.DB.NamedQueryContext(ctx, q, dbPage)
if err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrFailedToRetrieveAllGroups, err)
}
defer rows.Close()
var items []clients.Client
for rows.Next() {
dbc := DBClient{}
if err := rows.StructScan(&dbc); err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
c, err := ToClient(dbc)
if err != nil {
return clients.ClientsPage{}, err
}
items = append(items, c)
}
cq := fmt.Sprintf(`SELECT COUNT(*) FROM clients c %s;`, tq)
total, err := postgres.Total(ctx, repo.DB, cq, dbPage)
if err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
page := clients.ClientsPage{
Clients: items,
Page: clients.Page{
Total: total,
Offset: pm.Offset,
Limit: pm.Limit,
},
}
return page, nil
}
func (repo *Repository) RetrieveAllByIDs(ctx context.Context, pm clients.Page) (clients.ClientsPage, error) {
if (len(pm.IDs) == 0) && (pm.Domain == "") {
return clients.ClientsPage{
Page: clients.Page{Total: pm.Total, Offset: pm.Offset, Limit: pm.Limit},
}, nil
}
query, err := PageQuery(pm)
if err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
query = applyOrdering(query, pm)
q := fmt.Sprintf(`SELECT c.id, c.name, c.tags, c.identity, c.metadata, COALESCE(c.domain_id, '') AS domain_id, c.status,
c.created_at, c.updated_at, COALESCE(c.updated_by, '') AS updated_by FROM clients c %s ORDER BY c.created_at LIMIT :limit OFFSET :offset;`, query)
dbPage, err := ToDBClientsPage(pm)
if err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrFailedToRetrieveAllGroups, err)
}
rows, err := repo.DB.NamedQueryContext(ctx, q, dbPage)
if err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrFailedToRetrieveAllGroups, err)
}
defer rows.Close()
var items []clients.Client
for rows.Next() {
dbc := DBClient{}
if err := rows.StructScan(&dbc); err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
c, err := ToClient(dbc)
if err != nil {
return clients.ClientsPage{}, err
}
items = append(items, c)
}
cq := fmt.Sprintf(`SELECT COUNT(*) FROM clients c %s;`, query)
total, err := postgres.Total(ctx, repo.DB, cq, dbPage)
if err != nil {
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
page := clients.ClientsPage{
Clients: items,
Page: clients.Page{
Total: total,
Offset: pm.Offset,
Limit: pm.Limit,
},
}
return page, nil
}
func (repo *Repository) update(ctx context.Context, client clients.Client, query string) (clients.Client, error) {
dbc, err := ToDBClient(client)
if err != nil {
return clients.Client{}, errors.Wrap(repoerr.ErrUpdateEntity, err)
}
row, err := repo.DB.NamedQueryContext(ctx, query, dbc)
if err != nil {
return clients.Client{}, postgres.HandleError(repoerr.ErrUpdateEntity, err)
}
defer row.Close()
dbc = DBClient{}
if row.Next() {
if err := row.StructScan(&dbc); err != nil {
return clients.Client{}, errors.Wrap(repoerr.ErrUpdateEntity, err)
}
return ToClient(dbc)
}
return clients.Client{}, repoerr.ErrNotFound
}
func (repo *Repository) Delete(ctx context.Context, id string) error {
q := "DELETE FROM clients AS c WHERE c.id = $1 ;"
result, err := repo.DB.ExecContext(ctx, q, id)
if err != nil {
return postgres.HandleError(repoerr.ErrRemoveEntity, err)
}
if rows, _ := result.RowsAffected(); rows == 0 {
return repoerr.ErrNotFound
}
return nil
}
type DBClient struct {
ID string `db:"id"`
Name string `db:"name,omitempty"`
Tags pgtype.TextArray `db:"tags,omitempty"`
Identity string `db:"identity"`
Domain string `db:"domain_id"`
Secret string `db:"secret"`
Metadata []byte `db:"metadata,omitempty"`
CreatedAt time.Time `db:"created_at,omitempty"`
UpdatedAt sql.NullTime `db:"updated_at,omitempty"`
UpdatedBy *string `db:"updated_by,omitempty"`
Groups []groups.Group `db:"groups,omitempty"`
Status clients.Status `db:"status,omitempty"`
Role *clients.Role `db:"role,omitempty"`
}
func ToDBClient(c clients.Client) (DBClient, error) {
data := []byte("{}")
if len(c.Metadata) > 0 {
b, err := json.Marshal(c.Metadata)
if err != nil {
return DBClient{}, errors.Wrap(repoerr.ErrMalformedEntity, err)
}
data = b
}
var tags pgtype.TextArray
if err := tags.Set(c.Tags); err != nil {
return DBClient{}, err
}
var updatedBy *string
if c.UpdatedBy != "" {
updatedBy = &c.UpdatedBy
}
var updatedAt sql.NullTime
if c.UpdatedAt != (time.Time{}) {
updatedAt = sql.NullTime{Time: c.UpdatedAt, Valid: true}
}
return DBClient{
ID: c.ID,
Name: c.Name,
Tags: tags,
Domain: c.Domain,
Identity: c.Credentials.Identity,
Secret: c.Credentials.Secret,
Metadata: data,
CreatedAt: c.CreatedAt,
UpdatedAt: updatedAt,
UpdatedBy: updatedBy,
Status: c.Status,
}, nil
}
func ToClient(c DBClient) (clients.Client, error) {
var metadata clients.Metadata
if c.Metadata != nil {
if err := json.Unmarshal([]byte(c.Metadata), &metadata); err != nil {
return clients.Client{}, errors.Wrap(errors.ErrMalformedEntity, err)
}
}
var tags []string
for _, e := range c.Tags.Elements {
tags = append(tags, e.String)
}
var updatedBy string
if c.UpdatedBy != nil {
updatedBy = *c.UpdatedBy
}
var updatedAt time.Time
if c.UpdatedAt.Valid {
updatedAt = c.UpdatedAt.Time
}
cli := clients.Client{
ID: c.ID,
Name: c.Name,
Tags: tags,
Domain: c.Domain,
Credentials: clients.Credentials{
Identity: c.Identity,
Secret: c.Secret,
},
Metadata: metadata,
CreatedAt: c.CreatedAt,
UpdatedAt: updatedAt,
UpdatedBy: updatedBy,
Status: c.Status,
}
return cli, nil
}
func ToDBClientsPage(pm clients.Page) (dbClientsPage, error) {
_, data, err := postgres.CreateMetadataQuery("", pm.Metadata)
if err != nil {
return dbClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
return dbClientsPage{
Name: pm.Name,
Identity: pm.Identity,
Id: pm.Id,
Metadata: data,
Domain: pm.Domain,
Total: pm.Total,
Offset: pm.Offset,
Limit: pm.Limit,
Status: pm.Status,
Tag: pm.Tag,
Role: pm.Role,
}, nil
}
type dbClientsPage struct {
Total uint64 `db:"total"`
Limit uint64 `db:"limit"`
Offset uint64 `db:"offset"`
Name string `db:"name"`
Id string `db:"id"`
Domain string `db:"domain_id"`
Identity string `db:"identity"`
Metadata []byte `db:"metadata"`
Tag string `db:"tag"`
Status clients.Status `db:"status"`
GroupID string `db:"group_id"`
Role clients.Role `db:"role"`
}
func PageQuery(pm clients.Page) (string, error) {
mq, _, err := postgres.CreateMetadataQuery("", pm.Metadata)
if err != nil {
return "", errors.Wrap(errors.ErrMalformedEntity, err)
}
var query []string
if pm.Name != "" {
query = append(query, "name ILIKE '%' || :name || '%'")
}
if pm.Identity != "" {
query = append(query, "identity ILIKE '%' || :identity || '%'")
}
if pm.Id != "" {
query = append(query, "id ILIKE '%' || :id || '%'")
}
if pm.Tag != "" {
query = append(query, "EXISTS (SELECT 1 FROM unnest(tags) AS tag WHERE tag ILIKE '%' || :tag || '%')")
}
// If there are search params presents, use search and ignore other options.
// Always combine role with search params, so len(query) > 1.
if len(query) > 1 {
return fmt.Sprintf("WHERE %s", strings.Join(query, " AND ")), nil
}
if mq != "" {
query = append(query, mq)
}
if len(pm.IDs) != 0 {
query = append(query, fmt.Sprintf("id IN ('%s')", strings.Join(pm.IDs, "','")))
}
if pm.Status != clients.AllStatus {
query = append(query, "c.status = :status")
}
if pm.Domain != "" {
query = append(query, "c.domain_id = :domain_id")
}
var emq string
if len(query) > 0 {
emq = fmt.Sprintf("WHERE %s", strings.Join(query, " AND "))
}
return emq, nil
}
func applyOrdering(emq string, pm clients.Page) string {
switch pm.Order {
case "name", "identity", "created_at", "updated_at":
emq = fmt.Sprintf("%s ORDER BY %s", emq, pm.Order)
if pm.Dir == api.AscDir || pm.Dir == api.DescDir {
emq = fmt.Sprintf("%s %s", emq, pm.Dir)
}
}
return emq
}
File diff suppressed because it is too large Load Diff
-5
View File
@@ -1,5 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
// Package postgres contains the database implementation of clients repository layer.
package postgres
-97
View File
@@ -1,97 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package postgres_test
import (
"database/sql"
"fmt"
"log"
"os"
"testing"
"time"
"github.com/absmach/magistrala/pkg/postgres"
pgClient "github.com/absmach/magistrala/pkg/postgres"
tpostgres "github.com/absmach/magistrala/things/postgres"
"github.com/jmoiron/sqlx"
dockertest "github.com/ory/dockertest/v3"
"github.com/ory/dockertest/v3/docker"
"go.opentelemetry.io/otel"
)
var (
db *sqlx.DB
database postgres.Database
tracer = otel.Tracer("repo_tests")
)
func TestMain(m *testing.M) {
pool, err := dockertest.NewPool("")
if err != nil {
log.Fatalf("Could not connect to docker: %s", err)
}
container, err := pool.RunWithOptions(&dockertest.RunOptions{
Repository: "postgres",
Tag: "16.2-alpine",
Env: []string{
"POSTGRES_USER=test",
"POSTGRES_PASSWORD=test",
"POSTGRES_DB=test",
"listen_addresses = '*'",
},
}, func(config *docker.HostConfig) {
config.AutoRemove = true
config.RestartPolicy = docker.RestartPolicy{Name: "no"}
})
if err != nil {
log.Fatalf("Could not start container: %s", err)
}
port := container.GetPort("5432/tcp")
// exponential backoff-retry, because the application in the container might not be ready to accept connections yet
pool.MaxWait = 120 * time.Second
if err := pool.Retry(func() error {
url := fmt.Sprintf("host=localhost port=%s user=test dbname=test password=test sslmode=disable", port)
db, err := sql.Open("pgx", url)
if err != nil {
return err
}
return db.Ping()
}); err != nil {
log.Fatalf("Could not connect to docker: %s", err)
}
dbConfig := pgClient.Config{
Host: "localhost",
Port: port,
User: "test",
Pass: "test",
Name: "test",
SSLMode: "disable",
SSLCert: "",
SSLKey: "",
SSLRootCert: "",
}
if db, err = pgClient.Setup(dbConfig, *tpostgres.Migration()); err != nil {
log.Fatalf("Could not setup test DB connection: %s", err)
}
if db, err = pgClient.Connect(dbConfig); err != nil {
log.Fatalf("Could not setup test DB connection: %s", err)
}
database = postgres.NewDatabase(db, dbConfig, tracer)
code := m.Run()
// Defers will not be run when using os.Exit
db.Close()
if err := pool.Purge(container); err != nil {
log.Fatalf("Could not purge container: %s", err)
}
os.Exit(code)
}
-7
View File
@@ -1,7 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package clients
// Metadata represents arbitrary JSON.
type Metadata map[string]interface{}
+17 -15
View File
@@ -8,7 +8,6 @@ import (
"time"
"github.com/absmach/magistrala/pkg/authn"
"github.com/absmach/magistrala/pkg/clients"
)
// MaxLevel represents the maximum group hierarchy level.
@@ -19,20 +18,20 @@ const MaxLevel = uint64(5)
// Path in a tree consisting of group IDs
// Paths are unique per domain.
type Group struct {
ID string `json:"id"`
Domain string `json:"domain_id,omitempty"`
Parent string `json:"parent_id,omitempty"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Metadata clients.Metadata `json:"metadata,omitempty"`
Level int `json:"level,omitempty"`
Path string `json:"path,omitempty"`
Children []*Group `json:"children,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
UpdatedBy string `json:"updated_by,omitempty"`
Status clients.Status `json:"status"`
Permissions []string `json:"permissions,omitempty"`
ID string `json:"id"`
Domain string `json:"domain_id,omitempty"`
Parent string `json:"parent_id,omitempty"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
Level int `json:"level,omitempty"`
Path string `json:"path,omitempty"`
Children []*Group `json:"children,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
UpdatedBy string `json:"updated_by,omitempty"`
Status Status `json:"status"`
Permissions []string `json:"permissions,omitempty"`
}
type Member struct {
@@ -62,6 +61,9 @@ type Page struct {
Groups []Group
}
// Metadata represents arbitrary JSON.
type Metadata map[string]interface{}
// Repository specifies a group persistence API.
//
//go:generate mockery --name Repository --output=./mocks --filename repository.go --quiet --note "Copyright (c) Abstract Machines" --unroll-variadic=false
+9 -11
View File
@@ -3,17 +3,15 @@
package groups
import "github.com/absmach/magistrala/pkg/clients"
// PageMeta contains page metadata that helps navigation.
type PageMeta struct {
Total uint64 `json:"total"`
Offset uint64 `json:"offset"`
Limit uint64 `json:"limit"`
Name string `json:"name,omitempty"`
ID string `json:"id,omitempty"`
DomainID string `json:"domain_id,omitempty"`
Tag string `json:"tag,omitempty"`
Metadata clients.Metadata `json:"metadata,omitempty"`
Status clients.Status `json:"status,omitempty"`
Total uint64 `json:"total"`
Offset uint64 `json:"offset"`
Limit uint64 `json:"limit"`
Name string `json:"name,omitempty"`
ID string `json:"id,omitempty"`
DomainID string `json:"domain_id,omitempty"`
Tag string `json:"tag,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
Status Status `json:"status,omitempty"`
}
+83
View File
@@ -0,0 +1,83 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package groups
import (
"encoding/json"
"strings"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
)
// Status represents User status.
type Status uint8
// Possible User status values.
const (
// EnabledStatus represents enabled User.
EnabledStatus Status = iota
// DisabledStatus represents disabled User.
DisabledStatus
// DeletedStatus represents a user that will be deleted.
DeletedStatus
// AllStatus is used for querying purposes to list users irrespective
// of their status - both enabled and disabled. It is never stored in the
// database as the actual User status and should always be the largest
// value in this enumeration.
AllStatus
)
// String representation of the possible status values.
const (
Disabled = "disabled"
Enabled = "enabled"
Deleted = "deleted"
All = "all"
Unknown = "unknown"
)
// String converts user/group status to string literal.
func (s Status) String() string {
switch s {
case DisabledStatus:
return Disabled
case EnabledStatus:
return Enabled
case DeletedStatus:
return Deleted
case AllStatus:
return All
default:
return Unknown
}
}
// ToStatus converts string value to a valid User/Group status.
func ToStatus(status string) (Status, error) {
switch status {
case "", Enabled:
return EnabledStatus, nil
case Disabled:
return DisabledStatus, nil
case Deleted:
return DeletedStatus, nil
case All:
return AllStatus, nil
}
return Status(0), svcerr.ErrInvalidStatus
}
// Custom Marshaller for Uesr/Groups.
func (s Status) MarshalJSON() ([]byte, error) {
return json.Marshal(s.String())
}
// Custom Unmarshaler for User/Groups.
func (s *Status) UnmarshalJSON(data []byte) error {
str := strings.Trim(string(data), "\"")
val, err := ToStatus(str)
*s = val
return err
}
+34 -35
View File
@@ -17,7 +17,6 @@ import (
"github.com/absmach/magistrala/pkg/apiutil"
mgauthn "github.com/absmach/magistrala/pkg/authn"
authnmocks "github.com/absmach/magistrala/pkg/authn/mocks"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/pkg/groups"
@@ -65,14 +64,14 @@ func TestCreateChannel(t *testing.T) {
group := convertChannel(channel)
createGroupReq := groups.Group{
Name: channel.Name,
Metadata: mgclients.Metadata{"role": "client"},
Status: mgclients.EnabledStatus,
Metadata: groups.Metadata{"role": "client"},
Status: groups.EnabledStatus,
}
channelReq := sdk.Channel{
Name: channel.Name,
Metadata: validMetadata,
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
}
channelKind := "new_channel"
@@ -83,7 +82,7 @@ func TestCreateChannel(t *testing.T) {
pChannel.ParentID = parentID
iGroup := group
iGroup.Metadata = mgclients.Metadata{
iGroup.Metadata = groups.Metadata{
"test": make(chan int),
}
@@ -148,14 +147,14 @@ func TestCreateChannel(t *testing.T) {
channelReq: sdk.Channel{
Name: channel.Name,
ParentID: parentID,
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
},
domainID: domainID,
token: validToken,
createGroupReq: groups.Group{
Name: channel.Name,
Parent: parentID,
Status: mgclients.EnabledStatus,
Status: groups.EnabledStatus,
},
svcRes: pGroup,
svcErr: nil,
@@ -167,14 +166,14 @@ func TestCreateChannel(t *testing.T) {
channelReq: sdk.Channel{
Name: channel.Name,
ParentID: wrongID,
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
},
domainID: domainID,
token: validToken,
createGroupReq: groups.Group{
Name: channel.Name,
Parent: wrongID,
Status: mgclients.EnabledStatus,
Status: groups.EnabledStatus,
},
svcRes: groups.Group{},
svcErr: svcerr.ErrCreateEntity,
@@ -184,7 +183,7 @@ func TestCreateChannel(t *testing.T) {
{
desc: "create channel with missing name",
channelReq: sdk.Channel{
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
},
domainID: domainID,
token: validToken,
@@ -204,7 +203,7 @@ func TestCreateChannel(t *testing.T) {
Metadata: validMetadata,
CreatedAt: group.CreatedAt,
UpdatedAt: group.UpdatedAt,
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
},
domainID: domainID,
token: validToken,
@@ -213,10 +212,10 @@ func TestCreateChannel(t *testing.T) {
Parent: parentID,
Name: channel.Name,
Description: description,
Metadata: mgclients.Metadata{"role": "client"},
Metadata: groups.Metadata{"role": "client"},
CreatedAt: group.CreatedAt,
UpdatedAt: group.UpdatedAt,
Status: mgclients.EnabledStatus,
Status: groups.EnabledStatus,
},
svcRes: pGroup,
svcErr: nil,
@@ -270,7 +269,7 @@ func TestListChannels(t *testing.T) {
ID: generateUUID(t),
Name: fmt.Sprintf("channel_%d", i),
Metadata: sdk.Metadata{"name": fmt.Sprintf("thing_%d", i)},
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
}
chs = append(chs, gr)
}
@@ -280,7 +279,7 @@ func TestListChannels(t *testing.T) {
domainID string
token string
session mgauthn.Session
status mgclients.Status
status groups.Status
total uint64
offset uint64
limit uint64
@@ -438,7 +437,7 @@ func TestListChannels(t *testing.T) {
PageMeta: groups.PageMeta{
Offset: offset,
Limit: 10,
Metadata: mgclients.Metadata{"name": "thing_89"},
Metadata: groups.Metadata{"name": "thing_89"},
},
Permission: "view",
Direction: -1,
@@ -493,7 +492,7 @@ func TestListChannels(t *testing.T) {
},
Groups: []groups.Group{{
ID: generateUUID(t),
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"test": make(chan int),
},
}},
@@ -609,7 +608,7 @@ func TestViewChannel(t *testing.T) {
channelID: groupRes.ID,
svcRes: groups.Group{
ID: generateUUID(t),
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"test": make(chan int),
},
},
@@ -660,7 +659,7 @@ func TestUpdateChannel(t *testing.T) {
dChannel.Description = newDescription
mGroup := group
mGroup.Metadata = mgclients.Metadata{
mGroup.Metadata = groups.Metadata{
"field": "value2",
}
mChannel := channel
@@ -671,7 +670,7 @@ func TestUpdateChannel(t *testing.T) {
aGroup := group
aGroup.Name = newName
aGroup.Description = newDescription
aGroup.Metadata = mgclients.Metadata{"field": "value2"}
aGroup.Metadata = groups.Metadata{"field": "value2"}
aChannel := channel
aChannel.Name = newName
aChannel.Description = newDescription
@@ -736,7 +735,7 @@ func TestUpdateChannel(t *testing.T) {
},
updateGroupReq: groups.Group{
ID: group.ID,
Metadata: mgclients.Metadata{"field": "value2"},
Metadata: groups.Metadata{"field": "value2"},
},
svcRes: mGroup,
svcErr: nil,
@@ -757,7 +756,7 @@ func TestUpdateChannel(t *testing.T) {
ID: group.ID,
Name: newName,
Description: newDescription,
Metadata: mgclients.Metadata{"field": "value2"},
Metadata: groups.Metadata{"field": "value2"},
},
svcRes: aGroup,
svcErr: nil,
@@ -810,7 +809,7 @@ func TestUpdateChannel(t *testing.T) {
},
updateGroupReq: groups.Group{
ID: wrongID,
Metadata: mgclients.Metadata{"field": "value2"},
Metadata: groups.Metadata{"field": "value2"},
},
svcRes: groups.Group{},
svcErr: svcerr.ErrNotFound,
@@ -896,7 +895,7 @@ func TestUpdateChannel(t *testing.T) {
},
svcRes: groups.Group{
ID: generateUUID(t),
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"test": make(chan int),
},
},
@@ -955,7 +954,7 @@ func TestListChannelsByThing(t *testing.T) {
ID: generateUUID(t),
Name: fmt.Sprintf("membership_%d@example.com", i),
Metadata: sdk.Metadata{"role": "channel"},
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
}
aChannels = append(aChannels, channel)
}
@@ -1153,7 +1152,7 @@ func TestListChannelsByThing(t *testing.T) {
},
Groups: []groups.Group{{
ID: generateUUID(t),
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"test": make(chan int),
},
}},
@@ -1262,7 +1261,7 @@ func TestEnableChannel(t *testing.T) {
channelID: channel.ID,
svcRes: groups.Group{
ID: generateUUID(t),
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"test": make(chan int),
},
},
@@ -1302,9 +1301,9 @@ func TestDisableChannel(t *testing.T) {
group := convertChannel(channel)
dGroup := group
dGroup.Status = mgclients.DisabledStatus
dGroup.Status = groups.DisabledStatus
dChannel := channel
dChannel.Status = mgclients.DisabledStatus.String()
dChannel.Status = groups.DisabledStatus.String()
cases := []struct {
desc string
@@ -1375,7 +1374,7 @@ func TestDisableChannel(t *testing.T) {
channelID: channel.ID,
svcRes: groups.Group{
ID: generateUUID(t),
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"test": make(chan int),
},
},
@@ -2051,7 +2050,7 @@ func TestListChannelUserGroups(t *testing.T) {
ID: generateUUID(t),
Name: fmt.Sprintf("group_%d", i),
Metadata: sdk.Metadata{"role": "group"},
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
}
aGroups = append(aGroups, group)
}
@@ -2257,7 +2256,7 @@ func TestListChannelUserGroups(t *testing.T) {
Groups: []groups.Group{
{
ID: generateUUID(t),
Metadata: mgclients.Metadata{"test": make(chan int)},
Metadata: groups.Metadata{"test": make(chan int)},
},
},
},
@@ -2704,7 +2703,7 @@ func TestListGroupChannels(t *testing.T) {
ID: testsutil.GenerateUUID(t),
Name: "group_channel",
Metadata: sdk.Metadata{"role": "group"},
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
}
cases := []struct {
@@ -2854,7 +2853,7 @@ func TestListGroupChannels(t *testing.T) {
Groups: []groups.Group{
{
ID: generateUUID(t),
Metadata: mgclients.Metadata{"test": make(chan int)},
Metadata: groups.Metadata{"test": make(chan int)},
},
},
},
@@ -2895,7 +2894,7 @@ func generateTestChannel(t *testing.T) sdk.Channel {
Metadata: sdk.Metadata{"role": "client"},
CreatedAt: createdAt,
UpdatedAt: updatedAt,
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
}
return ch
}
+6 -7
View File
@@ -17,7 +17,6 @@ import (
"github.com/absmach/magistrala/internal/testsutil"
mglog "github.com/absmach/magistrala/logger"
"github.com/absmach/magistrala/pkg/apiutil"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
policies "github.com/absmach/magistrala/pkg/policies"
@@ -142,7 +141,7 @@ func TestCreateDomain(t *testing.T) {
svcRes: auth.Domain{
ID: authDomain.ID,
Name: authDomain.Name,
Metadata: mgclients.Metadata{
Metadata: auth.Metadata{
"key": make(chan int),
},
},
@@ -283,7 +282,7 @@ func TestUpdateDomain(t *testing.T) {
svcRes: auth.Domain{
ID: authDomain.ID,
Name: authDomain.Name,
Metadata: mgclients.Metadata{
Metadata: auth.Metadata{
"key": make(chan int),
},
},
@@ -379,7 +378,7 @@ func TestViewDomain(t *testing.T) {
svcRes: auth.Domain{
ID: authDomain.ID,
Name: authDomain.Name,
Metadata: mgclients.Metadata{
Metadata: auth.Metadata{
"key": make(chan int),
},
},
@@ -597,7 +596,7 @@ func TestListDomians(t *testing.T) {
Total: 1,
Domains: []auth.Domain{{
Name: authDomain.Name,
Metadata: mgclients.Metadata{"key": make(chan int)},
Metadata: auth.Metadata{"key": make(chan int)},
}},
},
svcErr: nil,
@@ -734,7 +733,7 @@ func TestListUserDomains(t *testing.T) {
Total: 1,
Domains: []auth.Domain{{
Name: authDomain.Name,
Metadata: mgclients.Metadata{"key": make(chan int)},
Metadata: auth.Metadata{"key": make(chan int)},
}},
},
svcErr: nil,
@@ -1111,7 +1110,7 @@ func generateTestDomain(t *testing.T) (auth.Domain, sdk.Domain) {
ad := auth.Domain{
ID: testsutil.GenerateUUID(t),
Name: "test-domain",
Metadata: mgclients.Metadata(validMetadata),
Metadata: auth.Metadata(validMetadata),
Tags: []string{"tag1", "tag2"},
Alias: "test-alias",
Status: auth.EnabledStatus,
+27 -28
View File
@@ -17,7 +17,6 @@ import (
"github.com/absmach/magistrala/pkg/apiutil"
mgauthn "github.com/absmach/magistrala/pkg/authn"
authnmocks "github.com/absmach/magistrala/pkg/authn/mocks"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/pkg/groups"
@@ -74,7 +73,7 @@ func TestCreateGroup(t *testing.T) {
psdkGroup.ParentID = pGroup.Parent
uGroup := group
uGroup.Metadata = mgclients.Metadata{
uGroup.Metadata = groups.Metadata{
"key": make(chan int),
}
cases := []struct {
@@ -98,7 +97,7 @@ func TestCreateGroup(t *testing.T) {
svcReq: groups.Group{
Name: gName,
Description: description,
Metadata: mgclients.Metadata{"role": "client"},
Metadata: groups.Metadata{"role": "client"},
},
svcRes: group,
svcErr: nil,
@@ -113,7 +112,7 @@ func TestCreateGroup(t *testing.T) {
svcReq: groups.Group{
Name: gName,
Description: description,
Metadata: mgclients.Metadata{"role": "client"},
Metadata: groups.Metadata{"role": "client"},
},
svcRes: group,
svcErr: nil,
@@ -133,7 +132,7 @@ func TestCreateGroup(t *testing.T) {
svcReq: groups.Group{
Name: gName,
Description: description,
Metadata: mgclients.Metadata{"role": "client"},
Metadata: groups.Metadata{"role": "client"},
Parent: pGroup.Parent,
},
svcRes: pGroup,
@@ -154,7 +153,7 @@ func TestCreateGroup(t *testing.T) {
svcReq: groups.Group{
Name: gName,
Description: description,
Metadata: mgclients.Metadata{"role": "client"},
Metadata: groups.Metadata{"role": "client"},
Parent: wrongID,
},
svcRes: groups.Group{},
@@ -174,7 +173,7 @@ func TestCreateGroup(t *testing.T) {
svcReq: groups.Group{
Name: gName,
Description: description,
Metadata: mgclients.Metadata{"role": "client"},
Metadata: groups.Metadata{"role": "client"},
},
svcRes: groups.Group{},
authenticateErr: svcerr.ErrAuthentication,
@@ -254,7 +253,7 @@ func TestCreateGroup(t *testing.T) {
svcReq: groups.Group{
Name: gName,
Description: description,
Metadata: mgclients.Metadata{"role": "client"},
Metadata: groups.Metadata{"role": "client"},
},
svcRes: uGroup,
svcErr: nil,
@@ -297,7 +296,7 @@ func TestListGroups(t *testing.T) {
ID: generateUUID(t),
Name: fmt.Sprintf("group_%d", i),
Metadata: sdk.Metadata{"name": fmt.Sprintf("user_%d", i)},
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
}
grps = append(grps, gr)
}
@@ -440,7 +439,7 @@ func TestListGroups(t *testing.T) {
PageMeta: groups.PageMeta{
Offset: 0,
Limit: 10,
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"name": "user_89",
},
},
@@ -517,7 +516,7 @@ func TestListGroups(t *testing.T) {
Groups: []groups.Group{{
ID: generateUUID(t),
Name: "group_1",
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"key": make(chan int),
},
}},
@@ -563,7 +562,7 @@ func TestListParentGroups(t *testing.T) {
ID: generateUUID(t),
Name: fmt.Sprintf("group_%d", i),
Metadata: sdk.Metadata{"name": fmt.Sprintf("user_%d", i)},
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
ParentID: parentID,
Level: 1,
}
@@ -721,7 +720,7 @@ func TestListParentGroups(t *testing.T) {
PageMeta: groups.PageMeta{
Offset: offset,
Limit: limit,
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"name": "user_89",
},
},
@@ -789,7 +788,7 @@ func TestListParentGroups(t *testing.T) {
Groups: []groups.Group{{
ID: generateUUID(t),
Name: "group_1",
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"key": make(chan int),
},
Level: 1,
@@ -836,7 +835,7 @@ func TestListChildrenGroups(t *testing.T) {
ID: generateUUID(t),
Name: fmt.Sprintf("group_%d", i),
Metadata: sdk.Metadata{"name": fmt.Sprintf("user_%d", i)},
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
ParentID: parentID,
Level: -1,
}
@@ -994,7 +993,7 @@ func TestListChildrenGroups(t *testing.T) {
PageMeta: groups.PageMeta{
Offset: offset,
Limit: limit,
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"name": "user_89",
},
},
@@ -1061,7 +1060,7 @@ func TestListChildrenGroups(t *testing.T) {
Groups: []groups.Group{{
ID: generateUUID(t),
Name: "group_1",
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"key": make(chan int),
},
Level: -1,
@@ -1161,7 +1160,7 @@ func TestViewGroup(t *testing.T) {
svcRes: groups.Group{
ID: group.ID,
Name: "group_1",
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"key": make(chan int),
},
},
@@ -1338,7 +1337,7 @@ func TestUpdateGroup(t *testing.T) {
ID: group.ID,
Name: updatedName,
Description: updatedDescription,
Metadata: mgclients.Metadata{"key": "value"},
Metadata: groups.Metadata{"key": "value"},
},
svcRes: convertGroup(upGroup),
svcErr: nil,
@@ -1359,7 +1358,7 @@ func TestUpdateGroup(t *testing.T) {
ID: wrongID,
Name: updatedName,
Description: updatedDescription,
Metadata: mgclients.Metadata{"key": "value"},
Metadata: groups.Metadata{"key": "value"},
},
svcRes: groups.Group{},
svcErr: svcerr.ErrNotFound,
@@ -1380,7 +1379,7 @@ func TestUpdateGroup(t *testing.T) {
ID: group.ID,
Name: updatedName,
Description: updatedDescription,
Metadata: mgclients.Metadata{"key": "value"},
Metadata: groups.Metadata{"key": "value"},
},
svcRes: groups.Group{},
authenticateErr: svcerr.ErrAuthentication,
@@ -1449,12 +1448,12 @@ func TestUpdateGroup(t *testing.T) {
ID: group.ID,
Name: updatedName,
Description: updatedDescription,
Metadata: mgclients.Metadata{"key": "value"},
Metadata: groups.Metadata{"key": "value"},
},
svcRes: groups.Group{
ID: group.ID,
Name: updatedName,
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"key": make(chan int),
},
},
@@ -1494,7 +1493,7 @@ func TestEnableGroup(t *testing.T) {
mgsdk := sdk.NewSDK(conf)
enGroup := sdkGroup
enGroup.Status = mgclients.EnabledStatus.String()
enGroup.Status = groups.EnabledStatus.String()
cases := []struct {
desc string
@@ -1566,7 +1565,7 @@ func TestEnableGroup(t *testing.T) {
svcRes: groups.Group{
ID: group.ID,
Name: "group_1",
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"key": make(chan int),
},
},
@@ -1605,7 +1604,7 @@ func TestDisableGroup(t *testing.T) {
mgsdk := sdk.NewSDK(conf)
disGroup := sdkGroup
disGroup.Status = mgclients.DisabledStatus.String()
disGroup.Status = groups.DisabledStatus.String()
cases := []struct {
desc string
@@ -1677,7 +1676,7 @@ func TestDisableGroup(t *testing.T) {
svcRes: groups.Group{
ID: group.ID,
Name: "group_1",
Metadata: mgclients.Metadata{
Metadata: groups.Metadata{
"key": make(chan int),
},
},
@@ -2033,7 +2032,7 @@ func generateTestGroup(t *testing.T) sdk.Group {
Metadata: sdk.Metadata{"role": "client"},
CreatedAt: createdAt,
UpdatedAt: updatedAt,
Status: mgclients.EnabledStatus.String(),
Status: groups.EnabledStatus.String(),
}
return gr
}
+16 -16
View File
@@ -13,10 +13,10 @@ import (
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/invitations"
"github.com/absmach/magistrala/journal"
mgclients "github.com/absmach/magistrala/pkg/clients"
mggroups "github.com/absmach/magistrala/pkg/groups"
sdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/absmach/magistrala/pkg/uuid"
"github.com/absmach/magistrala/things"
"github.com/absmach/magistrala/users"
"github.com/stretchr/testify/assert"
)
@@ -64,8 +64,8 @@ func convertUsers(cs []sdk.User) []users.User {
return ccs
}
func convertThings(cs ...sdk.Thing) []mgclients.Client {
ccs := []mgclients.Client{}
func convertThings(cs ...sdk.Thing) []things.Client {
ccs := []things.Client{}
for _, c := range cs {
ccs = append(ccs, convertThing(c))
@@ -96,9 +96,9 @@ func convertChannels(cs []sdk.Channel) []mggroups.Group {
func convertGroup(g sdk.Group) mggroups.Group {
if g.Status == "" {
g.Status = mgclients.EnabledStatus.String()
g.Status = mggroups.EnabledStatus.String()
}
status, err := mgclients.ToStatus(g.Status)
status, err := mggroups.ToStatus(g.Status)
if err != nil {
return mggroups.Group{}
}
@@ -109,7 +109,7 @@ func convertGroup(g sdk.Group) mggroups.Group {
Parent: g.ParentID,
Name: g.Name,
Description: g.Description,
Metadata: mgclients.Metadata(g.Metadata),
Metadata: mggroups.Metadata(g.Metadata),
Level: g.Level,
Path: g.Path,
Children: convertChildren(g.Children),
@@ -162,21 +162,21 @@ func convertUser(c sdk.User) users.User {
}
}
func convertThing(c sdk.Thing) mgclients.Client {
func convertThing(c sdk.Thing) things.Client {
if c.Status == "" {
c.Status = mgclients.EnabledStatus.String()
c.Status = things.EnabledStatus.String()
}
status, err := mgclients.ToStatus(c.Status)
status, err := things.ToStatus(c.Status)
if err != nil {
return mgclients.Client{}
return things.Client{}
}
return mgclients.Client{
return things.Client{
ID: c.ID,
Name: c.Name,
Tags: c.Tags,
Domain: c.DomainID,
Credentials: mgclients.Credentials(c.Credentials),
Metadata: mgclients.Metadata(c.Metadata),
Credentials: things.Credentials(c.Credentials),
Metadata: things.Metadata(c.Metadata),
CreatedAt: c.CreatedAt,
UpdatedAt: c.UpdatedAt,
Status: status,
@@ -185,9 +185,9 @@ func convertThing(c sdk.Thing) mgclients.Client {
func convertChannel(g sdk.Channel) mggroups.Group {
if g.Status == "" {
g.Status = mgclients.EnabledStatus.String()
g.Status = mggroups.EnabledStatus.String()
}
status, err := mgclients.ToStatus(g.Status)
status, err := mggroups.ToStatus(g.Status)
if err != nil {
return mggroups.Group{}
}
@@ -197,7 +197,7 @@ func convertChannel(g sdk.Channel) mggroups.Group {
Parent: g.ParentID,
Name: g.Name,
Description: g.Description,
Metadata: mgclients.Metadata(g.Metadata),
Metadata: mggroups.Metadata(g.Metadata),
Level: g.Level,
Path: g.Path,
CreatedAt: g.CreatedAt,
+181 -195
View File
File diff suppressed because it is too large Load Diff
+10 -10
View File
@@ -7,9 +7,9 @@ import (
"fmt"
"os"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
"github.com/absmach/magistrala/pkg/groups"
"github.com/absmach/magistrala/things"
"github.com/pelletier/go-toml"
)
@@ -60,15 +60,15 @@ type Cert struct {
// Config struct of Provision.
type Config struct {
File string `toml:"file" env:"MG_PROVISION_CONFIG_FILE" envDefault:"config.toml"`
Server ServiceConf `toml:"server" mapstructure:"server"`
Bootstrap Bootstrap `toml:"bootstrap" mapstructure:"bootstrap"`
Things []mgclients.Client `toml:"things" mapstructure:"things"`
Channels []groups.Group `toml:"channels" mapstructure:"channels"`
Cert Cert `toml:"cert" mapstructure:"cert"`
BSContent string `env:"MG_PROVISION_BS_CONTENT" envDefault:""`
SendTelemetry bool `env:"MG_SEND_TELEMETRY" envDefault:"true"`
InstanceID string `env:"MG_MQTT_ADAPTER_INSTANCE_ID" envDefault:""`
File string `toml:"file" env:"MG_PROVISION_CONFIG_FILE" envDefault:"config.toml"`
Server ServiceConf `toml:"server" mapstructure:"server"`
Bootstrap Bootstrap `toml:"bootstrap" mapstructure:"bootstrap"`
Things []things.Client `toml:"things" mapstructure:"things"`
Channels []groups.Group `toml:"channels" mapstructure:"channels"`
Cert Cert `toml:"cert" mapstructure:"cert"`
BSContent string `env:"MG_PROVISION_BS_CONTENT" envDefault:""`
SendTelemetry bool `env:"MG_SEND_TELEMETRY" envDefault:"true"`
InstanceID string `env:"MG_MQTT_ADAPTER_INSTANCE_ID" envDefault:""`
}
// Save - store config in a file.
+2 -2
View File
@@ -8,10 +8,10 @@ import (
"os"
"testing"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
"github.com/absmach/magistrala/pkg/groups"
"github.com/absmach/magistrala/provision"
"github.com/absmach/magistrala/things"
"github.com/pelletier/go-toml"
"github.com/stretchr/testify/assert"
)
@@ -31,7 +31,7 @@ var (
"test": "test",
},
},
Things: []mgclients.Client{
Things: []things.Client{
{
ID: "1234567890",
Name: "test",
+4 -4
View File
@@ -49,8 +49,8 @@ func (client grpcClient) Authorize(ctx context.Context, req *magistrala.ThingsAu
defer cancel()
res, err := client.authorize(ctx, things.AuthzReq{
ThingID: req.GetThingID(),
ThingKey: req.GetThingKey(),
ClientID: req.GetThingID(),
ClientKey: req.GetThingKey(),
ChannelID: req.GetChannelID(),
Permission: req.GetPermission(),
})
@@ -71,8 +71,8 @@ func encodeAuthorizeRequest(_ context.Context, grpcReq interface{}) (interface{}
req := grpcReq.(things.AuthzReq)
return &magistrala.ThingsAuthzReq{
ChannelID: req.ChannelID,
ThingID: req.ThingID,
ThingKey: req.ThingKey,
ThingID: req.ClientID,
ThingKey: req.ClientKey,
Permission: req.Permission,
}, nil
}
+2 -2
View File
@@ -16,8 +16,8 @@ func authorizeEndpoint(svc things.Service) endpoint.Endpoint {
thingID, err := svc.Authorize(ctx, things.AuthzReq{
ChannelID: req.ChannelID,
ThingID: req.ThingID,
ThingKey: req.ThingKey,
ClientID: req.ThingID,
ClientKey: req.ThingKey,
Permission: req.Permission,
})
if err != nil {
+20 -20
View File
@@ -28,7 +28,7 @@ const port = 7000
var (
thingID = "testID"
thingKey = "testKey"
clientKey = "testKey"
channelID = "testID"
invalid = "invalid"
)
@@ -71,17 +71,17 @@ func TestAuthorize(t *testing.T) {
desc: "authorize successfully",
thingID: thingID,
req: &magistrala.ThingsAuthzReq{
ThingKey: thingKey,
ThingKey: clientKey,
ChannelID: channelID,
Permission: policies.PublishPermission,
},
authorizeReq: things.AuthzReq{
ThingKey: thingKey,
ClientKey: clientKey,
ChannelID: channelID,
Permission: policies.PublishPermission,
},
authorizeRes: thingID,
identifyKey: thingKey,
identifyKey: clientKey,
res: &magistrala.ThingsAuthzRes{Authorized: true, Id: thingID},
err: nil,
},
@@ -93,7 +93,7 @@ func TestAuthorize(t *testing.T) {
Permission: policies.PublishPermission,
},
authorizeReq: things.AuthzReq{
ThingKey: invalid,
ClientKey: invalid,
ChannelID: channelID,
Permission: policies.PublishPermission,
},
@@ -107,17 +107,17 @@ func TestAuthorize(t *testing.T) {
desc: "authorize with failed authorization",
thingID: thingID,
req: &magistrala.ThingsAuthzReq{
ThingKey: thingKey,
ThingKey: clientKey,
ChannelID: channelID,
Permission: policies.PublishPermission,
},
authorizeReq: things.AuthzReq{
ThingKey: thingKey,
ClientKey: clientKey,
ChannelID: channelID,
Permission: policies.PublishPermission,
},
authorizeErr: svcerr.ErrAuthorization,
identifyKey: thingKey,
identifyKey: clientKey,
res: &magistrala.ThingsAuthzRes{Authorized: false},
err: svcerr.ErrAuthorization,
},
@@ -126,16 +126,16 @@ func TestAuthorize(t *testing.T) {
desc: "authorize with invalid permission",
thingID: thingID,
req: &magistrala.ThingsAuthzReq{
ThingKey: thingKey,
ThingKey: clientKey,
ChannelID: channelID,
Permission: invalid,
},
authorizeReq: things.AuthzReq{
ChannelID: channelID,
ThingKey: thingKey,
ClientKey: clientKey,
Permission: invalid,
},
identifyKey: thingKey,
identifyKey: clientKey,
authorizeErr: svcerr.ErrAuthorization,
res: &magistrala.ThingsAuthzRes{Authorized: false},
err: svcerr.ErrAuthorization,
@@ -144,16 +144,16 @@ func TestAuthorize(t *testing.T) {
desc: "authorize with invalid channel ID",
thingID: thingID,
req: &magistrala.ThingsAuthzReq{
ThingKey: thingKey,
ThingKey: clientKey,
ChannelID: invalid,
Permission: policies.PublishPermission,
},
authorizeReq: things.AuthzReq{
ChannelID: invalid,
ThingKey: thingKey,
ClientKey: clientKey,
Permission: policies.PublishPermission,
},
identifyKey: thingKey,
identifyKey: clientKey,
authorizeErr: svcerr.ErrAuthorization,
res: &magistrala.ThingsAuthzRes{Authorized: false},
err: svcerr.ErrAuthorization,
@@ -162,17 +162,17 @@ func TestAuthorize(t *testing.T) {
desc: "authorize with empty channel ID",
thingID: thingID,
req: &magistrala.ThingsAuthzReq{
ThingKey: thingKey,
ThingKey: clientKey,
ChannelID: "",
Permission: policies.PublishPermission,
},
authorizeReq: things.AuthzReq{
ThingKey: thingKey,
ClientKey: clientKey,
ChannelID: "",
Permission: policies.PublishPermission,
},
authorizeErr: svcerr.ErrAuthorization,
identifyKey: thingKey,
identifyKey: clientKey,
res: &magistrala.ThingsAuthzRes{Authorized: false},
err: svcerr.ErrAuthorization,
},
@@ -180,16 +180,16 @@ func TestAuthorize(t *testing.T) {
desc: "authorize with empty permission",
thingID: thingID,
req: &magistrala.ThingsAuthzReq{
ThingKey: thingKey,
ThingKey: clientKey,
ChannelID: channelID,
Permission: "",
},
authorizeReq: things.AuthzReq{
ChannelID: channelID,
Permission: "",
ThingKey: thingKey,
ClientKey: clientKey,
},
identifyKey: thingKey,
identifyKey: clientKey,
authorizeErr: svcerr.ErrAuthorization,
res: &magistrala.ThingsAuthzRes{Authorized: false},
err: svcerr.ErrAuthorization,
+6 -7
View File
@@ -13,7 +13,6 @@ import (
"github.com/absmach/magistrala/internal/api"
"github.com/absmach/magistrala/pkg/apiutil"
mgauthn "github.com/absmach/magistrala/pkg/authn"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
"github.com/absmach/magistrala/things"
"github.com/go-chi/chi/v5"
@@ -197,7 +196,7 @@ func decodeListClients(_ context.Context, r *http.Request) (interface{}, error)
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
st, err := mgclients.ToStatus(s)
st, err := things.ToStatus(s)
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
@@ -266,12 +265,12 @@ func decodeCreateClientReq(_ context.Context, r *http.Request) (interface{}, err
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
}
var c mgclients.Client
var c things.Client
if err := json.NewDecoder(r.Body).Decode(&c); err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
}
req := createClientReq{
client: c,
thing: c,
}
return req, nil
@@ -283,7 +282,7 @@ func decodeCreateClientsReq(_ context.Context, r *http.Request) (interface{}, er
}
c := createClientsReq{}
if err := json.NewDecoder(r.Body).Decode(&c.Clients); err != nil {
if err := json.NewDecoder(r.Body).Decode(&c.Things); err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(errors.ErrMalformedEntity, err))
}
@@ -315,7 +314,7 @@ func decodeListMembersRequest(_ context.Context, r *http.Request) (interface{},
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
st, err := mgclients.ToStatus(s)
st, err := things.ToStatus(s)
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
@@ -329,7 +328,7 @@ func decodeListMembersRequest(_ context.Context, r *http.Request) (interface{},
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
req := listMembersReq{
Page: mgclients.Page{
Page: things.Page{
Status: st,
Offset: o,
Limit: l,
+15 -18
View File
@@ -9,7 +9,6 @@ import (
"github.com/absmach/magistrala/internal/api"
"github.com/absmach/magistrala/pkg/apiutil"
"github.com/absmach/magistrala/pkg/authn"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/pkg/groups"
@@ -30,13 +29,13 @@ func createClientEndpoint(svc things.Service) endpoint.Endpoint {
return nil, svcerr.ErrAuthorization
}
client, err := svc.CreateThings(ctx, session, req.client)
thing, err := svc.CreateClients(ctx, session, req.thing)
if err != nil {
return nil, err
}
return createClientRes{
Client: client[0],
Client: thing[0],
created: true,
}, nil
}
@@ -54,7 +53,7 @@ func createClientsEndpoint(svc things.Service) endpoint.Endpoint {
return nil, svcerr.ErrAuthorization
}
page, err := svc.CreateThings(ctx, session, req.Clients...)
page, err := svc.CreateClients(ctx, session, req.Things...)
if err != nil {
return nil, err
}
@@ -85,7 +84,7 @@ func viewClientEndpoint(svc things.Service) endpoint.Endpoint {
return nil, svcerr.ErrAuthorization
}
c, err := svc.ViewClient(ctx, session, req.id)
c, err := svc.View(ctx, session, req.id)
if err != nil {
return nil, err
}
@@ -106,7 +105,7 @@ func viewClientPermsEndpoint(svc things.Service) endpoint.Endpoint {
return nil, svcerr.ErrAuthorization
}
p, err := svc.ViewClientPerms(ctx, session, req.id)
p, err := svc.ViewPerms(ctx, session, req.id)
if err != nil {
return nil, err
}
@@ -127,7 +126,7 @@ func listClientsEndpoint(svc things.Service) endpoint.Endpoint {
return nil, svcerr.ErrAuthorization
}
pm := mgclients.Page{
pm := things.Page{
Status: req.status,
Offset: req.offset,
Limit: req.limit,
@@ -136,7 +135,6 @@ func listClientsEndpoint(svc things.Service) endpoint.Endpoint {
Permission: req.permission,
Metadata: req.metadata,
ListPerms: req.listPerms,
Role: mgclients.AllRole, // retrieve all things since things don't have roles
Id: req.id,
}
page, err := svc.ListClients(ctx, session, req.userID, pm)
@@ -172,7 +170,6 @@ func listMembersEndpoint(svc things.Service) endpoint.Endpoint {
return nil, svcerr.ErrAuthorization
}
req.Page.Role = mgclients.AllRole // retrieve all things since things don't have roles
page, err := svc.ListClientsByGroup(ctx, session, req.groupID, req.Page)
if err != nil {
return nil, err
@@ -194,12 +191,12 @@ func updateClientEndpoint(svc things.Service) endpoint.Endpoint {
return nil, svcerr.ErrAuthorization
}
cli := mgclients.Client{
cli := things.Client{
ID: req.id,
Name: req.Name,
Metadata: req.Metadata,
}
client, err := svc.UpdateClient(ctx, session, cli)
client, err := svc.Update(ctx, session, cli)
if err != nil {
return nil, err
}
@@ -220,11 +217,11 @@ func updateClientTagsEndpoint(svc things.Service) endpoint.Endpoint {
return nil, svcerr.ErrAuthorization
}
cli := mgclients.Client{
cli := things.Client{
ID: req.id,
Tags: req.Tags,
}
client, err := svc.UpdateClientTags(ctx, session, cli)
client, err := svc.UpdateTags(ctx, session, cli)
if err != nil {
return nil, err
}
@@ -245,7 +242,7 @@ func updateClientSecretEndpoint(svc things.Service) endpoint.Endpoint {
return nil, svcerr.ErrAuthorization
}
client, err := svc.UpdateClientSecret(ctx, session, req.id, req.Secret)
client, err := svc.UpdateSecret(ctx, session, req.id, req.Secret)
if err != nil {
return nil, err
}
@@ -266,7 +263,7 @@ func enableClientEndpoint(svc things.Service) endpoint.Endpoint {
return nil, svcerr.ErrAuthorization
}
client, err := svc.EnableClient(ctx, session, req.id)
client, err := svc.Enable(ctx, session, req.id)
if err != nil {
return nil, err
}
@@ -287,7 +284,7 @@ func disableClientEndpoint(svc things.Service) endpoint.Endpoint {
return nil, svcerr.ErrAuthorization
}
client, err := svc.DisableClient(ctx, session, req.id)
client, err := svc.Disable(ctx, session, req.id)
if err != nil {
return nil, err
}
@@ -296,7 +293,7 @@ func disableClientEndpoint(svc things.Service) endpoint.Endpoint {
}
}
func buildClientsResponse(cp mgclients.MembersPage) clientsPageRes {
func buildClientsResponse(cp things.MembersPage) clientsPageRes {
res := clientsPageRes{
pageRes: pageRes{
Total: cp.Total,
@@ -524,7 +521,7 @@ func deleteClientEndpoint(svc things.Service) endpoint.Endpoint {
return nil, svcerr.ErrAuthorization
}
if err := svc.DeleteClient(ctx, session, req.id); err != nil {
if err := svc.Delete(ctx, session, req.id); err != nil {
return nil, err
}
+139 -139
View File
@@ -19,10 +19,10 @@ import (
"github.com/absmach/magistrala/pkg/apiutil"
mgauthn "github.com/absmach/magistrala/pkg/authn"
authnmocks "github.com/absmach/magistrala/pkg/authn/mocks"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
gmocks "github.com/absmach/magistrala/pkg/groups/mocks"
"github.com/absmach/magistrala/things"
httpapi "github.com/absmach/magistrala/things/api/http"
"github.com/absmach/magistrala/things/mocks"
"github.com/go-chi/chi/v5"
@@ -32,15 +32,15 @@ import (
var (
secret = "strongsecret"
validCMetadata = mgclients.Metadata{"role": "client"}
validCMetadata = things.Metadata{"role": "client"}
ID = testsutil.GenerateUUID(&testing.T{})
client = mgclients.Client{
client = things.Client{
ID: ID,
Name: "clientname",
Tags: []string{"tag1", "tag2"},
Credentials: mgclients.Credentials{Identity: "clientidentity", Secret: secret},
Credentials: things.Credentials{Identity: "clientidentity", Secret: secret},
Metadata: validCMetadata,
Status: mgclients.EnabledStatus,
Status: things.EnabledStatus,
}
validToken = "token"
inValidToken = "invalid"
@@ -106,7 +106,7 @@ func TestCreateThing(t *testing.T) {
cases := []struct {
desc string
client mgclients.Client
client things.Client
domainID string
token string
contentType string
@@ -147,9 +147,9 @@ func TestCreateThing(t *testing.T) {
},
{
desc: "register a thing with an invalid ID",
client: mgclients.Client{
client: things.Client{
ID: inValid,
Credentials: mgclients.Credentials{
Credentials: things.Credentials{
Identity: "user@example.com",
Secret: "12345678",
},
@@ -163,8 +163,8 @@ func TestCreateThing(t *testing.T) {
},
{
desc: "register a thing that can't be marshalled",
client: mgclients.Client{
Credentials: mgclients.Credentials{
client: things.Client{
Credentials: things.Credentials{
Identity: "user@example.com",
Secret: "12345678",
},
@@ -181,13 +181,13 @@ func TestCreateThing(t *testing.T) {
},
{
desc: "register thing with invalid status",
client: mgclients.Client{
client: things.Client{
ID: testsutil.GenerateUUID(t),
Credentials: mgclients.Credentials{
Credentials: things.Credentials{
Identity: "newclientwithinvalidstatus@example.com",
Secret: secret,
},
Status: mgclients.AllStatus,
Status: things.AllStatus,
},
domainID: domainID,
token: validToken,
@@ -198,9 +198,9 @@ func TestCreateThing(t *testing.T) {
},
{
desc: "create thing with invalid contentype",
client: mgclients.Client{
client: things.Client{
ID: testsutil.GenerateUUID(t),
Credentials: mgclients.Credentials{
Credentials: things.Credentials{
Identity: "example@example.com",
Secret: secret,
},
@@ -227,7 +227,7 @@ func TestCreateThing(t *testing.T) {
}
authCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
svcCall := svc.On("CreateThings", mock.Anything, tc.authnRes, tc.client).Return([]mgclients.Client{tc.client}, tc.err)
svcCall := svc.On("CreateClients", mock.Anything, tc.authnRes, tc.client).Return([]things.Client{tc.client}, tc.err)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
var errRes respBody
@@ -249,24 +249,24 @@ func TestCreateThings(t *testing.T) {
defer ts.Close()
num := 3
var items []mgclients.Client
var items []things.Client
for i := 0; i < num; i++ {
client := mgclients.Client{
client := things.Client{
ID: testsutil.GenerateUUID(t),
Name: namesgen.Generate(),
Credentials: mgclients.Credentials{
Credentials: things.Credentials{
Identity: fmt.Sprintf("%s@example.com", namesgen.Generate()),
Secret: secret,
},
Metadata: mgclients.Metadata{},
Status: mgclients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
}
items = append(items, client)
}
cases := []struct {
desc string
client []mgclients.Client
client []things.Client
domainID string
token string
contentType string
@@ -308,7 +308,7 @@ func TestCreateThings(t *testing.T) {
},
{
desc: "create things with empty request",
client: []mgclients.Client{},
client: []things.Client{},
domainID: domainID,
token: validToken,
authnRes: mgauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
@@ -319,7 +319,7 @@ func TestCreateThings(t *testing.T) {
},
{
desc: "create things with invalid IDs",
client: []mgclients.Client{
client: []things.Client{
{
ID: inValid,
},
@@ -339,7 +339,7 @@ func TestCreateThings(t *testing.T) {
},
{
desc: "create things with invalid contentype",
client: []mgclients.Client{
client: []things.Client{
{
ID: testsutil.GenerateUUID(t),
},
@@ -353,10 +353,10 @@ func TestCreateThings(t *testing.T) {
},
{
desc: "create a thing that can't be marshalled",
client: []mgclients.Client{
client: []things.Client{
{
ID: testsutil.GenerateUUID(t),
Credentials: mgclients.Credentials{
Credentials: things.Credentials{
Identity: "user@example.com",
Secret: "12345678",
},
@@ -397,7 +397,7 @@ func TestCreateThings(t *testing.T) {
}
authCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
svcCall := svc.On("CreateThings", mock.Anything, tc.authnRes, mock.Anything, mock.Anything, mock.Anything).Return(tc.client, tc.err)
svcCall := svc.On("CreateClients", mock.Anything, tc.authnRes, mock.Anything, mock.Anything, mock.Anything).Return(tc.client, tc.err)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
@@ -425,7 +425,7 @@ func TestListThings(t *testing.T) {
query string
domainID string
token string
listThingsResponse mgclients.ClientsPage
listThingsResponse things.ClientsPage
status int
authnRes mgauthn.Session
authnErr error
@@ -437,11 +437,11 @@ func TestListThings(t *testing.T) {
token: validToken,
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID, DomainUserID: domainID + "_" + validID, SuperAdmin: false},
status: http.StatusOK,
listThingsResponse: mgclients.ClientsPage{
Page: mgclients.Page{
listThingsResponse: things.ClientsPage{
Page: things.Page{
Total: 1,
},
Clients: []mgclients.Client{client},
Clients: []things.Client{client},
},
err: nil,
},
@@ -451,11 +451,11 @@ func TestListThings(t *testing.T) {
token: validToken,
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID, DomainUserID: domainID + "_" + validID, SuperAdmin: false},
status: http.StatusOK,
listThingsResponse: mgclients.ClientsPage{
Page: mgclients.Page{
listThingsResponse: things.ClientsPage{
Page: things.Page{
Total: 1,
},
Clients: []mgclients.Client{client},
Clients: []things.Client{client},
},
err: nil,
},
@@ -479,12 +479,12 @@ func TestListThings(t *testing.T) {
domainID: domainID,
token: validToken,
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID, DomainUserID: domainID + "_" + validID, SuperAdmin: false},
listThingsResponse: mgclients.ClientsPage{
Page: mgclients.Page{
listThingsResponse: things.ClientsPage{
Page: things.Page{
Offset: 1,
Total: 1,
},
Clients: []mgclients.Client{client},
Clients: []things.Client{client},
},
query: "offset=1",
status: http.StatusOK,
@@ -504,12 +504,12 @@ func TestListThings(t *testing.T) {
domainID: domainID,
token: validToken,
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID, DomainUserID: domainID + "_" + validID, SuperAdmin: false},
listThingsResponse: mgclients.ClientsPage{
Page: mgclients.Page{
listThingsResponse: things.ClientsPage{
Page: things.Page{
Limit: 1,
Total: 1,
},
Clients: []mgclients.Client{client},
Clients: []things.Client{client},
},
query: "limit=1",
status: http.StatusOK,
@@ -538,11 +538,11 @@ func TestListThings(t *testing.T) {
domainID: domainID,
token: validToken,
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID, DomainUserID: domainID + "_" + validID, SuperAdmin: false},
listThingsResponse: mgclients.ClientsPage{
Page: mgclients.Page{
listThingsResponse: things.ClientsPage{
Page: things.Page{
Total: 1,
},
Clients: []mgclients.Client{client},
Clients: []things.Client{client},
},
query: "name=clientname",
status: http.StatusOK,
@@ -571,11 +571,11 @@ func TestListThings(t *testing.T) {
domainID: domainID,
token: validToken,
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID, DomainUserID: domainID + "_" + validID, SuperAdmin: false},
listThingsResponse: mgclients.ClientsPage{
Page: mgclients.Page{
listThingsResponse: things.ClientsPage{
Page: things.Page{
Total: 1,
},
Clients: []mgclients.Client{client},
Clients: []things.Client{client},
},
query: "status=enabled",
status: http.StatusOK,
@@ -604,11 +604,11 @@ func TestListThings(t *testing.T) {
domainID: domainID,
token: validToken,
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID, DomainUserID: domainID + "_" + validID, SuperAdmin: false},
listThingsResponse: mgclients.ClientsPage{
Page: mgclients.Page{
listThingsResponse: things.ClientsPage{
Page: things.Page{
Total: 1,
},
Clients: []mgclients.Client{client},
Clients: []things.Client{client},
},
query: "tag=tag1,tag2",
status: http.StatusOK,
@@ -637,11 +637,11 @@ func TestListThings(t *testing.T) {
domainID: domainID,
token: validToken,
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID, DomainUserID: domainID + "_" + validID, SuperAdmin: false},
listThingsResponse: mgclients.ClientsPage{
Page: mgclients.Page{
listThingsResponse: things.ClientsPage{
Page: things.Page{
Total: 1,
},
Clients: []mgclients.Client{client},
Clients: []things.Client{client},
},
query: "metadata=%7B%22domain%22%3A%20%22example.com%22%7D&",
status: http.StatusOK,
@@ -670,11 +670,11 @@ func TestListThings(t *testing.T) {
domainID: domainID,
token: validToken,
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID, DomainUserID: domainID + "_" + validID, SuperAdmin: false},
listThingsResponse: mgclients.ClientsPage{
Page: mgclients.Page{
listThingsResponse: things.ClientsPage{
Page: things.Page{
Total: 1,
},
Clients: []mgclients.Client{client},
Clients: []things.Client{client},
},
query: "permission=view",
status: http.StatusOK,
@@ -703,11 +703,11 @@ func TestListThings(t *testing.T) {
domainID: domainID,
token: validToken,
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID, DomainUserID: domainID + "_" + validID, SuperAdmin: false},
listThingsResponse: mgclients.ClientsPage{
Page: mgclients.Page{
listThingsResponse: things.ClientsPage{
Page: things.Page{
Total: 1,
},
Clients: []mgclients.Client{client},
Clients: []things.Client{client},
},
query: "list_perms=true",
status: http.StatusOK,
@@ -825,7 +825,7 @@ func TestViewThing(t *testing.T) {
}
authCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
svcCall := svc.On("ViewClient", mock.Anything, tc.authnRes, tc.id).Return(mgclients.Client{}, tc.err)
svcCall := svc.On("View", mock.Anything, tc.authnRes, tc.id).Return(things.Client{}, tc.err)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
var errRes respBody
@@ -921,7 +921,7 @@ func TestViewThingPerms(t *testing.T) {
}
authCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
svcCall := svc.On("ViewClientPerms", mock.Anything, tc.authnRes, tc.thingID).Return(tc.response, tc.err)
svcCall := svc.On("ViewPerms", mock.Anything, tc.authnRes, tc.thingID).Return(tc.response, tc.err)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
var resBody respBody
@@ -945,13 +945,13 @@ func TestUpdateThing(t *testing.T) {
newName := "newname"
newTag := "newtag"
newMetadata := mgclients.Metadata{"newkey": "newvalue"}
newMetadata := things.Metadata{"newkey": "newvalue"}
cases := []struct {
desc string
id string
data string
clientResponse mgclients.Client
clientResponse things.Client
domainID string
token string
contentType string
@@ -968,7 +968,7 @@ func TestUpdateThing(t *testing.T) {
data: fmt.Sprintf(`{"name":"%s","tags":["%s"],"metadata":%s}`, newName, newTag, toJSON(newMetadata)),
token: validToken,
contentType: contentType,
clientResponse: mgclients.Client{
clientResponse: things.Client{
ID: client.ID,
Name: newName,
Tags: []string{newTag},
@@ -1043,7 +1043,7 @@ func TestUpdateThing(t *testing.T) {
domainID: domainID,
token: validToken,
contentType: contentType,
clientResponse: mgclients.Client{},
clientResponse: things.Client{},
status: http.StatusBadRequest,
err: apiutil.ErrNameSize,
},
@@ -1061,7 +1061,7 @@ func TestUpdateThing(t *testing.T) {
}
authCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
svcCall := svc.On("UpdateClient", mock.Anything, tc.authnRes, mock.Anything).Return(tc.clientResponse, tc.err)
svcCall := svc.On("Update", mock.Anything, tc.authnRes, mock.Anything).Return(tc.clientResponse, tc.err)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
@@ -1094,7 +1094,7 @@ func TestUpdateThingsTags(t *testing.T) {
id string
data string
contentType string
clientResponse mgclients.Client
clientResponse things.Client
domainID string
token string
status int
@@ -1107,7 +1107,7 @@ func TestUpdateThingsTags(t *testing.T) {
id: client.ID,
data: fmt.Sprintf(`{"tags":["%s"]}`, newTag),
contentType: contentType,
clientResponse: mgclients.Client{
clientResponse: things.Client{
ID: client.ID,
Tags: []string{newTag},
},
@@ -1200,7 +1200,7 @@ func TestUpdateThingsTags(t *testing.T) {
}
authCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
svcCall := svc.On("UpdateClientTags", mock.Anything, tc.authnRes, mock.Anything).Return(tc.clientResponse, tc.err)
svcCall := svc.On("UpdateTags", mock.Anything, tc.authnRes, mock.Anything).Return(tc.clientResponse, tc.err)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
var resBody respBody
@@ -1224,7 +1224,7 @@ func TestUpdateClientSecret(t *testing.T) {
cases := []struct {
desc string
data string
client mgclients.Client
client things.Client
contentType string
domainID string
token string
@@ -1236,9 +1236,9 @@ func TestUpdateClientSecret(t *testing.T) {
{
desc: "update thing secret with valid token",
data: fmt.Sprintf(`{"secret": "%s"}`, "strongersecret"),
client: mgclients.Client{
client: things.Client{
ID: client.ID,
Credentials: mgclients.Credentials{
Credentials: things.Credentials{
Identity: "clientname",
Secret: "strongersecret",
},
@@ -1253,9 +1253,9 @@ func TestUpdateClientSecret(t *testing.T) {
{
desc: "update thing secret with empty token",
data: fmt.Sprintf(`{"secret": "%s"}`, "strongersecret"),
client: mgclients.Client{
client: things.Client{
ID: client.ID,
Credentials: mgclients.Credentials{
Credentials: things.Credentials{
Identity: "clientname",
Secret: "strongersecret",
},
@@ -1269,9 +1269,9 @@ func TestUpdateClientSecret(t *testing.T) {
{
desc: "update thing secret with invalid token",
data: fmt.Sprintf(`{"secret": "%s"}`, "strongersecret"),
client: mgclients.Client{
client: things.Client{
ID: client.ID,
Credentials: mgclients.Credentials{
Credentials: things.Credentials{
Identity: "clientname",
Secret: "strongersecret",
},
@@ -1286,9 +1286,9 @@ func TestUpdateClientSecret(t *testing.T) {
{
desc: "update thing secret with empty id",
data: fmt.Sprintf(`{"secret": "%s"}`, "strongersecret"),
client: mgclients.Client{
client: things.Client{
ID: "",
Credentials: mgclients.Credentials{
Credentials: things.Credentials{
Identity: "clientname",
Secret: "strongersecret",
},
@@ -1303,9 +1303,9 @@ func TestUpdateClientSecret(t *testing.T) {
{
desc: "update thing secret with empty secret",
data: fmt.Sprintf(`{"secret": "%s"}`, ""),
client: mgclients.Client{
client: things.Client{
ID: client.ID,
Credentials: mgclients.Credentials{
Credentials: things.Credentials{
Identity: "clientname",
Secret: "",
},
@@ -1321,9 +1321,9 @@ func TestUpdateClientSecret(t *testing.T) {
{
desc: "update thing secret with invalid contentype",
data: fmt.Sprintf(`{"secret": "%s"}`, ""),
client: mgclients.Client{
client: things.Client{
ID: client.ID,
Credentials: mgclients.Credentials{
Credentials: things.Credentials{
Identity: "clientname",
Secret: "",
},
@@ -1339,9 +1339,9 @@ func TestUpdateClientSecret(t *testing.T) {
{
desc: "update thing secret with malformed data",
data: fmt.Sprintf(`{"secret": %s}`, "invalid"),
client: mgclients.Client{
client: things.Client{
ID: client.ID,
Credentials: mgclients.Credentials{
Credentials: things.Credentials{
Identity: "clientname",
Secret: "",
},
@@ -1368,7 +1368,7 @@ func TestUpdateClientSecret(t *testing.T) {
}
authCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
svcCall := svc.On("UpdateClientSecret", mock.Anything, tc.authnRes, tc.client.ID, mock.Anything).Return(tc.client, tc.err)
svcCall := svc.On("UpdateSecret", mock.Anything, tc.authnRes, tc.client.ID, mock.Anything).Return(tc.client, tc.err)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
var resBody respBody
@@ -1391,8 +1391,8 @@ func TestEnableThing(t *testing.T) {
cases := []struct {
desc string
client mgclients.Client
response mgclients.Client
client things.Client
response things.Client
domainID string
token string
status int
@@ -1403,9 +1403,9 @@ func TestEnableThing(t *testing.T) {
{
desc: "enable thing with valid token",
client: client,
response: mgclients.Client{
response: things.Client{
ID: client.ID,
Status: mgclients.EnabledStatus,
Status: things.EnabledStatus,
},
domainID: domainID,
token: validToken,
@@ -1425,7 +1425,7 @@ func TestEnableThing(t *testing.T) {
},
{
desc: "enable thing with empty id",
client: mgclients.Client{
client: things.Client{
ID: "",
},
domainID: domainID,
@@ -1450,7 +1450,7 @@ func TestEnableThing(t *testing.T) {
}
authCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
svcCall := svc.On("EnableClient", mock.Anything, tc.authnRes, tc.client.ID).Return(tc.response, tc.err)
svcCall := svc.On("Enable", mock.Anything, tc.authnRes, tc.client.ID).Return(tc.response, tc.err)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
var resBody respBody
@@ -1476,8 +1476,8 @@ func TestDisableThing(t *testing.T) {
cases := []struct {
desc string
client mgclients.Client
response mgclients.Client
client things.Client
response things.Client
domainID string
token string
status int
@@ -1488,9 +1488,9 @@ func TestDisableThing(t *testing.T) {
{
desc: "disable thing with valid token",
client: client,
response: mgclients.Client{
response: things.Client{
ID: client.ID,
Status: mgclients.DisabledStatus,
Status: things.DisabledStatus,
},
domainID: domainID,
token: validToken,
@@ -1510,7 +1510,7 @@ func TestDisableThing(t *testing.T) {
},
{
desc: "disable thing with empty id",
client: mgclients.Client{
client: things.Client{
ID: "",
},
domainID: domainID,
@@ -1535,7 +1535,7 @@ func TestDisableThing(t *testing.T) {
}
authCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
svcCall := svc.On("DisableClient", mock.Anything, tc.authnRes, tc.client.ID).Return(tc.response, tc.err)
svcCall := svc.On("Disable", mock.Anything, tc.authnRes, tc.client.ID).Return(tc.response, tc.err)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
var resBody respBody
@@ -1933,7 +1933,7 @@ func TestDeleteThing(t *testing.T) {
}
authCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
svcCall := svc.On("DeleteClient", mock.Anything, tc.authnRes, tc.id).Return(tc.err)
svcCall := svc.On("Delete", mock.Anything, tc.authnRes, tc.id).Return(tc.err)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
@@ -1953,7 +1953,7 @@ func TestListMembers(t *testing.T) {
groupID string
domainID string
token string
listMembersResponse mgclients.MembersPage
listMembersResponse things.MembersPage
status int
authnRes mgauthn.Session
authnErr error
@@ -1965,11 +1965,11 @@ func TestListMembers(t *testing.T) {
token: validToken,
authnRes: mgauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
groupID: client.ID,
listMembersResponse: mgclients.MembersPage{
Page: mgclients.Page{
listMembersResponse: things.MembersPage{
Page: things.Page{
Total: 1,
},
Members: []mgclients.Client{client},
Members: []things.Client{client},
},
status: http.StatusOK,
@@ -1999,12 +1999,12 @@ func TestListMembers(t *testing.T) {
authnRes: mgauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
query: "offset=1",
groupID: client.ID,
listMembersResponse: mgclients.MembersPage{
Page: mgclients.Page{
listMembersResponse: things.MembersPage{
Page: things.Page{
Offset: 1,
Total: 1,
},
Members: []mgclients.Client{client},
Members: []things.Client{client},
},
status: http.StatusOK,
@@ -2028,12 +2028,12 @@ func TestListMembers(t *testing.T) {
authnRes: mgauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
query: "limit=1",
groupID: client.ID,
listMembersResponse: mgclients.MembersPage{
Page: mgclients.Page{
listMembersResponse: things.MembersPage{
Page: things.Page{
Limit: 1,
Total: 1,
},
Members: []mgclients.Client{client},
Members: []things.Client{client},
},
status: http.StatusOK,
@@ -2068,11 +2068,11 @@ func TestListMembers(t *testing.T) {
authnRes: mgauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
query: fmt.Sprintf("channel_id=%s", validID),
groupID: client.ID,
listMembersResponse: mgclients.MembersPage{
Page: mgclients.Page{
listMembersResponse: things.MembersPage{
Page: things.Page{
Total: 1,
},
Members: []mgclients.Client{client},
Members: []things.Client{client},
},
status: http.StatusOK,
@@ -2107,11 +2107,11 @@ func TestListMembers(t *testing.T) {
authnRes: mgauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
query: "connected=true",
groupID: client.ID,
listMembersResponse: mgclients.MembersPage{
Page: mgclients.Page{
listMembersResponse: things.MembersPage{
Page: things.Page{
Total: 1,
},
Members: []mgclients.Client{client},
Members: []things.Client{client},
},
status: http.StatusOK,
@@ -2151,12 +2151,12 @@ func TestListMembers(t *testing.T) {
},
{
desc: "list members with status",
query: fmt.Sprintf("status=%s", mgclients.EnabledStatus),
listMembersResponse: mgclients.MembersPage{
Page: mgclients.Page{
query: fmt.Sprintf("status=%s", things.EnabledStatus),
listMembersResponse: things.MembersPage{
Page: things.Page{
Total: 1,
},
Members: []mgclients.Client{client},
Members: []things.Client{client},
},
domainID: domainID,
token: validToken,
@@ -2179,7 +2179,7 @@ func TestListMembers(t *testing.T) {
},
{
desc: "list members with duplicate status",
query: fmt.Sprintf("status=%s&status=%s", mgclients.EnabledStatus, mgclients.DisabledStatus),
query: fmt.Sprintf("status=%s&status=%s", things.EnabledStatus, things.DisabledStatus),
domainID: domainID,
token: validToken,
authnRes: mgauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
@@ -2193,11 +2193,11 @@ func TestListMembers(t *testing.T) {
domainID: domainID,
token: validToken,
authnRes: mgauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
listMembersResponse: mgclients.MembersPage{
Page: mgclients.Page{
listMembersResponse: things.MembersPage{
Page: things.Page{
Total: 1,
},
Members: []mgclients.Client{client},
Members: []things.Client{client},
},
groupID: client.ID,
query: "metadata=%7B%22domain%22%3A%20%22example.com%22%7D&",
@@ -2230,11 +2230,11 @@ func TestListMembers(t *testing.T) {
{
desc: "list members with permission",
query: fmt.Sprintf("permission=%s", "view"),
listMembersResponse: mgclients.MembersPage{
Page: mgclients.Page{
listMembersResponse: things.MembersPage{
Page: things.Page{
Total: 1,
},
Members: []mgclients.Client{client},
Members: []things.Client{client},
},
domainID: domainID,
token: validToken,
@@ -2261,11 +2261,11 @@ func TestListMembers(t *testing.T) {
domainID: domainID,
token: validToken,
authnRes: mgauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
listMembersResponse: mgclients.MembersPage{
Page: mgclients.Page{
listMembersResponse: things.MembersPage{
Page: things.Page{
Total: 1,
},
Members: []mgclients.Client{client},
Members: []things.Client{client},
},
groupID: client.ID,
status: http.StatusOK,
@@ -2296,18 +2296,18 @@ func TestListMembers(t *testing.T) {
},
{
desc: "list members with all query params",
query: fmt.Sprintf("offset=1&limit=1&channel_id=%s&connected=true&status=%s&metadata=%s&permission=%s&list_perms=true", validID, mgclients.EnabledStatus, "%7B%22domain%22%3A%20%22example.com%22%7D", "view"),
query: fmt.Sprintf("offset=1&limit=1&channel_id=%s&connected=true&status=%s&metadata=%s&permission=%s&list_perms=true", validID, things.EnabledStatus, "%7B%22domain%22%3A%20%22example.com%22%7D", "view"),
domainID: domainID,
token: validToken,
authnRes: mgauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
groupID: client.ID,
listMembersResponse: mgclients.MembersPage{
Page: mgclients.Page{
listMembersResponse: things.MembersPage{
Page: things.Page{
Offset: 1,
Limit: 1,
Total: 1,
},
Members: []mgclients.Client{client},
Members: []things.Client{client},
},
status: http.StatusOK,
@@ -3338,13 +3338,13 @@ func TestDisconnect(t *testing.T) {
}
type respBody struct {
Err string `json:"error"`
Message string `json:"message"`
Total int `json:"total"`
Permissions []string `json:"permissions"`
ID string `json:"id"`
Tags []string `json:"tags"`
Status mgclients.Status `json:"status"`
Err string `json:"error"`
Message string `json:"message"`
Total int `json:"total"`
Permissions []string `json:"permissions"`
ID string `json:"id"`
Tags []string `json:"tags"`
Status things.Status `json:"status"`
}
type groupReqBody struct {
+14 -14
View File
@@ -6,39 +6,39 @@ package http
import (
"github.com/absmach/magistrala/internal/api"
"github.com/absmach/magistrala/pkg/apiutil"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/things"
)
type createClientReq struct {
client mgclients.Client
thing things.Client
}
func (req createClientReq) validate() error {
if len(req.client.Name) > api.MaxNameSize {
if len(req.thing.Name) > api.MaxNameSize {
return apiutil.ErrNameSize
}
if req.client.ID != "" {
return api.ValidateUUID(req.client.ID)
if req.thing.ID != "" {
return api.ValidateUUID(req.thing.ID)
}
return nil
}
type createClientsReq struct {
Clients []mgclients.Client
Things []things.Client
}
func (req createClientsReq) validate() error {
if len(req.Clients) == 0 {
if len(req.Things) == 0 {
return apiutil.ErrEmptyList
}
for _, client := range req.Clients {
if client.ID != "" {
if err := api.ValidateUUID(client.ID); err != nil {
for _, thing := range req.Things {
if thing.ID != "" {
if err := api.ValidateUUID(thing.ID); err != nil {
return err
}
}
if len(client.Name) > api.MaxNameSize {
if len(thing.Name) > api.MaxNameSize {
return apiutil.ErrNameSize
}
}
@@ -71,7 +71,7 @@ func (req viewClientPermsReq) validate() error {
}
type listClientsReq struct {
status mgclients.Status
status things.Status
offset uint64
limit uint64
name string
@@ -80,7 +80,7 @@ type listClientsReq struct {
visibility string
userID string
listPerms bool
metadata mgclients.Metadata
metadata things.Metadata
id string
}
@@ -102,7 +102,7 @@ func (req listClientsReq) validate() error {
}
type listMembersReq struct {
mgclients.Page
things.Page
groupID string
}
+8 -8
View File
@@ -10,7 +10,7 @@ import (
"github.com/absmach/magistrala/internal/api"
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/apiutil"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/things"
"github.com/stretchr/testify/assert"
)
@@ -31,7 +31,7 @@ func TestCreateThingReqValidate(t *testing.T) {
{
desc: "valid request",
req: createClientReq{
client: mgclients.Client{
thing: things.Client{
ID: validID,
Name: valid,
},
@@ -41,7 +41,7 @@ func TestCreateThingReqValidate(t *testing.T) {
{
desc: "name too long",
req: createClientReq{
client: mgclients.Client{
thing: things.Client{
ID: validID,
Name: strings.Repeat("a", api.MaxNameSize+1),
},
@@ -51,7 +51,7 @@ func TestCreateThingReqValidate(t *testing.T) {
{
desc: "invalid id",
req: createClientReq{
client: mgclients.Client{
thing: things.Client{
ID: invalid,
Name: valid,
},
@@ -76,7 +76,7 @@ func TestCreateThingsReqValidate(t *testing.T) {
{
desc: "valid request",
req: createClientsReq{
Clients: []mgclients.Client{
Things: []things.Client{
{
ID: validID,
Name: valid,
@@ -88,14 +88,14 @@ func TestCreateThingsReqValidate(t *testing.T) {
{
desc: "empty list",
req: createClientsReq{
Clients: []mgclients.Client{},
Things: []things.Client{},
},
err: apiutil.ErrEmptyList,
},
{
desc: "name too long",
req: createClientsReq{
Clients: []mgclients.Client{
Things: []things.Client{
{
ID: validID,
Name: strings.Repeat("a", api.MaxNameSize+1),
@@ -107,7 +107,7 @@ func TestCreateThingsReqValidate(t *testing.T) {
{
desc: "invalid id",
req: createClientsReq{
Clients: []mgclients.Client{
Things: []things.Client{
{
ID: invalid,
Name: valid,
+6 -6
View File
@@ -8,7 +8,7 @@ import (
"net/http"
"github.com/absmach/magistrala"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/things"
)
var (
@@ -32,7 +32,7 @@ type pageRes struct {
}
type createClientRes struct {
mgclients.Client
things.Client
created bool
}
@@ -59,7 +59,7 @@ func (res createClientRes) Empty() bool {
}
type updateClientRes struct {
mgclients.Client
things.Client
}
func (res updateClientRes) Code() int {
@@ -75,7 +75,7 @@ func (res updateClientRes) Empty() bool {
}
type viewClientRes struct {
mgclients.Client
things.Client
}
func (res viewClientRes) Code() int {
@@ -124,7 +124,7 @@ func (res clientsPageRes) Empty() bool {
}
type viewMembersRes struct {
mgclients.Client
things.Client
}
func (res viewMembersRes) Code() int {
@@ -140,7 +140,7 @@ func (res viewMembersRes) Empty() bool {
}
type changeClientStatusRes struct {
mgclients.Client
things.Client
}
func (res changeClientStatusRes) Code() int {
+196
View File
@@ -0,0 +1,196 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package things
import (
"context"
"time"
"github.com/absmach/magistrala/pkg/authn"
"github.com/absmach/magistrala/pkg/postgres"
)
type AuthzReq struct {
ChannelID string
ClientID string
ClientKey string
Permission string
}
type ClientRepository struct {
DB postgres.Database
}
// Repository is the interface that wraps the basic methods for
// a client repository.
//
//go:generate mockery --name Repository --output=./mocks --filename repository.go --quiet --note "Copyright (c) Abstract Machines"
type Repository interface {
// RetrieveByID retrieves client by its unique ID.
RetrieveByID(ctx context.Context, id string) (Client, error)
// RetrieveAll retrieves all clients.
RetrieveAll(ctx context.Context, pm Page) (ClientsPage, error)
// SearchClients retrieves clients based on search criteria.
SearchClients(ctx context.Context, pm Page) (ClientsPage, error)
// RetrieveAllByIDs retrieves for given client IDs .
RetrieveAllByIDs(ctx context.Context, pm Page) (ClientsPage, error)
// Update updates the client name and metadata.
Update(ctx context.Context, client Client) (Client, error)
// UpdateTags updates the client tags.
UpdateTags(ctx context.Context, client Client) (Client, error)
// UpdateIdentity updates identity for client with given id.
UpdateIdentity(ctx context.Context, client Client) (Client, error)
// UpdateSecret updates secret for client with given identity.
UpdateSecret(ctx context.Context, client Client) (Client, error)
// ChangeStatus changes client status to enabled or disabled
ChangeStatus(ctx context.Context, client Client) (Client, error)
// Delete deletes client with given id
Delete(ctx context.Context, id string) error
// Save persists the client account. A non-nil error is returned to indicate
// operation failure.
Save(ctx context.Context, client ...Client) ([]Client, error)
// RetrieveBySecret retrieves a client based on the secret (key).
RetrieveBySecret(ctx context.Context, key string) (Client, error)
}
// Service specifies an API that must be fullfiled by the domain service
// implementation, and all of its decorators (e.g. logging & metrics).
//
//go:generate mockery --name Service --filename service.go --quiet --note "Copyright (c) Abstract Machines"
type Service interface {
// CreateClients creates new client. In case of the failed registration, a
// non-nil error value is returned.
CreateClients(ctx context.Context, session authn.Session, client ...Client) ([]Client, error)
// View retrieves client info for a given client ID and an authorized token.
View(ctx context.Context, session authn.Session, id string) (Client, error)
// ViewPerms retrieves permissions on the client id for the given authorized token.
ViewPerms(ctx context.Context, session authn.Session, id string) ([]string, error)
// ListClients retrieves clients list for a valid auth token.
ListClients(ctx context.Context, session authn.Session, reqUserID string, pm Page) (ClientsPage, error)
// ListClientsByGroup retrieves data about subset of clients that are
// connected or not connected to specified channel and belong to the user identified by
// the provided key.
ListClientsByGroup(ctx context.Context, session authn.Session, groupID string, pm Page) (MembersPage, error)
// Update updates the client's name and metadata.
Update(ctx context.Context, session authn.Session, client Client) (Client, error)
// UpdateTags updates the client's tags.
UpdateTags(ctx context.Context, session authn.Session, client Client) (Client, error)
// UpdateSecret updates the client's secret
UpdateSecret(ctx context.Context, session authn.Session, id, key string) (Client, error)
// Enable logically enableds the client identified with the provided ID
Enable(ctx context.Context, session authn.Session, id string) (Client, error)
// Disable logically disables the client identified with the provided ID
Disable(ctx context.Context, session authn.Session, id string) (Client, error)
// Share add share policy to client id with given relation for given user ids
Share(ctx context.Context, session authn.Session, id string, relation string, userids ...string) error
// Unshare remove share policy to client id with given relation for given user ids
Unshare(ctx context.Context, session authn.Session, id string, relation string, userids ...string) error
// Identify returns client ID for given client key.
Identify(ctx context.Context, key string) (string, error)
// Authorize used for Clients authorization.
Authorize(ctx context.Context, req AuthzReq) (string, error)
// Delete deletes client with given ID.
Delete(ctx context.Context, session authn.Session, id string) error
}
// Cache contains client caching interface.
//
//go:generate mockery --name Cache --filename cache.go --quiet --note "Copyright (c) Abstract Machines"
type Cache interface {
// Save stores pair client secret, client id.
Save(ctx context.Context, clientSecret, clientID string) error
// ID returns client ID for given client secret.
ID(ctx context.Context, clientSecret string) (string, error)
// Removes client from cache.
Remove(ctx context.Context, clientID string) error
}
// Client Struct represents a client.
type Client struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Tags []string `json:"tags,omitempty"`
Domain string `json:"domain_id,omitempty"`
Credentials Credentials `json:"credentials,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
UpdatedBy string `json:"updated_by,omitempty"`
Status Status `json:"status,omitempty"` // 1 for enabled, 0 for disabled
Permissions []string `json:"permissions,omitempty"`
Identity string `json:"identity,omitempty"`
}
// ClientsPage contains page related metadata as well as list.
type ClientsPage struct {
Page
Clients []Client
}
// MembersPage contains page related metadata as well as list of members that
// belong to this page.
type MembersPage struct {
Page
Members []Client
}
// Page contains the page metadata that helps navigation.
type Page struct {
Total uint64 `json:"total"`
Offset uint64 `json:"offset"`
Limit uint64 `json:"limit"`
Name string `json:"name,omitempty"`
Id string `json:"id,omitempty"`
Order string `json:"order,omitempty"`
Dir string `json:"dir,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
Domain string `json:"domain,omitempty"`
Tag string `json:"tag,omitempty"`
Permission string `json:"permission,omitempty"`
Status Status `json:"status,omitempty"`
IDs []string `json:"ids,omitempty"`
Identity string `json:"identity,omitempty"`
ListPerms bool `json:"-"`
}
// Metadata represents arbitrary JSON.
type Metadata map[string]interface{}
// Credentials represent client credentials: its
// "identity" which can be a username, email, generated name;
// and "secret" which can be a password or access token.
type Credentials struct {
Identity string `json:"identity,omitempty"` // username or generated login ID
Secret string `json:"secret,omitempty"` // password or token
}
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package clients
package things
import "errors"
+7 -7
View File
@@ -6,12 +6,12 @@ package events
import (
"time"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/events"
"github.com/absmach/magistrala/things"
)
const (
clientPrefix = "thing."
clientPrefix = "client."
clientCreate = clientPrefix + "create"
clientUpdate = clientPrefix + "update"
clientChangeStatus = clientPrefix + "change_status"
@@ -39,7 +39,7 @@ var (
)
type createClientEvent struct {
mgclients.Client
things.Client
}
func (cce createClientEvent) Encode() (map[string]interface{}, error) {
@@ -70,7 +70,7 @@ func (cce createClientEvent) Encode() (map[string]interface{}, error) {
}
type updateClientEvent struct {
mgclients.Client
things.Client
operation string
}
@@ -130,7 +130,7 @@ func (rce changeStatusClientEvent) Encode() (map[string]interface{}, error) {
}
type viewClientEvent struct {
mgclients.Client
things.Client
}
func (vce viewClientEvent) Encode() (map[string]interface{}, error) {
@@ -184,7 +184,7 @@ func (vcpe viewClientPermsEvent) Encode() (map[string]interface{}, error) {
type listClientEvent struct {
reqUserID string
mgclients.Page
things.Page
}
func (lce listClientEvent) Encode() (map[string]interface{}, error) {
@@ -231,7 +231,7 @@ func (lce listClientEvent) Encode() (map[string]interface{}, error) {
}
type listClientByGroupEvent struct {
mgclients.Page
things.Page
channelID string
}
+36 -37
View File
@@ -7,7 +7,6 @@ import (
"context"
"github.com/absmach/magistrala/pkg/authn"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/events"
"github.com/absmach/magistrala/pkg/events/store"
"github.com/absmach/magistrala/things"
@@ -36,8 +35,8 @@ func NewEventStoreMiddleware(ctx context.Context, svc things.Service, url string
}, nil
}
func (es *eventStore) CreateThings(ctx context.Context, session authn.Session, thing ...mgclients.Client) ([]mgclients.Client, error) {
sths, err := es.svc.CreateThings(ctx, session, thing...)
func (es *eventStore) CreateClients(ctx context.Context, session authn.Session, thing ...things.Client) ([]things.Client, error) {
sths, err := es.svc.CreateClients(ctx, session, thing...)
if err != nil {
return sths, err
}
@@ -54,8 +53,8 @@ func (es *eventStore) CreateThings(ctx context.Context, session authn.Session, t
return sths, nil
}
func (es *eventStore) UpdateClient(ctx context.Context, session authn.Session, thing mgclients.Client) (mgclients.Client, error) {
cli, err := es.svc.UpdateClient(ctx, session, thing)
func (es *eventStore) Update(ctx context.Context, session authn.Session, thing things.Client) (things.Client, error) {
cli, err := es.svc.Update(ctx, session, thing)
if err != nil {
return cli, err
}
@@ -63,8 +62,8 @@ func (es *eventStore) UpdateClient(ctx context.Context, session authn.Session, t
return es.update(ctx, "", cli)
}
func (es *eventStore) UpdateClientTags(ctx context.Context, session authn.Session, thing mgclients.Client) (mgclients.Client, error) {
cli, err := es.svc.UpdateClientTags(ctx, session, thing)
func (es *eventStore) UpdateTags(ctx context.Context, session authn.Session, thing things.Client) (things.Client, error) {
cli, err := es.svc.UpdateTags(ctx, session, thing)
if err != nil {
return cli, err
}
@@ -72,8 +71,8 @@ func (es *eventStore) UpdateClientTags(ctx context.Context, session authn.Sessio
return es.update(ctx, "tags", cli)
}
func (es *eventStore) UpdateClientSecret(ctx context.Context, session authn.Session, id, key string) (mgclients.Client, error) {
cli, err := es.svc.UpdateClientSecret(ctx, session, id, key)
func (es *eventStore) UpdateSecret(ctx context.Context, session authn.Session, id, key string) (things.Client, error) {
cli, err := es.svc.UpdateSecret(ctx, session, id, key)
if err != nil {
return cli, err
}
@@ -81,7 +80,7 @@ func (es *eventStore) UpdateClientSecret(ctx context.Context, session authn.Sess
return es.update(ctx, "secret", cli)
}
func (es *eventStore) update(ctx context.Context, operation string, thing mgclients.Client) (mgclients.Client, error) {
func (es *eventStore) update(ctx context.Context, operation string, thing things.Client) (things.Client, error) {
event := updateClientEvent{
thing, operation,
}
@@ -93,24 +92,24 @@ func (es *eventStore) update(ctx context.Context, operation string, thing mgclie
return thing, nil
}
func (es *eventStore) ViewClient(ctx context.Context, session authn.Session, id string) (mgclients.Client, error) {
cli, err := es.svc.ViewClient(ctx, session, id)
func (es *eventStore) View(ctx context.Context, session authn.Session, id string) (things.Client, error) {
thi, err := es.svc.View(ctx, session, id)
if err != nil {
return cli, err
return thi, err
}
event := viewClientEvent{
cli,
thi,
}
if err := es.Publish(ctx, event); err != nil {
return cli, err
return thi, err
}
return cli, nil
return thi, nil
}
func (es *eventStore) ViewClientPerms(ctx context.Context, session authn.Session, id string) ([]string, error) {
permissions, err := es.svc.ViewClientPerms(ctx, session, id)
func (es *eventStore) ViewPerms(ctx context.Context, session authn.Session, id string) ([]string, error) {
permissions, err := es.svc.ViewPerms(ctx, session, id)
if err != nil {
return permissions, err
}
@@ -125,7 +124,7 @@ func (es *eventStore) ViewClientPerms(ctx context.Context, session authn.Session
return permissions, nil
}
func (es *eventStore) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm mgclients.Page) (mgclients.ClientsPage, error) {
func (es *eventStore) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm things.Page) (things.ClientsPage, error) {
cp, err := es.svc.ListClients(ctx, session, reqUserID, pm)
if err != nil {
return cp, err
@@ -141,7 +140,7 @@ func (es *eventStore) ListClients(ctx context.Context, session authn.Session, re
return cp, nil
}
func (es *eventStore) ListClientsByGroup(ctx context.Context, session authn.Session, chID string, pm mgclients.Page) (mgclients.MembersPage, error) {
func (es *eventStore) ListClientsByGroup(ctx context.Context, session authn.Session, chID string, pm things.Page) (things.MembersPage, error) {
mp, err := es.svc.ListClientsByGroup(ctx, session, chID, pm)
if err != nil {
return mp, err
@@ -156,36 +155,36 @@ func (es *eventStore) ListClientsByGroup(ctx context.Context, session authn.Sess
return mp, nil
}
func (es *eventStore) EnableClient(ctx context.Context, session authn.Session, id string) (mgclients.Client, error) {
cli, err := es.svc.EnableClient(ctx, session, id)
func (es *eventStore) Enable(ctx context.Context, session authn.Session, id string) (things.Client, error) {
thi, err := es.svc.Enable(ctx, session, id)
if err != nil {
return cli, err
return thi, err
}
return es.changeStatus(ctx, cli)
return es.changeStatus(ctx, thi)
}
func (es *eventStore) DisableClient(ctx context.Context, session authn.Session, id string) (mgclients.Client, error) {
cli, err := es.svc.DisableClient(ctx, session, id)
func (es *eventStore) Disable(ctx context.Context, session authn.Session, id string) (things.Client, error) {
thi, err := es.svc.Disable(ctx, session, id)
if err != nil {
return cli, err
return thi, err
}
return es.changeStatus(ctx, cli)
return es.changeStatus(ctx, thi)
}
func (es *eventStore) changeStatus(ctx context.Context, cli mgclients.Client) (mgclients.Client, error) {
func (es *eventStore) changeStatus(ctx context.Context, thi things.Client) (things.Client, error) {
event := changeStatusClientEvent{
id: cli.ID,
updatedAt: cli.UpdatedAt,
updatedBy: cli.UpdatedBy,
status: cli.Status.String(),
id: thi.ID,
updatedAt: thi.UpdatedAt,
updatedBy: thi.UpdatedBy,
status: thi.Status.String(),
}
if err := es.Publish(ctx, event); err != nil {
return cli, err
return thi, err
}
return cli, nil
return thi, nil
}
func (es *eventStore) Identify(ctx context.Context, key string) (string, error) {
@@ -252,8 +251,8 @@ func (es *eventStore) Unshare(ctx context.Context, session authn.Session, id, re
return es.Publish(ctx, event)
}
func (es *eventStore) DeleteClient(ctx context.Context, session authn.Session, id string) error {
if err := es.svc.DeleteClient(ctx, session, id); err != nil {
func (es *eventStore) Delete(ctx context.Context, session authn.Session, id string) error {
if err := es.svc.Delete(ctx, session, id); err != nil {
return err
}
+36 -37
View File
@@ -8,7 +8,6 @@ import (
"github.com/absmach/magistrala/pkg/authn"
mgauthz "github.com/absmach/magistrala/pkg/authz"
"github.com/absmach/magistrala/pkg/clients"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/pkg/policies"
"github.com/absmach/magistrala/things"
@@ -29,37 +28,37 @@ func AuthorizationMiddleware(svc things.Service, authz mgauthz.Authorization) th
}
}
func (am *authorizationMiddleware) CreateThings(ctx context.Context, session authn.Session, client ...clients.Client) ([]clients.Client, error) {
func (am *authorizationMiddleware) CreateClients(ctx context.Context, session authn.Session, client ...things.Client) ([]things.Client, error) {
if err := am.authorize(ctx, "", policies.UserType, policies.UsersKind, session.DomainUserID, policies.CreatePermission, policies.DomainType, session.DomainID); err != nil {
return nil, err
}
return am.svc.CreateThings(ctx, session, client...)
return am.svc.CreateClients(ctx, session, client...)
}
func (am *authorizationMiddleware) ViewClient(ctx context.Context, session authn.Session, id string) (clients.Client, error) {
func (am *authorizationMiddleware) View(ctx context.Context, session authn.Session, id string) (things.Client, error) {
if session.DomainUserID == "" {
return clients.Client{}, svcerr.ErrDomainAuthorization
return things.Client{}, svcerr.ErrDomainAuthorization
}
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.ViewPermission, policies.ThingType, id); err != nil {
return clients.Client{}, err
return things.Client{}, err
}
return am.svc.ViewClient(ctx, session, id)
return am.svc.View(ctx, session, id)
}
func (am *authorizationMiddleware) ViewClientPerms(ctx context.Context, session authn.Session, id string) ([]string, error) {
return am.svc.ViewClientPerms(ctx, session, id)
func (am *authorizationMiddleware) ViewPerms(ctx context.Context, session authn.Session, id string) ([]string, error) {
return am.svc.ViewPerms(ctx, session, id)
}
func (am *authorizationMiddleware) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm clients.Page) (clients.ClientsPage, error) {
func (am *authorizationMiddleware) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm things.Page) (things.ClientsPage, error) {
if session.DomainUserID == "" {
return clients.ClientsPage{}, svcerr.ErrDomainAuthorization
return things.ClientsPage{}, svcerr.ErrDomainAuthorization
}
switch {
case reqUserID != "" && reqUserID != session.UserID:
if err := am.authorize(ctx, "", policies.UserType, policies.UsersKind, session.DomainUserID, policies.AdminPermission, policies.DomainType, session.DomainID); err != nil {
return clients.ClientsPage{}, err
return things.ClientsPage{}, err
}
default:
err := am.checkSuperAdmin(ctx, session.UserID)
@@ -68,7 +67,7 @@ func (am *authorizationMiddleware) ListClients(ctx context.Context, session auth
session.SuperAdmin = true
default:
if err := am.authorize(ctx, "", policies.UserType, policies.UsersKind, session.DomainUserID, policies.MembershipPermission, policies.DomainType, session.DomainID); err != nil {
return clients.ClientsPage{}, err
return things.ClientsPage{}, err
}
}
}
@@ -76,67 +75,67 @@ func (am *authorizationMiddleware) ListClients(ctx context.Context, session auth
return am.svc.ListClients(ctx, session, reqUserID, pm)
}
func (am *authorizationMiddleware) ListClientsByGroup(ctx context.Context, session authn.Session, groupID string, pm clients.Page) (clients.MembersPage, error) {
func (am *authorizationMiddleware) ListClientsByGroup(ctx context.Context, session authn.Session, groupID string, pm things.Page) (things.MembersPage, error) {
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, pm.Permission, policies.GroupType, groupID); err != nil {
return clients.MembersPage{}, err
return things.MembersPage{}, err
}
return am.svc.ListClientsByGroup(ctx, session, groupID, pm)
}
func (am *authorizationMiddleware) UpdateClient(ctx context.Context, session authn.Session, client clients.Client) (clients.Client, error) {
func (am *authorizationMiddleware) Update(ctx context.Context, session authn.Session, client things.Client) (things.Client, error) {
if session.DomainUserID == "" {
return clients.Client{}, svcerr.ErrDomainAuthorization
return things.Client{}, svcerr.ErrDomainAuthorization
}
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.EditPermission, policies.ThingType, client.ID); err != nil {
return clients.Client{}, err
return things.Client{}, err
}
return am.svc.UpdateClient(ctx, session, client)
return am.svc.Update(ctx, session, client)
}
func (am *authorizationMiddleware) UpdateClientTags(ctx context.Context, session authn.Session, client clients.Client) (clients.Client, error) {
func (am *authorizationMiddleware) UpdateTags(ctx context.Context, session authn.Session, client things.Client) (things.Client, error) {
if session.DomainUserID == "" {
return clients.Client{}, svcerr.ErrDomainAuthorization
return things.Client{}, svcerr.ErrDomainAuthorization
}
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.EditPermission, policies.ThingType, client.ID); err != nil {
return clients.Client{}, err
return things.Client{}, err
}
return am.svc.UpdateClientTags(ctx, session, client)
return am.svc.UpdateTags(ctx, session, client)
}
func (am *authorizationMiddleware) UpdateClientSecret(ctx context.Context, session authn.Session, id, key string) (clients.Client, error) {
func (am *authorizationMiddleware) UpdateSecret(ctx context.Context, session authn.Session, id, key string) (things.Client, error) {
if session.DomainUserID == "" {
return clients.Client{}, svcerr.ErrDomainAuthorization
return things.Client{}, svcerr.ErrDomainAuthorization
}
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.EditPermission, policies.ThingType, id); err != nil {
return clients.Client{}, err
return things.Client{}, err
}
return am.svc.UpdateClientSecret(ctx, session, id, key)
return am.svc.UpdateSecret(ctx, session, id, key)
}
func (am *authorizationMiddleware) EnableClient(ctx context.Context, session authn.Session, id string) (clients.Client, error) {
func (am *authorizationMiddleware) Enable(ctx context.Context, session authn.Session, id string) (things.Client, error) {
if session.DomainUserID == "" {
return clients.Client{}, svcerr.ErrDomainAuthorization
return things.Client{}, svcerr.ErrDomainAuthorization
}
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.DeletePermission, policies.ThingType, id); err != nil {
return clients.Client{}, err
return things.Client{}, err
}
return am.svc.EnableClient(ctx, session, id)
return am.svc.Enable(ctx, session, id)
}
func (am *authorizationMiddleware) DisableClient(ctx context.Context, session authn.Session, id string) (clients.Client, error) {
func (am *authorizationMiddleware) Disable(ctx context.Context, session authn.Session, id string) (things.Client, error) {
if session.DomainUserID == "" {
return clients.Client{}, svcerr.ErrDomainAuthorization
return things.Client{}, svcerr.ErrDomainAuthorization
}
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.DeletePermission, policies.ThingType, id); err != nil {
return clients.Client{}, err
return things.Client{}, err
}
return am.svc.DisableClient(ctx, session, id)
return am.svc.Disable(ctx, session, id)
}
func (am *authorizationMiddleware) Share(ctx context.Context, session authn.Session, id string, relation string, userids ...string) error {
@@ -163,12 +162,12 @@ func (am *authorizationMiddleware) Authorize(ctx context.Context, req things.Aut
return am.svc.Authorize(ctx, req)
}
func (am *authorizationMiddleware) DeleteClient(ctx context.Context, session authn.Session, id string) error {
func (am *authorizationMiddleware) Delete(ctx context.Context, session authn.Session, id string) error {
if err := am.authorize(ctx, session.DomainID, policies.UserType, policies.UsersKind, session.DomainUserID, policies.DeletePermission, policies.ThingType, id); err != nil {
return err
}
return am.svc.DeleteClient(ctx, session, id)
return am.svc.Delete(ctx, session, id)
}
func (am *authorizationMiddleware) checkSuperAdmin(ctx context.Context, adminID string) error {
+31 -32
View File
@@ -10,7 +10,6 @@ import (
"time"
"github.com/absmach/magistrala/pkg/authn"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/things"
)
@@ -25,7 +24,7 @@ func LoggingMiddleware(svc things.Service, logger *slog.Logger) things.Service {
return &loggingMiddleware{logger, svc}
}
func (lm *loggingMiddleware) CreateThings(ctx context.Context, session authn.Session, clients ...mgclients.Client) (cs []mgclients.Client, err error) {
func (lm *loggingMiddleware) CreateClients(ctx context.Context, session authn.Session, clients ...things.Client) (cs []things.Client, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
@@ -37,10 +36,10 @@ func (lm *loggingMiddleware) CreateThings(ctx context.Context, session authn.Ses
}
lm.logger.Info(fmt.Sprintf("Create %d things completed successfully", len(clients)), args...)
}(time.Now())
return lm.svc.CreateThings(ctx, session, clients...)
return lm.svc.CreateClients(ctx, session, clients...)
}
func (lm *loggingMiddleware) ViewClient(ctx context.Context, session authn.Session, id string) (c mgclients.Client, err error) {
func (lm *loggingMiddleware) View(ctx context.Context, session authn.Session, id string) (c things.Client, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
@@ -56,10 +55,10 @@ func (lm *loggingMiddleware) ViewClient(ctx context.Context, session authn.Sessi
}
lm.logger.Info("View thing completed successfully", args...)
}(time.Now())
return lm.svc.ViewClient(ctx, session, id)
return lm.svc.View(ctx, session, id)
}
func (lm *loggingMiddleware) ViewClientPerms(ctx context.Context, session authn.Session, id string) (p []string, err error) {
func (lm *loggingMiddleware) ViewPerms(ctx context.Context, session authn.Session, id string) (p []string, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
@@ -72,10 +71,10 @@ func (lm *loggingMiddleware) ViewClientPerms(ctx context.Context, session authn.
}
lm.logger.Info("View thing permissions completed successfully", args...)
}(time.Now())
return lm.svc.ViewClientPerms(ctx, session, id)
return lm.svc.ViewPerms(ctx, session, id)
}
func (lm *loggingMiddleware) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm mgclients.Page) (cp mgclients.ClientsPage, err error) {
func (lm *loggingMiddleware) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm things.Page) (cp things.ClientsPage, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
@@ -96,7 +95,7 @@ func (lm *loggingMiddleware) ListClients(ctx context.Context, session authn.Sess
return lm.svc.ListClients(ctx, session, reqUserID, pm)
}
func (lm *loggingMiddleware) UpdateClient(ctx context.Context, session authn.Session, client mgclients.Client) (c mgclients.Client, err error) {
func (lm *loggingMiddleware) Update(ctx context.Context, session authn.Session, client things.Client) (c things.Client, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
@@ -113,10 +112,10 @@ func (lm *loggingMiddleware) UpdateClient(ctx context.Context, session authn.Ses
}
lm.logger.Info("Update thing completed successfully", args...)
}(time.Now())
return lm.svc.UpdateClient(ctx, session, client)
return lm.svc.Update(ctx, session, client)
}
func (lm *loggingMiddleware) UpdateClientTags(ctx context.Context, session authn.Session, client mgclients.Client) (c mgclients.Client, err error) {
func (lm *loggingMiddleware) UpdateTags(ctx context.Context, session authn.Session, client things.Client) (c things.Client, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
@@ -133,10 +132,10 @@ func (lm *loggingMiddleware) UpdateClientTags(ctx context.Context, session authn
}
lm.logger.Info("Update thing tags completed successfully", args...)
}(time.Now())
return lm.svc.UpdateClientTags(ctx, session, client)
return lm.svc.UpdateTags(ctx, session, client)
}
func (lm *loggingMiddleware) UpdateClientSecret(ctx context.Context, session authn.Session, oldSecret, newSecret string) (c mgclients.Client, err error) {
func (lm *loggingMiddleware) UpdateSecret(ctx context.Context, session authn.Session, oldSecret, newSecret string) (c things.Client, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
@@ -152,10 +151,10 @@ func (lm *loggingMiddleware) UpdateClientSecret(ctx context.Context, session aut
}
lm.logger.Info("Update thing secret completed successfully", args...)
}(time.Now())
return lm.svc.UpdateClientSecret(ctx, session, oldSecret, newSecret)
return lm.svc.UpdateSecret(ctx, session, oldSecret, newSecret)
}
func (lm *loggingMiddleware) EnableClient(ctx context.Context, session authn.Session, id string) (c mgclients.Client, err error) {
func (lm *loggingMiddleware) Enable(ctx context.Context, session authn.Session, id string) (c things.Client, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
@@ -171,10 +170,10 @@ func (lm *loggingMiddleware) EnableClient(ctx context.Context, session authn.Ses
}
lm.logger.Info("Enable thing completed successfully", args...)
}(time.Now())
return lm.svc.EnableClient(ctx, session, id)
return lm.svc.Enable(ctx, session, id)
}
func (lm *loggingMiddleware) DisableClient(ctx context.Context, session authn.Session, id string) (c mgclients.Client, err error) {
func (lm *loggingMiddleware) Disable(ctx context.Context, session authn.Session, id string) (c things.Client, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
@@ -190,10 +189,10 @@ func (lm *loggingMiddleware) DisableClient(ctx context.Context, session authn.Se
}
lm.logger.Info("Disable thing completed successfully", args...)
}(time.Now())
return lm.svc.DisableClient(ctx, session, id)
return lm.svc.Disable(ctx, session, id)
}
func (lm *loggingMiddleware) ListClientsByGroup(ctx context.Context, session authn.Session, channelID string, cp mgclients.Page) (mp mgclients.MembersPage, err error) {
func (lm *loggingMiddleware) ListClientsByGroup(ctx context.Context, session authn.Session, channelID string, cp things.Page) (mp things.MembersPage, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
@@ -234,8 +233,8 @@ func (lm *loggingMiddleware) Authorize(ctx context.Context, req things.AuthzReq)
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("thingID", req.ThingID),
slog.String("thingID", req.ThingKey),
slog.String("clientID", req.ClientID),
slog.String("clientKey", req.ClientKey),
slog.String("channelID", req.ChannelID),
slog.String("permission", req.Permission),
}
@@ -253,16 +252,16 @@ func (lm *loggingMiddleware) Share(ctx context.Context, session authn.Session, i
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("thing_id", id),
slog.String("client_id", id),
slog.Any("user_ids", userids),
slog.String("relation", relation),
}
if err != nil {
args = append(args, slog.Any("error", err))
lm.logger.Warn("Share thing failed", args...)
lm.logger.Warn("Share client failed", args...)
return
}
lm.logger.Info("Share thing completed successfully", args...)
lm.logger.Info("Share client completed successfully", args...)
}(time.Now())
return lm.svc.Share(ctx, session, id, relation, userids...)
}
@@ -271,32 +270,32 @@ func (lm *loggingMiddleware) Unshare(ctx context.Context, session authn.Session,
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("thing_id", id),
slog.String("client_id", id),
slog.Any("user_ids", userids),
slog.String("relation", relation),
}
if err != nil {
args = append(args, slog.Any("error", err))
lm.logger.Warn("Unshare thing failed", args...)
lm.logger.Warn("Unshare client failed", args...)
return
}
lm.logger.Info("Unshare thing completed successfully", args...)
lm.logger.Info("Unshare client completed successfully", args...)
}(time.Now())
return lm.svc.Unshare(ctx, session, id, relation, userids...)
}
func (lm *loggingMiddleware) DeleteClient(ctx context.Context, session authn.Session, id string) (err error) {
func (lm *loggingMiddleware) Delete(ctx context.Context, session authn.Session, id string) (err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("thing_id", id),
slog.String("client_id", id),
}
if err != nil {
args = append(args, slog.Any("error", err))
lm.logger.Warn("Delete thing failed", args...)
lm.logger.Warn("Delete client failed", args...)
return
}
lm.logger.Info("Delete thing completed successfully", args...)
lm.logger.Info("Delete client completed successfully", args...)
}(time.Now())
return lm.svc.DeleteClient(ctx, session, id)
return lm.svc.Delete(ctx, session, id)
}
+42 -43
View File
@@ -8,7 +8,6 @@ import (
"time"
"github.com/absmach/magistrala/pkg/authn"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/things"
"github.com/go-kit/kit/metrics"
)
@@ -30,90 +29,90 @@ func MetricsMiddleware(svc things.Service, counter metrics.Counter, latency metr
}
}
func (ms *metricsMiddleware) CreateThings(ctx context.Context, session authn.Session, clients ...mgclients.Client) ([]mgclients.Client, error) {
func (ms *metricsMiddleware) CreateClients(ctx context.Context, session authn.Session, things ...things.Client) ([]things.Client, error) {
defer func(begin time.Time) {
ms.counter.With("method", "register_things").Add(1)
ms.latency.With("method", "register_things").Observe(time.Since(begin).Seconds())
ms.counter.With("method", "register_clients").Add(1)
ms.latency.With("method", "register_clients").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.CreateThings(ctx, session, clients...)
return ms.svc.CreateClients(ctx, session, things...)
}
func (ms *metricsMiddleware) ViewClient(ctx context.Context, session authn.Session, id string) (mgclients.Client, error) {
func (ms *metricsMiddleware) View(ctx context.Context, session authn.Session, id string) (things.Client, error) {
defer func(begin time.Time) {
ms.counter.With("method", "view_thing").Add(1)
ms.latency.With("method", "view_thing").Observe(time.Since(begin).Seconds())
ms.counter.With("method", "view_client").Add(1)
ms.latency.With("method", "view_client").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.ViewClient(ctx, session, id)
return ms.svc.View(ctx, session, id)
}
func (ms *metricsMiddleware) ViewClientPerms(ctx context.Context, session authn.Session, id string) ([]string, error) {
func (ms *metricsMiddleware) ViewPerms(ctx context.Context, session authn.Session, id string) ([]string, error) {
defer func(begin time.Time) {
ms.counter.With("method", "view_thing_permissions").Add(1)
ms.latency.With("method", "view_thing_permissions").Observe(time.Since(begin).Seconds())
ms.counter.With("method", "view_client_permissions").Add(1)
ms.latency.With("method", "view_client_permissions").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.ViewClientPerms(ctx, session, id)
return ms.svc.ViewPerms(ctx, session, id)
}
func (ms *metricsMiddleware) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm mgclients.Page) (mgclients.ClientsPage, error) {
func (ms *metricsMiddleware) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm things.Page) (things.ClientsPage, error) {
defer func(begin time.Time) {
ms.counter.With("method", "list_things").Add(1)
ms.latency.With("method", "list_things").Observe(time.Since(begin).Seconds())
ms.counter.With("method", "list_clients").Add(1)
ms.latency.With("method", "list_clients").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.ListClients(ctx, session, reqUserID, pm)
}
func (ms *metricsMiddleware) UpdateClient(ctx context.Context, session authn.Session, client mgclients.Client) (mgclients.Client, error) {
func (ms *metricsMiddleware) Update(ctx context.Context, session authn.Session, thing things.Client) (things.Client, error) {
defer func(begin time.Time) {
ms.counter.With("method", "update_thing_name_and_metadata").Add(1)
ms.latency.With("method", "update_thing_name_and_metadata").Observe(time.Since(begin).Seconds())
ms.counter.With("method", "update_client").Add(1)
ms.latency.With("method", "update_client").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.UpdateClient(ctx, session, client)
return ms.svc.Update(ctx, session, thing)
}
func (ms *metricsMiddleware) UpdateClientTags(ctx context.Context, session authn.Session, client mgclients.Client) (mgclients.Client, error) {
func (ms *metricsMiddleware) UpdateTags(ctx context.Context, session authn.Session, thing things.Client) (things.Client, error) {
defer func(begin time.Time) {
ms.counter.With("method", "update_thing_tags").Add(1)
ms.latency.With("method", "update_thing_tags").Observe(time.Since(begin).Seconds())
ms.counter.With("method", "update_client_tags").Add(1)
ms.latency.With("method", "update_client_tags").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.UpdateClientTags(ctx, session, client)
return ms.svc.UpdateTags(ctx, session, thing)
}
func (ms *metricsMiddleware) UpdateClientSecret(ctx context.Context, session authn.Session, oldSecret, newSecret string) (mgclients.Client, error) {
func (ms *metricsMiddleware) UpdateSecret(ctx context.Context, session authn.Session, oldSecret, newSecret string) (things.Client, error) {
defer func(begin time.Time) {
ms.counter.With("method", "update_thing_secret").Add(1)
ms.latency.With("method", "update_thing_secret").Observe(time.Since(begin).Seconds())
ms.counter.With("method", "update_client_secret").Add(1)
ms.latency.With("method", "update_client_secret").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.UpdateClientSecret(ctx, session, oldSecret, newSecret)
return ms.svc.UpdateSecret(ctx, session, oldSecret, newSecret)
}
func (ms *metricsMiddleware) EnableClient(ctx context.Context, session authn.Session, id string) (mgclients.Client, error) {
func (ms *metricsMiddleware) Enable(ctx context.Context, session authn.Session, id string) (things.Client, error) {
defer func(begin time.Time) {
ms.counter.With("method", "enable_thing").Add(1)
ms.latency.With("method", "enable_thing").Observe(time.Since(begin).Seconds())
ms.counter.With("method", "enable_client").Add(1)
ms.latency.With("method", "enable_client").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.EnableClient(ctx, session, id)
return ms.svc.Enable(ctx, session, id)
}
func (ms *metricsMiddleware) DisableClient(ctx context.Context, session authn.Session, id string) (mgclients.Client, error) {
func (ms *metricsMiddleware) Disable(ctx context.Context, session authn.Session, id string) (things.Client, error) {
defer func(begin time.Time) {
ms.counter.With("method", "disable_thing").Add(1)
ms.latency.With("method", "disable_thing").Observe(time.Since(begin).Seconds())
ms.counter.With("method", "disable_client").Add(1)
ms.latency.With("method", "disable_client").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.DisableClient(ctx, session, id)
return ms.svc.Disable(ctx, session, id)
}
func (ms *metricsMiddleware) ListClientsByGroup(ctx context.Context, session authn.Session, groupID string, pm mgclients.Page) (mp mgclients.MembersPage, err error) {
func (ms *metricsMiddleware) ListClientsByGroup(ctx context.Context, session authn.Session, groupID string, pm things.Page) (mp things.MembersPage, err error) {
defer func(begin time.Time) {
ms.counter.With("method", "list_things_by_channel").Add(1)
ms.latency.With("method", "list_things_by_channel").Observe(time.Since(begin).Seconds())
ms.counter.With("method", "list_clients_by_channel").Add(1)
ms.latency.With("method", "list_clients_by_channel").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.ListClientsByGroup(ctx, session, groupID, pm)
}
func (ms *metricsMiddleware) Identify(ctx context.Context, key string) (string, error) {
defer func(begin time.Time) {
ms.counter.With("method", "identify_thing").Add(1)
ms.latency.With("method", "identify_thing").Observe(time.Since(begin).Seconds())
ms.counter.With("method", "identify_client").Add(1)
ms.latency.With("method", "identify_client").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.Identify(ctx, key)
}
@@ -142,10 +141,10 @@ func (ms *metricsMiddleware) Unshare(ctx context.Context, session authn.Session,
return ms.svc.Unshare(ctx, session, id, relation, userids...)
}
func (ms *metricsMiddleware) DeleteClient(ctx context.Context, session authn.Session, id string) error {
func (ms *metricsMiddleware) Delete(ctx context.Context, session authn.Session, id string) error {
defer func(begin time.Time) {
ms.counter.With("method", "delete_client").Add(1)
ms.latency.With("method", "delete_client").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.DeleteClient(ctx, session, id)
return ms.svc.Delete(ctx, session, id)
}
+14 -14
View File
@@ -15,9 +15,9 @@ type Cache struct {
mock.Mock
}
// ID provides a mock function with given fields: ctx, thingSecret
func (_m *Cache) ID(ctx context.Context, thingSecret string) (string, error) {
ret := _m.Called(ctx, thingSecret)
// ID provides a mock function with given fields: ctx, clientSecret
func (_m *Cache) ID(ctx context.Context, clientSecret string) (string, error) {
ret := _m.Called(ctx, clientSecret)
if len(ret) == 0 {
panic("no return value specified for ID")
@@ -26,16 +26,16 @@ func (_m *Cache) ID(ctx context.Context, thingSecret string) (string, error) {
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (string, error)); ok {
return rf(ctx, thingSecret)
return rf(ctx, clientSecret)
}
if rf, ok := ret.Get(0).(func(context.Context, string) string); ok {
r0 = rf(ctx, thingSecret)
r0 = rf(ctx, clientSecret)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, thingSecret)
r1 = rf(ctx, clientSecret)
} else {
r1 = ret.Error(1)
}
@@ -43,9 +43,9 @@ func (_m *Cache) ID(ctx context.Context, thingSecret string) (string, error) {
return r0, r1
}
// Remove provides a mock function with given fields: ctx, thingID
func (_m *Cache) Remove(ctx context.Context, thingID string) error {
ret := _m.Called(ctx, thingID)
// Remove provides a mock function with given fields: ctx, clientID
func (_m *Cache) Remove(ctx context.Context, clientID string) error {
ret := _m.Called(ctx, clientID)
if len(ret) == 0 {
panic("no return value specified for Remove")
@@ -53,7 +53,7 @@ func (_m *Cache) Remove(ctx context.Context, thingID string) error {
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, thingID)
r0 = rf(ctx, clientID)
} else {
r0 = ret.Error(0)
}
@@ -61,9 +61,9 @@ func (_m *Cache) Remove(ctx context.Context, thingID string) error {
return r0
}
// Save provides a mock function with given fields: ctx, thingSecret, thingID
func (_m *Cache) Save(ctx context.Context, thingSecret string, thingID string) error {
ret := _m.Called(ctx, thingSecret, thingID)
// Save provides a mock function with given fields: ctx, clientSecret, clientID
func (_m *Cache) Save(ctx context.Context, clientSecret string, clientID string) error {
ret := _m.Called(ctx, clientSecret, clientID)
if len(ret) == 0 {
panic("no return value specified for Save")
@@ -71,7 +71,7 @@ func (_m *Cache) Save(ctx context.Context, thingSecret string, thingID string) e
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
r0 = rf(ctx, thingSecret, thingID)
r0 = rf(ctx, clientSecret, clientID)
} else {
r0 = ret.Error(0)
}
+65 -122
View File
@@ -7,8 +7,7 @@ package mocks
import (
context "context"
clients "github.com/absmach/magistrala/pkg/clients"
things "github.com/absmach/magistrala/things"
mock "github.com/stretchr/testify/mock"
)
@@ -18,25 +17,25 @@ type Repository struct {
}
// ChangeStatus provides a mock function with given fields: ctx, client
func (_m *Repository) ChangeStatus(ctx context.Context, client clients.Client) (clients.Client, error) {
func (_m *Repository) ChangeStatus(ctx context.Context, client things.Client) (things.Client, error) {
ret := _m.Called(ctx, client)
if len(ret) == 0 {
panic("no return value specified for ChangeStatus")
}
var r0 clients.Client
var r0 things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, clients.Client) (clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Client) (things.Client, error)); ok {
return rf(ctx, client)
}
if rf, ok := ret.Get(0).(func(context.Context, clients.Client) clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Client) things.Client); ok {
r0 = rf(ctx, client)
} else {
r0 = ret.Get(0).(clients.Client)
r0 = ret.Get(0).(things.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, clients.Client) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, things.Client) error); ok {
r1 = rf(ctx, client)
} else {
r1 = ret.Error(1)
@@ -64,25 +63,25 @@ func (_m *Repository) Delete(ctx context.Context, id string) error {
}
// RetrieveAll provides a mock function with given fields: ctx, pm
func (_m *Repository) RetrieveAll(ctx context.Context, pm clients.Page) (clients.ClientsPage, error) {
func (_m *Repository) RetrieveAll(ctx context.Context, pm things.Page) (things.ClientsPage, error) {
ret := _m.Called(ctx, pm)
if len(ret) == 0 {
panic("no return value specified for RetrieveAll")
}
var r0 clients.ClientsPage
var r0 things.ClientsPage
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, clients.Page) (clients.ClientsPage, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Page) (things.ClientsPage, error)); ok {
return rf(ctx, pm)
}
if rf, ok := ret.Get(0).(func(context.Context, clients.Page) clients.ClientsPage); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Page) things.ClientsPage); ok {
r0 = rf(ctx, pm)
} else {
r0 = ret.Get(0).(clients.ClientsPage)
r0 = ret.Get(0).(things.ClientsPage)
}
if rf, ok := ret.Get(1).(func(context.Context, clients.Page) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, things.Page) error); ok {
r1 = rf(ctx, pm)
} else {
r1 = ret.Error(1)
@@ -92,25 +91,25 @@ func (_m *Repository) RetrieveAll(ctx context.Context, pm clients.Page) (clients
}
// RetrieveAllByIDs provides a mock function with given fields: ctx, pm
func (_m *Repository) RetrieveAllByIDs(ctx context.Context, pm clients.Page) (clients.ClientsPage, error) {
func (_m *Repository) RetrieveAllByIDs(ctx context.Context, pm things.Page) (things.ClientsPage, error) {
ret := _m.Called(ctx, pm)
if len(ret) == 0 {
panic("no return value specified for RetrieveAllByIDs")
}
var r0 clients.ClientsPage
var r0 things.ClientsPage
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, clients.Page) (clients.ClientsPage, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Page) (things.ClientsPage, error)); ok {
return rf(ctx, pm)
}
if rf, ok := ret.Get(0).(func(context.Context, clients.Page) clients.ClientsPage); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Page) things.ClientsPage); ok {
r0 = rf(ctx, pm)
} else {
r0 = ret.Get(0).(clients.ClientsPage)
r0 = ret.Get(0).(things.ClientsPage)
}
if rf, ok := ret.Get(1).(func(context.Context, clients.Page) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, things.Page) error); ok {
r1 = rf(ctx, pm)
} else {
r1 = ret.Error(1)
@@ -120,22 +119,22 @@ func (_m *Repository) RetrieveAllByIDs(ctx context.Context, pm clients.Page) (cl
}
// RetrieveByID provides a mock function with given fields: ctx, id
func (_m *Repository) RetrieveByID(ctx context.Context, id string) (clients.Client, error) {
func (_m *Repository) RetrieveByID(ctx context.Context, id string) (things.Client, error) {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for RetrieveByID")
}
var r0 clients.Client
var r0 things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, string) (things.Client, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, string) clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, string) things.Client); ok {
r0 = rf(ctx, id)
} else {
r0 = ret.Get(0).(clients.Client)
r0 = ret.Get(0).(things.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
@@ -147,51 +146,23 @@ func (_m *Repository) RetrieveByID(ctx context.Context, id string) (clients.Clie
return r0, r1
}
// RetrieveByIdentity provides a mock function with given fields: ctx, identity
func (_m *Repository) RetrieveByIdentity(ctx context.Context, identity string) (clients.Client, error) {
ret := _m.Called(ctx, identity)
if len(ret) == 0 {
panic("no return value specified for RetrieveByIdentity")
}
var r0 clients.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (clients.Client, error)); ok {
return rf(ctx, identity)
}
if rf, ok := ret.Get(0).(func(context.Context, string) clients.Client); ok {
r0 = rf(ctx, identity)
} else {
r0 = ret.Get(0).(clients.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, identity)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// RetrieveBySecret provides a mock function with given fields: ctx, key
func (_m *Repository) RetrieveBySecret(ctx context.Context, key string) (clients.Client, error) {
func (_m *Repository) RetrieveBySecret(ctx context.Context, key string) (things.Client, error) {
ret := _m.Called(ctx, key)
if len(ret) == 0 {
panic("no return value specified for RetrieveBySecret")
}
var r0 clients.Client
var r0 things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, string) (things.Client, error)); ok {
return rf(ctx, key)
}
if rf, ok := ret.Get(0).(func(context.Context, string) clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, string) things.Client); ok {
r0 = rf(ctx, key)
} else {
r0 = ret.Get(0).(clients.Client)
r0 = ret.Get(0).(things.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
@@ -204,7 +175,7 @@ func (_m *Repository) RetrieveBySecret(ctx context.Context, key string) (clients
}
// Save provides a mock function with given fields: ctx, client
func (_m *Repository) Save(ctx context.Context, client ...clients.Client) ([]clients.Client, error) {
func (_m *Repository) Save(ctx context.Context, client ...things.Client) ([]things.Client, error) {
_va := make([]interface{}, len(client))
for _i := range client {
_va[_i] = client[_i]
@@ -218,20 +189,20 @@ func (_m *Repository) Save(ctx context.Context, client ...clients.Client) ([]cli
panic("no return value specified for Save")
}
var r0 []clients.Client
var r0 []things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, ...clients.Client) ([]clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, ...things.Client) ([]things.Client, error)); ok {
return rf(ctx, client...)
}
if rf, ok := ret.Get(0).(func(context.Context, ...clients.Client) []clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, ...things.Client) []things.Client); ok {
r0 = rf(ctx, client...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]clients.Client)
r0 = ret.Get(0).([]things.Client)
}
}
if rf, ok := ret.Get(1).(func(context.Context, ...clients.Client) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, ...things.Client) error); ok {
r1 = rf(ctx, client...)
} else {
r1 = ret.Error(1)
@@ -241,25 +212,25 @@ func (_m *Repository) Save(ctx context.Context, client ...clients.Client) ([]cli
}
// SearchClients provides a mock function with given fields: ctx, pm
func (_m *Repository) SearchClients(ctx context.Context, pm clients.Page) (clients.ClientsPage, error) {
func (_m *Repository) SearchClients(ctx context.Context, pm things.Page) (things.ClientsPage, error) {
ret := _m.Called(ctx, pm)
if len(ret) == 0 {
panic("no return value specified for SearchClients")
}
var r0 clients.ClientsPage
var r0 things.ClientsPage
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, clients.Page) (clients.ClientsPage, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Page) (things.ClientsPage, error)); ok {
return rf(ctx, pm)
}
if rf, ok := ret.Get(0).(func(context.Context, clients.Page) clients.ClientsPage); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Page) things.ClientsPage); ok {
r0 = rf(ctx, pm)
} else {
r0 = ret.Get(0).(clients.ClientsPage)
r0 = ret.Get(0).(things.ClientsPage)
}
if rf, ok := ret.Get(1).(func(context.Context, clients.Page) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, things.Page) error); ok {
r1 = rf(ctx, pm)
} else {
r1 = ret.Error(1)
@@ -269,25 +240,25 @@ func (_m *Repository) SearchClients(ctx context.Context, pm clients.Page) (clien
}
// Update provides a mock function with given fields: ctx, client
func (_m *Repository) Update(ctx context.Context, client clients.Client) (clients.Client, error) {
func (_m *Repository) Update(ctx context.Context, client things.Client) (things.Client, error) {
ret := _m.Called(ctx, client)
if len(ret) == 0 {
panic("no return value specified for Update")
}
var r0 clients.Client
var r0 things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, clients.Client) (clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Client) (things.Client, error)); ok {
return rf(ctx, client)
}
if rf, ok := ret.Get(0).(func(context.Context, clients.Client) clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Client) things.Client); ok {
r0 = rf(ctx, client)
} else {
r0 = ret.Get(0).(clients.Client)
r0 = ret.Get(0).(things.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, clients.Client) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, things.Client) error); ok {
r1 = rf(ctx, client)
} else {
r1 = ret.Error(1)
@@ -297,53 +268,25 @@ func (_m *Repository) Update(ctx context.Context, client clients.Client) (client
}
// UpdateIdentity provides a mock function with given fields: ctx, client
func (_m *Repository) UpdateIdentity(ctx context.Context, client clients.Client) (clients.Client, error) {
func (_m *Repository) UpdateIdentity(ctx context.Context, client things.Client) (things.Client, error) {
ret := _m.Called(ctx, client)
if len(ret) == 0 {
panic("no return value specified for UpdateIdentity")
}
var r0 clients.Client
var r0 things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, clients.Client) (clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Client) (things.Client, error)); ok {
return rf(ctx, client)
}
if rf, ok := ret.Get(0).(func(context.Context, clients.Client) clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Client) things.Client); ok {
r0 = rf(ctx, client)
} else {
r0 = ret.Get(0).(clients.Client)
r0 = ret.Get(0).(things.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, clients.Client) error); ok {
r1 = rf(ctx, client)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// UpdateRole provides a mock function with given fields: ctx, client
func (_m *Repository) UpdateRole(ctx context.Context, client clients.Client) (clients.Client, error) {
ret := _m.Called(ctx, client)
if len(ret) == 0 {
panic("no return value specified for UpdateRole")
}
var r0 clients.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, clients.Client) (clients.Client, error)); ok {
return rf(ctx, client)
}
if rf, ok := ret.Get(0).(func(context.Context, clients.Client) clients.Client); ok {
r0 = rf(ctx, client)
} else {
r0 = ret.Get(0).(clients.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, clients.Client) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, things.Client) error); ok {
r1 = rf(ctx, client)
} else {
r1 = ret.Error(1)
@@ -353,25 +296,25 @@ func (_m *Repository) UpdateRole(ctx context.Context, client clients.Client) (cl
}
// UpdateSecret provides a mock function with given fields: ctx, client
func (_m *Repository) UpdateSecret(ctx context.Context, client clients.Client) (clients.Client, error) {
func (_m *Repository) UpdateSecret(ctx context.Context, client things.Client) (things.Client, error) {
ret := _m.Called(ctx, client)
if len(ret) == 0 {
panic("no return value specified for UpdateSecret")
}
var r0 clients.Client
var r0 things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, clients.Client) (clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Client) (things.Client, error)); ok {
return rf(ctx, client)
}
if rf, ok := ret.Get(0).(func(context.Context, clients.Client) clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Client) things.Client); ok {
r0 = rf(ctx, client)
} else {
r0 = ret.Get(0).(clients.Client)
r0 = ret.Get(0).(things.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, clients.Client) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, things.Client) error); ok {
r1 = rf(ctx, client)
} else {
r1 = ret.Error(1)
@@ -381,25 +324,25 @@ func (_m *Repository) UpdateSecret(ctx context.Context, client clients.Client) (
}
// UpdateTags provides a mock function with given fields: ctx, client
func (_m *Repository) UpdateTags(ctx context.Context, client clients.Client) (clients.Client, error) {
func (_m *Repository) UpdateTags(ctx context.Context, client things.Client) (things.Client, error) {
ret := _m.Called(ctx, client)
if len(ret) == 0 {
panic("no return value specified for UpdateTags")
}
var r0 clients.Client
var r0 things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, clients.Client) (clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Client) (things.Client, error)); ok {
return rf(ctx, client)
}
if rf, ok := ret.Get(0).(func(context.Context, clients.Client) clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, things.Client) things.Client); ok {
r0 = rf(ctx, client)
} else {
r0 = ret.Get(0).(clients.Client)
r0 = ret.Get(0).(things.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, clients.Client) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, things.Client) error); ok {
r1 = rf(ctx, client)
} else {
r1 = ret.Error(1)
+72 -73
View File
@@ -5,11 +5,10 @@
package mocks
import (
authn "github.com/absmach/magistrala/pkg/authn"
clients "github.com/absmach/magistrala/pkg/clients"
context "context"
authn "github.com/absmach/magistrala/pkg/authn"
mock "github.com/stretchr/testify/mock"
things "github.com/absmach/magistrala/things"
@@ -48,8 +47,8 @@ func (_m *Service) Authorize(ctx context.Context, req things.AuthzReq) (string,
return r0, r1
}
// CreateThings provides a mock function with given fields: ctx, session, client
func (_m *Service) CreateThings(ctx context.Context, session authn.Session, client ...clients.Client) ([]clients.Client, error) {
// CreateClients provides a mock function with given fields: ctx, session, client
func (_m *Service) CreateClients(ctx context.Context, session authn.Session, client ...things.Client) ([]things.Client, error) {
_va := make([]interface{}, len(client))
for _i := range client {
_va[_i] = client[_i]
@@ -60,23 +59,23 @@ func (_m *Service) CreateThings(ctx context.Context, session authn.Session, clie
ret := _m.Called(_ca...)
if len(ret) == 0 {
panic("no return value specified for CreateThings")
panic("no return value specified for CreateClients")
}
var r0 []clients.Client
var r0 []things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, ...clients.Client) ([]clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, ...things.Client) ([]things.Client, error)); ok {
return rf(ctx, session, client...)
}
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, ...clients.Client) []clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, ...things.Client) []things.Client); ok {
r0 = rf(ctx, session, client...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]clients.Client)
r0 = ret.Get(0).([]things.Client)
}
}
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, ...clients.Client) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, ...things.Client) error); ok {
r1 = rf(ctx, session, client...)
} else {
r1 = ret.Error(1)
@@ -85,12 +84,12 @@ func (_m *Service) CreateThings(ctx context.Context, session authn.Session, clie
return r0, r1
}
// DeleteClient provides a mock function with given fields: ctx, session, id
func (_m *Service) DeleteClient(ctx context.Context, session authn.Session, id string) error {
// Delete provides a mock function with given fields: ctx, session, id
func (_m *Service) Delete(ctx context.Context, session authn.Session, id string) error {
ret := _m.Called(ctx, session, id)
if len(ret) == 0 {
panic("no return value specified for DeleteClient")
panic("no return value specified for Delete")
}
var r0 error
@@ -103,23 +102,23 @@ func (_m *Service) DeleteClient(ctx context.Context, session authn.Session, id s
return r0
}
// DisableClient provides a mock function with given fields: ctx, session, id
func (_m *Service) DisableClient(ctx context.Context, session authn.Session, id string) (clients.Client, error) {
// Disable provides a mock function with given fields: ctx, session, id
func (_m *Service) Disable(ctx context.Context, session authn.Session, id string) (things.Client, error) {
ret := _m.Called(ctx, session, id)
if len(ret) == 0 {
panic("no return value specified for DisableClient")
panic("no return value specified for Disable")
}
var r0 clients.Client
var r0 things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) (clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) (things.Client, error)); ok {
return rf(ctx, session, id)
}
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) things.Client); ok {
r0 = rf(ctx, session, id)
} else {
r0 = ret.Get(0).(clients.Client)
r0 = ret.Get(0).(things.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string) error); ok {
@@ -131,23 +130,23 @@ func (_m *Service) DisableClient(ctx context.Context, session authn.Session, id
return r0, r1
}
// EnableClient provides a mock function with given fields: ctx, session, id
func (_m *Service) EnableClient(ctx context.Context, session authn.Session, id string) (clients.Client, error) {
// Enable provides a mock function with given fields: ctx, session, id
func (_m *Service) Enable(ctx context.Context, session authn.Session, id string) (things.Client, error) {
ret := _m.Called(ctx, session, id)
if len(ret) == 0 {
panic("no return value specified for EnableClient")
panic("no return value specified for Enable")
}
var r0 clients.Client
var r0 things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) (clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) (things.Client, error)); ok {
return rf(ctx, session, id)
}
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) things.Client); ok {
r0 = rf(ctx, session, id)
} else {
r0 = ret.Get(0).(clients.Client)
r0 = ret.Get(0).(things.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string) error); ok {
@@ -188,25 +187,25 @@ func (_m *Service) Identify(ctx context.Context, key string) (string, error) {
}
// ListClients provides a mock function with given fields: ctx, session, reqUserID, pm
func (_m *Service) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm clients.Page) (clients.ClientsPage, error) {
func (_m *Service) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm things.Page) (things.ClientsPage, error) {
ret := _m.Called(ctx, session, reqUserID, pm)
if len(ret) == 0 {
panic("no return value specified for ListClients")
}
var r0 clients.ClientsPage
var r0 things.ClientsPage
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, clients.Page) (clients.ClientsPage, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, things.Page) (things.ClientsPage, error)); ok {
return rf(ctx, session, reqUserID, pm)
}
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, clients.Page) clients.ClientsPage); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, things.Page) things.ClientsPage); ok {
r0 = rf(ctx, session, reqUserID, pm)
} else {
r0 = ret.Get(0).(clients.ClientsPage)
r0 = ret.Get(0).(things.ClientsPage)
}
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, clients.Page) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, things.Page) error); ok {
r1 = rf(ctx, session, reqUserID, pm)
} else {
r1 = ret.Error(1)
@@ -216,25 +215,25 @@ func (_m *Service) ListClients(ctx context.Context, session authn.Session, reqUs
}
// ListClientsByGroup provides a mock function with given fields: ctx, session, groupID, pm
func (_m *Service) ListClientsByGroup(ctx context.Context, session authn.Session, groupID string, pm clients.Page) (clients.MembersPage, error) {
func (_m *Service) ListClientsByGroup(ctx context.Context, session authn.Session, groupID string, pm things.Page) (things.MembersPage, error) {
ret := _m.Called(ctx, session, groupID, pm)
if len(ret) == 0 {
panic("no return value specified for ListClientsByGroup")
}
var r0 clients.MembersPage
var r0 things.MembersPage
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, clients.Page) (clients.MembersPage, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, things.Page) (things.MembersPage, error)); ok {
return rf(ctx, session, groupID, pm)
}
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, clients.Page) clients.MembersPage); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, things.Page) things.MembersPage); ok {
r0 = rf(ctx, session, groupID, pm)
} else {
r0 = ret.Get(0).(clients.MembersPage)
r0 = ret.Get(0).(things.MembersPage)
}
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, clients.Page) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, things.Page) error); ok {
r1 = rf(ctx, session, groupID, pm)
} else {
r1 = ret.Error(1)
@@ -293,26 +292,26 @@ func (_m *Service) Unshare(ctx context.Context, session authn.Session, id string
return r0
}
// UpdateClient provides a mock function with given fields: ctx, session, client
func (_m *Service) UpdateClient(ctx context.Context, session authn.Session, client clients.Client) (clients.Client, error) {
// Update provides a mock function with given fields: ctx, session, client
func (_m *Service) Update(ctx context.Context, session authn.Session, client things.Client) (things.Client, error) {
ret := _m.Called(ctx, session, client)
if len(ret) == 0 {
panic("no return value specified for UpdateClient")
panic("no return value specified for Update")
}
var r0 clients.Client
var r0 things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, clients.Client) (clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, things.Client) (things.Client, error)); ok {
return rf(ctx, session, client)
}
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, clients.Client) clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, things.Client) things.Client); ok {
r0 = rf(ctx, session, client)
} else {
r0 = ret.Get(0).(clients.Client)
r0 = ret.Get(0).(things.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, clients.Client) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, things.Client) error); ok {
r1 = rf(ctx, session, client)
} else {
r1 = ret.Error(1)
@@ -321,23 +320,23 @@ func (_m *Service) UpdateClient(ctx context.Context, session authn.Session, clie
return r0, r1
}
// UpdateClientSecret provides a mock function with given fields: ctx, session, id, key
func (_m *Service) UpdateClientSecret(ctx context.Context, session authn.Session, id string, key string) (clients.Client, error) {
// UpdateSecret provides a mock function with given fields: ctx, session, id, key
func (_m *Service) UpdateSecret(ctx context.Context, session authn.Session, id string, key string) (things.Client, error) {
ret := _m.Called(ctx, session, id, key)
if len(ret) == 0 {
panic("no return value specified for UpdateClientSecret")
panic("no return value specified for UpdateSecret")
}
var r0 clients.Client
var r0 things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) (clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) (things.Client, error)); ok {
return rf(ctx, session, id, key)
}
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) things.Client); ok {
r0 = rf(ctx, session, id, key)
} else {
r0 = ret.Get(0).(clients.Client)
r0 = ret.Get(0).(things.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string, string) error); ok {
@@ -349,26 +348,26 @@ func (_m *Service) UpdateClientSecret(ctx context.Context, session authn.Session
return r0, r1
}
// UpdateClientTags provides a mock function with given fields: ctx, session, client
func (_m *Service) UpdateClientTags(ctx context.Context, session authn.Session, client clients.Client) (clients.Client, error) {
// UpdateTags provides a mock function with given fields: ctx, session, client
func (_m *Service) UpdateTags(ctx context.Context, session authn.Session, client things.Client) (things.Client, error) {
ret := _m.Called(ctx, session, client)
if len(ret) == 0 {
panic("no return value specified for UpdateClientTags")
panic("no return value specified for UpdateTags")
}
var r0 clients.Client
var r0 things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, clients.Client) (clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, things.Client) (things.Client, error)); ok {
return rf(ctx, session, client)
}
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, clients.Client) clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, things.Client) things.Client); ok {
r0 = rf(ctx, session, client)
} else {
r0 = ret.Get(0).(clients.Client)
r0 = ret.Get(0).(things.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, clients.Client) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, things.Client) error); ok {
r1 = rf(ctx, session, client)
} else {
r1 = ret.Error(1)
@@ -377,23 +376,23 @@ func (_m *Service) UpdateClientTags(ctx context.Context, session authn.Session,
return r0, r1
}
// ViewClient provides a mock function with given fields: ctx, session, id
func (_m *Service) ViewClient(ctx context.Context, session authn.Session, id string) (clients.Client, error) {
// View provides a mock function with given fields: ctx, session, id
func (_m *Service) View(ctx context.Context, session authn.Session, id string) (things.Client, error) {
ret := _m.Called(ctx, session, id)
if len(ret) == 0 {
panic("no return value specified for ViewClient")
panic("no return value specified for View")
}
var r0 clients.Client
var r0 things.Client
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) (clients.Client, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) (things.Client, error)); ok {
return rf(ctx, session, id)
}
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) clients.Client); ok {
if rf, ok := ret.Get(0).(func(context.Context, authn.Session, string) things.Client); ok {
r0 = rf(ctx, session, id)
} else {
r0 = ret.Get(0).(clients.Client)
r0 = ret.Get(0).(things.Client)
}
if rf, ok := ret.Get(1).(func(context.Context, authn.Session, string) error); ok {
@@ -405,12 +404,12 @@ func (_m *Service) ViewClient(ctx context.Context, session authn.Session, id str
return r0, r1
}
// ViewClientPerms provides a mock function with given fields: ctx, session, id
func (_m *Service) ViewClientPerms(ctx context.Context, session authn.Session, id string) ([]string, error) {
// ViewPerms provides a mock function with given fields: ctx, session, id
func (_m *Service) ViewPerms(ctx context.Context, session authn.Session, id string) ([]string, error) {
ret := _m.Called(ctx, session, id)
if len(ret) == 0 {
panic("no return value specified for ViewClientPerms")
panic("no return value specified for ViewPerms")
}
var r0 []string
+503 -52
View File
@@ -5,119 +5,570 @@ package postgres
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"strings"
"time"
mgclients "github.com/absmach/magistrala/pkg/clients"
pgclients "github.com/absmach/magistrala/pkg/clients/postgres"
"github.com/absmach/magistrala/internal/api"
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
"github.com/absmach/magistrala/pkg/groups"
"github.com/absmach/magistrala/pkg/postgres"
"github.com/absmach/magistrala/things"
"github.com/jackc/pgtype"
)
var _ mgclients.Repository = (*clientRepo)(nil)
type clientRepo struct {
pgclients.Repository
}
// Repository is the interface that wraps the basic methods for
// a client repository.
//
//go:generate mockery --name Repository --output=../mocks --filename repository.go --quiet --note "Copyright (c) Abstract Machines"
type Repository interface {
mgclients.Repository
// Save persists the client account. A non-nil error is returned to indicate
// operation failure.
Save(ctx context.Context, client ...mgclients.Client) ([]mgclients.Client, error)
// RetrieveBySecret retrieves a client based on the secret (key).
RetrieveBySecret(ctx context.Context, key string) (mgclients.Client, error)
Repository things.ClientRepository
}
// NewRepository instantiates a PostgreSQL
// implementation of Clients repository.
func NewRepository(db postgres.Database) Repository {
func NewRepository(db postgres.Database) things.Repository {
return &clientRepo{
Repository: pgclients.Repository{DB: db},
Repository: things.ClientRepository{DB: db},
}
}
func (repo clientRepo) Save(ctx context.Context, cs ...mgclients.Client) ([]mgclients.Client, error) {
tx, err := repo.DB.BeginTxx(ctx, nil)
func (repo *clientRepo) Save(ctx context.Context, th ...things.Client) ([]things.Client, error) {
tx, err := repo.Repository.DB.BeginTxx(ctx, nil)
if err != nil {
return []mgclients.Client{}, errors.Wrap(repoerr.ErrCreateEntity, err)
return []things.Client{}, errors.Wrap(repoerr.ErrCreateEntity, err)
}
var clients []mgclients.Client
var thingsList []things.Client
for _, cli := range cs {
for _, thi := range th {
q := `INSERT INTO clients (id, name, tags, domain_id, identity, secret, metadata, created_at, updated_at, updated_by, status)
VALUES (:id, :name, :tags, :domain_id, :identity, :secret, :metadata, :created_at, :updated_at, :updated_by, :status)
RETURNING id, name, tags, identity, secret, metadata, COALESCE(domain_id, '') AS domain_id, status, created_at, updated_at, updated_by`
dbcli, err := pgclients.ToDBClient(cli)
dbthi, err := ToDBClient(thi)
if err != nil {
return []mgclients.Client{}, errors.Wrap(repoerr.ErrCreateEntity, err)
return []things.Client{}, errors.Wrap(repoerr.ErrCreateEntity, err)
}
row, err := repo.DB.NamedQueryContext(ctx, q, dbcli)
row, err := repo.Repository.DB.NamedQueryContext(ctx, q, dbthi)
if err != nil {
if err := tx.Rollback(); err != nil {
return []mgclients.Client{}, postgres.HandleError(repoerr.ErrCreateEntity, err)
return []things.Client{}, postgres.HandleError(repoerr.ErrCreateEntity, err)
}
return []mgclients.Client{}, errors.Wrap(repoerr.ErrCreateEntity, err)
return []things.Client{}, errors.Wrap(repoerr.ErrCreateEntity, err)
}
defer row.Close()
if row.Next() {
dbcli = pgclients.DBClient{}
if err := row.StructScan(&dbcli); err != nil {
return []mgclients.Client{}, errors.Wrap(repoerr.ErrFailedOpDB, err)
dbthi = DBClient{}
if err := row.StructScan(&dbthi); err != nil {
return []things.Client{}, errors.Wrap(repoerr.ErrFailedOpDB, err)
}
client, err := pgclients.ToClient(dbcli)
thing, err := ToClient(dbthi)
if err != nil {
return []mgclients.Client{}, errors.Wrap(repoerr.ErrFailedOpDB, err)
return []things.Client{}, errors.Wrap(repoerr.ErrFailedOpDB, err)
}
clients = append(clients, client)
thingsList = append(thingsList, thing)
}
}
if err = tx.Commit(); err != nil {
return []mgclients.Client{}, errors.Wrap(repoerr.ErrCreateEntity, err)
return []things.Client{}, errors.Wrap(repoerr.ErrCreateEntity, err)
}
return clients, nil
return thingsList, nil
}
func (repo clientRepo) RetrieveBySecret(ctx context.Context, key string) (mgclients.Client, error) {
func (repo *clientRepo) RetrieveBySecret(ctx context.Context, key string) (things.Client, error) {
q := fmt.Sprintf(`SELECT id, name, tags, COALESCE(domain_id, '') AS domain_id, identity, secret, metadata, created_at, updated_at, updated_by, status
FROM clients
WHERE secret = :secret AND status = %d`, mgclients.EnabledStatus)
WHERE secret = :secret AND status = %d`, things.EnabledStatus)
dbc := pgclients.DBClient{
dbt := DBClient{
Secret: key,
}
rows, err := repo.DB.NamedQueryContext(ctx, q, dbc)
rows, err := repo.Repository.DB.NamedQueryContext(ctx, q, dbt)
if err != nil {
return mgclients.Client{}, postgres.HandleError(repoerr.ErrViewEntity, err)
return things.Client{}, postgres.HandleError(repoerr.ErrViewEntity, err)
}
defer rows.Close()
dbc = pgclients.DBClient{}
dbt = DBClient{}
if rows.Next() {
if err = rows.StructScan(&dbc); err != nil {
return mgclients.Client{}, postgres.HandleError(repoerr.ErrViewEntity, err)
if err = rows.StructScan(&dbt); err != nil {
return things.Client{}, postgres.HandleError(repoerr.ErrViewEntity, err)
}
client, err := pgclients.ToClient(dbc)
thing, err := ToClient(dbt)
if err != nil {
return mgclients.Client{}, errors.Wrap(repoerr.ErrFailedOpDB, err)
return things.Client{}, errors.Wrap(repoerr.ErrFailedOpDB, err)
}
return client, nil
return thing, nil
}
return mgclients.Client{}, repoerr.ErrNotFound
return things.Client{}, repoerr.ErrNotFound
}
func (repo *clientRepo) Update(ctx context.Context, thing things.Client) (things.Client, error) {
var query []string
var upq string
if thing.Name != "" {
query = append(query, "name = :name,")
}
if thing.Metadata != nil {
query = append(query, "metadata = :metadata,")
}
if len(query) > 0 {
upq = strings.Join(query, " ")
}
q := fmt.Sprintf(`UPDATE clients SET %s updated_at = :updated_at, updated_by = :updated_by
WHERE id = :id AND status = :status
RETURNING id, name, tags, identity, secret, metadata, COALESCE(domain_id, '') AS domain_id, status, created_at, updated_at, updated_by`,
upq)
thing.Status = things.EnabledStatus
return repo.update(ctx, thing, q)
}
func (repo *clientRepo) UpdateTags(ctx context.Context, thing things.Client) (things.Client, error) {
q := `UPDATE clients SET tags = :tags, updated_at = :updated_at, updated_by = :updated_by
WHERE id = :id AND status = :status
RETURNING id, name, tags, identity, metadata, COALESCE(domain_id, '') AS domain_id, status, created_at, updated_at, updated_by`
thing.Status = things.EnabledStatus
return repo.update(ctx, thing, q)
}
func (repo *clientRepo) UpdateIdentity(ctx context.Context, thing things.Client) (things.Client, error) {
q := `UPDATE clients SET identity = :identity, updated_at = :updated_at, updated_by = :updated_by
WHERE id = :id AND status = :status
RETURNING id, name, tags, identity, metadata, COALESCE(domain_id, '') AS domain_id, status, created_at, updated_at, updated_by`
thing.Status = things.EnabledStatus
return repo.update(ctx, thing, q)
}
func (repo *clientRepo) UpdateSecret(ctx context.Context, thing things.Client) (things.Client, error) {
q := `UPDATE clients SET secret = :secret, updated_at = :updated_at, updated_by = :updated_by
WHERE id = :id AND status = :status
RETURNING id, name, tags, identity, metadata, COALESCE(domain_id, '') AS domain_id, status, created_at, updated_at, updated_by`
thing.Status = things.EnabledStatus
return repo.update(ctx, thing, q)
}
func (repo *clientRepo) ChangeStatus(ctx context.Context, thing things.Client) (things.Client, error) {
q := `UPDATE clients SET status = :status, updated_at = :updated_at, updated_by = :updated_by
WHERE id = :id
RETURNING id, name, tags, identity, metadata, COALESCE(domain_id, '') AS domain_id, status, created_at, updated_at, updated_by`
return repo.update(ctx, thing, q)
}
func (repo *clientRepo) RetrieveByID(ctx context.Context, id string) (things.Client, error) {
q := `SELECT id, name, tags, COALESCE(domain_id, '') AS domain_id, identity, secret, metadata, created_at, updated_at, updated_by, status
FROM clients WHERE id = :id`
dbt := DBClient{
ID: id,
}
row, err := repo.Repository.DB.NamedQueryContext(ctx, q, dbt)
if err != nil {
return things.Client{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
defer row.Close()
dbt = DBClient{}
if row.Next() {
if err := row.StructScan(&dbt); err != nil {
return things.Client{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
return ToClient(dbt)
}
return things.Client{}, repoerr.ErrNotFound
}
func (repo *clientRepo) RetrieveAll(ctx context.Context, pm things.Page) (things.ClientsPage, error) {
query, err := PageQuery(pm)
if err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
query = applyOrdering(query, pm)
q := fmt.Sprintf(`SELECT c.id, c.name, c.tags, c.identity, c.metadata, COALESCE(c.domain_id, '') AS domain_id, c.status,
c.created_at, c.updated_at, COALESCE(c.updated_by, '') AS updated_by FROM clients c %s ORDER BY c.created_at LIMIT :limit OFFSET :offset;`, query)
dbPage, err := ToDBClientsPage(pm)
if err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrFailedToRetrieveAllGroups, err)
}
rows, err := repo.Repository.DB.NamedQueryContext(ctx, q, dbPage)
if err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrFailedToRetrieveAllGroups, err)
}
defer rows.Close()
var items []things.Client
for rows.Next() {
dbt := DBClient{}
if err := rows.StructScan(&dbt); err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
c, err := ToClient(dbt)
if err != nil {
return things.ClientsPage{}, err
}
items = append(items, c)
}
cq := fmt.Sprintf(`SELECT COUNT(*) FROM clients c %s;`, query)
total, err := postgres.Total(ctx, repo.Repository.DB, cq, dbPage)
if err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
page := things.ClientsPage{
Clients: items,
Page: things.Page{
Total: total,
Offset: pm.Offset,
Limit: pm.Limit,
},
}
return page, nil
}
func (repo *clientRepo) SearchClients(ctx context.Context, pm things.Page) (things.ClientsPage, error) {
query, err := PageQuery(pm)
if err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
tq := query
query = applyOrdering(query, pm)
q := fmt.Sprintf(`SELECT c.id, c.name, c.created_at, c.updated_at FROM clients c %s LIMIT :limit OFFSET :offset;`, query)
dbPage, err := ToDBClientsPage(pm)
if err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrFailedToRetrieveAllGroups, err)
}
rows, err := repo.Repository.DB.NamedQueryContext(ctx, q, dbPage)
if err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrFailedToRetrieveAllGroups, err)
}
defer rows.Close()
var items []things.Client
for rows.Next() {
dbt := DBClient{}
if err := rows.StructScan(&dbt); err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
c, err := ToClient(dbt)
if err != nil {
return things.ClientsPage{}, err
}
items = append(items, c)
}
cq := fmt.Sprintf(`SELECT COUNT(*) FROM clients c %s;`, tq)
total, err := postgres.Total(ctx, repo.Repository.DB, cq, dbPage)
if err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
page := things.ClientsPage{
Clients: items,
Page: things.Page{
Total: total,
Offset: pm.Offset,
Limit: pm.Limit,
},
}
return page, nil
}
func (repo *clientRepo) RetrieveAllByIDs(ctx context.Context, pm things.Page) (things.ClientsPage, error) {
if (len(pm.IDs) == 0) && (pm.Domain == "") {
return things.ClientsPage{
Page: things.Page{Total: pm.Total, Offset: pm.Offset, Limit: pm.Limit},
}, nil
}
query, err := PageQuery(pm)
if err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
query = applyOrdering(query, pm)
q := fmt.Sprintf(`SELECT c.id, c.name, c.tags, c.identity, c.metadata, COALESCE(c.domain_id, '') AS domain_id, c.status,
c.created_at, c.updated_at, COALESCE(c.updated_by, '') AS updated_by FROM clients c %s ORDER BY c.created_at LIMIT :limit OFFSET :offset;`, query)
dbPage, err := ToDBClientsPage(pm)
if err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrFailedToRetrieveAllGroups, err)
}
rows, err := repo.Repository.DB.NamedQueryContext(ctx, q, dbPage)
if err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrFailedToRetrieveAllGroups, err)
}
defer rows.Close()
var items []things.Client
for rows.Next() {
dbt := DBClient{}
if err := rows.StructScan(&dbt); err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
c, err := ToClient(dbt)
if err != nil {
return things.ClientsPage{}, err
}
items = append(items, c)
}
cq := fmt.Sprintf(`SELECT COUNT(*) FROM clients c %s;`, query)
total, err := postgres.Total(ctx, repo.Repository.DB, cq, dbPage)
if err != nil {
return things.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
page := things.ClientsPage{
Clients: items,
Page: things.Page{
Total: total,
Offset: pm.Offset,
Limit: pm.Limit,
},
}
return page, nil
}
func (repo *clientRepo) update(ctx context.Context, thing things.Client, query string) (things.Client, error) {
dbc, err := ToDBClient(thing)
if err != nil {
return things.Client{}, errors.Wrap(repoerr.ErrUpdateEntity, err)
}
row, err := repo.Repository.DB.NamedQueryContext(ctx, query, dbc)
if err != nil {
return things.Client{}, postgres.HandleError(repoerr.ErrUpdateEntity, err)
}
defer row.Close()
dbc = DBClient{}
if row.Next() {
if err := row.StructScan(&dbc); err != nil {
return things.Client{}, errors.Wrap(repoerr.ErrUpdateEntity, err)
}
return ToClient(dbc)
}
return things.Client{}, repoerr.ErrNotFound
}
func (repo *clientRepo) Delete(ctx context.Context, id string) error {
q := "DELETE FROM clients AS c WHERE c.id = $1 ;"
result, err := repo.Repository.DB.ExecContext(ctx, q, id)
if err != nil {
return postgres.HandleError(repoerr.ErrRemoveEntity, err)
}
if rows, _ := result.RowsAffected(); rows == 0 {
return repoerr.ErrNotFound
}
return nil
}
type DBClient struct {
ID string `db:"id"`
Name string `db:"name,omitempty"`
Tags pgtype.TextArray `db:"tags,omitempty"`
Identity string `db:"identity"`
Domain string `db:"domain_id"`
Secret string `db:"secret"`
Metadata []byte `db:"metadata,omitempty"`
CreatedAt time.Time `db:"created_at,omitempty"`
UpdatedAt sql.NullTime `db:"updated_at,omitempty"`
UpdatedBy *string `db:"updated_by,omitempty"`
Groups []groups.Group `db:"groups,omitempty"`
Status things.Status `db:"status,omitempty"`
}
func ToDBClient(c things.Client) (DBClient, error) {
data := []byte("{}")
if len(c.Metadata) > 0 {
b, err := json.Marshal(c.Metadata)
if err != nil {
return DBClient{}, errors.Wrap(repoerr.ErrMalformedEntity, err)
}
data = b
}
var tags pgtype.TextArray
if err := tags.Set(c.Tags); err != nil {
return DBClient{}, err
}
var updatedBy *string
if c.UpdatedBy != "" {
updatedBy = &c.UpdatedBy
}
var updatedAt sql.NullTime
if c.UpdatedAt != (time.Time{}) {
updatedAt = sql.NullTime{Time: c.UpdatedAt, Valid: true}
}
return DBClient{
ID: c.ID,
Name: c.Name,
Tags: tags,
Domain: c.Domain,
Identity: c.Credentials.Identity,
Secret: c.Credentials.Secret,
Metadata: data,
CreatedAt: c.CreatedAt,
UpdatedAt: updatedAt,
UpdatedBy: updatedBy,
Status: c.Status,
}, nil
}
func ToClient(t DBClient) (things.Client, error) {
var metadata things.Metadata
if t.Metadata != nil {
if err := json.Unmarshal([]byte(t.Metadata), &metadata); err != nil {
return things.Client{}, errors.Wrap(errors.ErrMalformedEntity, err)
}
}
var tags []string
for _, e := range t.Tags.Elements {
tags = append(tags, e.String)
}
var updatedBy string
if t.UpdatedBy != nil {
updatedBy = *t.UpdatedBy
}
var updatedAt time.Time
if t.UpdatedAt.Valid {
updatedAt = t.UpdatedAt.Time
}
thg := things.Client{
ID: t.ID,
Name: t.Name,
Tags: tags,
Domain: t.Domain,
Credentials: things.Credentials{
Identity: t.Identity,
Secret: t.Secret,
},
Metadata: metadata,
CreatedAt: t.CreatedAt,
UpdatedAt: updatedAt,
UpdatedBy: updatedBy,
Status: t.Status,
}
return thg, nil
}
func ToDBClientsPage(pm things.Page) (dbClientsPage, error) {
_, data, err := postgres.CreateMetadataQuery("", pm.Metadata)
if err != nil {
return dbClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
}
return dbClientsPage{
Name: pm.Name,
Identity: pm.Identity,
Id: pm.Id,
Metadata: data,
Domain: pm.Domain,
Total: pm.Total,
Offset: pm.Offset,
Limit: pm.Limit,
Status: pm.Status,
Tag: pm.Tag,
}, nil
}
type dbClientsPage struct {
Total uint64 `db:"total"`
Limit uint64 `db:"limit"`
Offset uint64 `db:"offset"`
Name string `db:"name"`
Id string `db:"id"`
Domain string `db:"domain_id"`
Identity string `db:"identity"`
Metadata []byte `db:"metadata"`
Tag string `db:"tag"`
Status things.Status `db:"status"`
GroupID string `db:"group_id"`
}
func PageQuery(pm things.Page) (string, error) {
mq, _, err := postgres.CreateMetadataQuery("", pm.Metadata)
if err != nil {
return "", errors.Wrap(errors.ErrMalformedEntity, err)
}
var query []string
if pm.Name != "" {
query = append(query, "name ILIKE '%' || :name || '%'")
}
if pm.Identity != "" {
query = append(query, "identity ILIKE '%' || :identity || '%'")
}
if pm.Id != "" {
query = append(query, "id ILIKE '%' || :id || '%'")
}
if pm.Tag != "" {
query = append(query, "EXISTS (SELECT 1 FROM unnest(tags) AS tag WHERE tag ILIKE '%' || :tag || '%')")
}
// If there are search params presents, use search and ignore other options.
// Always combine role with search params, so len(query) > 1.
if len(query) > 1 {
return fmt.Sprintf("WHERE %s", strings.Join(query, " AND ")), nil
}
if mq != "" {
query = append(query, mq)
}
if len(pm.IDs) != 0 {
query = append(query, fmt.Sprintf("id IN ('%s')", strings.Join(pm.IDs, "','")))
}
if pm.Status != things.AllStatus {
query = append(query, "c.status = :status")
}
if pm.Domain != "" {
query = append(query, "c.domain_id = :domain_id")
}
var emq string
if len(query) > 0 {
emq = fmt.Sprintf("WHERE %s", strings.Join(query, " AND "))
}
return emq, nil
}
func applyOrdering(emq string, pm things.Page) string {
switch pm.Order {
case "name", "identity", "created_at", "updated_at":
emq = fmt.Sprintf("%s ORDER BY %s", emq, pm.Order)
if pm.Dir == api.AscDir || pm.Dir == api.DescDir {
emq = fmt.Sprintf("%s %s", emq, pm.Dir)
}
}
return emq
}
+185 -123
View File
@@ -11,9 +11,9 @@ import (
"github.com/0x6flab/namegenerator"
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
"github.com/absmach/magistrala/things"
"github.com/absmach/magistrala/things/postgres"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -23,10 +23,10 @@ const maxNameSize = 1024
var (
invalidName = strings.Repeat("m", maxNameSize+10)
clientIdentity = "client-identity@example.com"
clientName = "client name"
thingIdentity = "thing-identity@example.com"
thingName = "thing name"
invalidDomainID = strings.Repeat("m", maxNameSize+10)
namesgen = namegenerator.NewGenerator()
namegen = namegenerator.NewGenerator()
)
func TestClientsSave(t *testing.T) {
@@ -41,254 +41,254 @@ func TestClientsSave(t *testing.T) {
secret := testsutil.GenerateUUID(t)
cases := []struct {
desc string
clients []clients.Client
err error
desc string
things []things.Client
err error
}{
{
desc: "add new client successfully",
clients: []clients.Client{
desc: "add new thing successfully",
things: []things.Client{
{
ID: uid,
Domain: domainID,
Name: clientName,
Credentials: clients.Credentials{
Identity: clientIdentity,
Name: thingName,
Credentials: things.Credentials{
Identity: thingIdentity,
Secret: secret,
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
},
err: nil,
},
{
desc: "add multiple clients successfully",
clients: []clients.Client{
desc: "add multiple things successfully",
things: []things.Client{
{
ID: testsutil.GenerateUUID(t),
Domain: testsutil.GenerateUUID(t),
Name: namesgen.Generate(),
Credentials: clients.Credentials{
Name: namegen.Generate(),
Credentials: things.Credentials{
Secret: testsutil.GenerateUUID(t),
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
{
ID: testsutil.GenerateUUID(t),
Domain: testsutil.GenerateUUID(t),
Name: namesgen.Generate(),
Credentials: clients.Credentials{
Name: namegen.Generate(),
Credentials: things.Credentials{
Secret: testsutil.GenerateUUID(t),
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
{
ID: testsutil.GenerateUUID(t),
Domain: testsutil.GenerateUUID(t),
Name: namesgen.Generate(),
Credentials: clients.Credentials{
Name: namegen.Generate(),
Credentials: things.Credentials{
Secret: testsutil.GenerateUUID(t),
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
},
err: nil,
},
{
desc: "add new client with duplicate secret",
clients: []clients.Client{
desc: "add new thing with duplicate secret",
things: []things.Client{
{
ID: testsutil.GenerateUUID(t),
Domain: domainID,
Name: namesgen.Generate(),
Credentials: clients.Credentials{
Identity: clientIdentity,
Name: namegen.Generate(),
Credentials: things.Credentials{
Identity: thingIdentity,
Secret: secret,
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
},
err: repoerr.ErrCreateEntity,
},
{
desc: "add multiple clients with one client having duplicate secret",
clients: []clients.Client{
desc: "add multiple things with one thing having duplicate secret",
things: []things.Client{
{
ID: testsutil.GenerateUUID(t),
Domain: testsutil.GenerateUUID(t),
Name: namesgen.Generate(),
Credentials: clients.Credentials{
Name: namegen.Generate(),
Credentials: things.Credentials{
Secret: testsutil.GenerateUUID(t),
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
{
ID: testsutil.GenerateUUID(t),
Domain: domainID,
Name: namesgen.Generate(),
Credentials: clients.Credentials{
Identity: clientIdentity,
Name: namegen.Generate(),
Credentials: things.Credentials{
Identity: thingIdentity,
Secret: secret,
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
},
err: repoerr.ErrCreateEntity,
},
{
desc: "add new client without domain id",
clients: []clients.Client{
desc: "add new thing without domain id",
things: []things.Client{
{
ID: testsutil.GenerateUUID(t),
Name: clientName,
Credentials: clients.Credentials{
Identity: "withoutdomain-client@example.com",
Name: thingName,
Credentials: things.Credentials{
Identity: "withoutdomain-thing@example.com",
Secret: testsutil.GenerateUUID(t),
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
},
err: nil,
},
{
desc: "add client with invalid client id",
clients: []clients.Client{
desc: "add thing with invalid thing id",
things: []things.Client{
{
ID: invalidName,
Domain: domainID,
Name: clientName,
Credentials: clients.Credentials{
Identity: "invalidid-client@example.com",
Name: thingName,
Credentials: things.Credentials{
Identity: "invalidid-thing@example.com",
Secret: testsutil.GenerateUUID(t),
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
},
err: repoerr.ErrCreateEntity,
},
{
desc: "add multiple clients with one client having invalid client id",
clients: []clients.Client{
desc: "add multiple things with one thing having invalid thing id",
things: []things.Client{
{
ID: testsutil.GenerateUUID(t),
Domain: testsutil.GenerateUUID(t),
Name: namesgen.Generate(),
Credentials: clients.Credentials{
Name: namegen.Generate(),
Credentials: things.Credentials{
Secret: testsutil.GenerateUUID(t),
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
{
ID: invalidName,
Domain: testsutil.GenerateUUID(t),
Name: namesgen.Generate(),
Credentials: clients.Credentials{
Name: namegen.Generate(),
Credentials: things.Credentials{
Secret: testsutil.GenerateUUID(t),
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
},
err: repoerr.ErrCreateEntity,
},
{
desc: "add client with invalid client name",
clients: []clients.Client{
desc: "add thing with invalid thing name",
things: []things.Client{
{
ID: testsutil.GenerateUUID(t),
Name: invalidName,
Domain: domainID,
Credentials: clients.Credentials{
Identity: "invalidname-client@example.com",
Credentials: things.Credentials{
Identity: "invalidname-thing@example.com",
Secret: testsutil.GenerateUUID(t),
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
},
err: repoerr.ErrCreateEntity,
},
{
desc: "add client with invalid client domain id",
clients: []clients.Client{
desc: "add thing with invalid thing domain id",
things: []things.Client{
{
ID: testsutil.GenerateUUID(t),
Domain: invalidDomainID,
Credentials: clients.Credentials{
Identity: "invaliddomainid-client@example.com",
Credentials: things.Credentials{
Identity: "invaliddomainid-thing@example.com",
Secret: testsutil.GenerateUUID(t),
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
},
err: repoerr.ErrCreateEntity,
},
{
desc: "add client with invalid client identity",
clients: []clients.Client{
desc: "add thing with invalid thing identity",
things: []things.Client{
{
ID: testsutil.GenerateUUID(t),
Name: clientName,
Credentials: clients.Credentials{
Name: thingName,
Credentials: things.Credentials{
Identity: invalidName,
Secret: testsutil.GenerateUUID(t),
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
},
},
err: repoerr.ErrCreateEntity,
},
{
desc: "add client with a missing client identity",
clients: []clients.Client{
desc: "add thing with a missing thing identity",
things: []things.Client{
{
ID: testsutil.GenerateUUID(t),
Domain: testsutil.GenerateUUID(t),
Name: "missing-client-identity",
Credentials: clients.Credentials{
Name: "missing-thing-identity",
Credentials: things.Credentials{
Identity: "",
Secret: testsutil.GenerateUUID(t),
},
Metadata: clients.Metadata{},
Metadata: things.Metadata{},
},
},
err: nil,
},
{
desc: "add client with a missing client secret",
clients: []clients.Client{
desc: "add thing with a missing thing secret",
things: []things.Client{
{
ID: testsutil.GenerateUUID(t),
Domain: testsutil.GenerateUUID(t),
Credentials: clients.Credentials{
Identity: "missing-client-secret@example.com",
Credentials: things.Credentials{
Identity: "missing-thing-secret@example.com",
Secret: "",
},
Metadata: clients.Metadata{},
Metadata: things.Metadata{},
},
},
err: nil,
},
{
desc: "add a client with invalid metadata",
clients: []clients.Client{
desc: "add a thing with invalid metadata",
things: []things.Client{
{
ID: testsutil.GenerateUUID(t),
Name: namesgen.Generate(),
Credentials: clients.Credentials{
Identity: fmt.Sprintf("%s@example.com", namesgen.Generate()),
Name: namegen.Generate(),
Credentials: things.Credentials{
Identity: fmt.Sprintf("%s@example.com", namegen.Generate()),
Secret: testsutil.GenerateUUID(t),
},
Metadata: map[string]interface{}{
@@ -300,60 +300,60 @@ func TestClientsSave(t *testing.T) {
},
}
for _, tc := range cases {
rClients, err := repo.Save(context.Background(), tc.clients...)
rThings, err := repo.Save(context.Background(), tc.things...)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
if err == nil {
for i := range rClients {
tc.clients[i].Credentials.Secret = rClients[i].Credentials.Secret
for i := range rThings {
tc.things[i].Credentials.Secret = rThings[i].Credentials.Secret
}
assert.Equal(t, tc.clients, rClients, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.clients, rClients))
assert.Equal(t, tc.things, rThings, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.things, rThings))
}
}
}
func TestClientsRetrieveBySecret(t *testing.T) {
func TestThingsRetrieveBySecret(t *testing.T) {
t.Cleanup(func() {
_, err := db.Exec("DELETE FROM clients")
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
})
repo := postgres.NewRepository(database)
client := clients.Client{
thing := things.Client{
ID: testsutil.GenerateUUID(t),
Name: clientName,
Credentials: clients.Credentials{
Identity: clientIdentity,
Name: thingName,
Credentials: things.Credentials{
Identity: thingIdentity,
Secret: testsutil.GenerateUUID(t),
},
Metadata: clients.Metadata{},
Status: clients.EnabledStatus,
Metadata: things.Metadata{},
Status: things.EnabledStatus,
}
_, err := repo.Save(context.Background(), client)
_, err := repo.Save(context.Background(), thing)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
cases := []struct {
desc string
secret string
response clients.Client
response things.Client
err error
}{
{
desc: "retrieve client by secret successfully",
secret: client.Credentials.Secret,
response: client,
desc: "retrieve thing by secret successfully",
secret: thing.Credentials.Secret,
response: thing,
err: nil,
},
{
desc: "retrieve client by invalid secret",
desc: "retrieve thing by invalid secret",
secret: "non-existent-secret",
response: clients.Client{},
response: things.Client{},
err: repoerr.ErrNotFound,
},
{
desc: "retrieve client by empty secret",
desc: "retrieve thing by empty secret",
secret: "",
response: clients.Client{},
response: things.Client{},
err: repoerr.ErrNotFound,
},
}
@@ -364,3 +364,65 @@ func TestClientsRetrieveBySecret(t *testing.T) {
assert.Equal(t, res, tc.response, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, res))
}
}
func TestRetrieveByID(t *testing.T) {
t.Cleanup(func() {
_, err := db.Exec("DELETE FROM clients")
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
})
repo := postgres.NewRepository(database)
thing := things.Client{
ID: testsutil.GenerateUUID(t),
Name: thingName,
Credentials: things.Credentials{
Identity: thingIdentity,
Secret: testsutil.GenerateUUID(t),
},
Metadata: things.Metadata{},
Status: things.EnabledStatus,
}
_, err := repo.Save(context.Background(), thing)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
cases := []struct {
desc string
id string
response things.Client
err error
}{
{
desc: "successfully",
id: thing.ID,
response: thing,
err: nil,
},
{
desc: "with invalid id",
id: testsutil.GenerateUUID(t),
response: things.Client{},
err: repoerr.ErrNotFound,
},
{
desc: "with empty id",
id: "",
response: things.Client{},
err: repoerr.ErrNotFound,
},
}
for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
cli, err := repo.RetrieveByID(context.Background(), c.id)
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("expected %s got %s\n", c.err, err))
if err == nil {
assert.Equal(t, thing.ID, cli.ID)
assert.Equal(t, thing.Name, cli.Name)
assert.Equal(t, thing.Metadata, cli.Metadata)
assert.Equal(t, thing.Credentials.Identity, cli.Credentials.Identity)
assert.Equal(t, thing.Credentials.Secret, cli.Credentials.Secret)
assert.Equal(t, thing.Status, cli.Status)
}
})
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package clients
package things
import (
"encoding/json"
@@ -1,40 +1,40 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package clients_test
package things_test
import (
"testing"
"github.com/absmach/magistrala/pkg/apiutil"
"github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/things"
"github.com/stretchr/testify/assert"
)
func TestRoleString(t *testing.T) {
cases := []struct {
desc string
role clients.Role
role things.Role
expected string
}{
{
desc: "User",
role: clients.UserRole,
role: things.UserRole,
expected: "user",
},
{
desc: "Admin",
role: clients.AdminRole,
role: things.AdminRole,
expected: "admin",
},
{
desc: "All",
role: clients.AllRole,
role: things.AllRole,
expected: "all",
},
{
desc: "Unknown",
role: clients.Role(100),
role: things.Role(100),
expected: "unknown",
},
}
@@ -51,38 +51,38 @@ func TestToRole(t *testing.T) {
cases := []struct {
desc string
role string
expected clients.Role
expected things.Role
err error
}{
{
desc: "User",
role: "user",
expected: clients.UserRole,
expected: things.UserRole,
err: nil,
},
{
desc: "Admin",
role: "admin",
expected: clients.AdminRole,
expected: things.AdminRole,
err: nil,
},
{
desc: "All",
role: "all",
expected: clients.AllRole,
expected: things.AllRole,
err: nil,
},
{
desc: "Unknown",
role: "unknown",
expected: clients.Role(0),
expected: things.Role(0),
err: apiutil.ErrInvalidRole,
},
}
for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
got, err := clients.ToRole(c.role)
got, err := things.ToRole(c.role)
assert.Equal(t, c.err, err, "ToRole() error = %v, expected %v", err, c.err)
assert.Equal(t, c.expected, got, "ToRole() = %v, expected %v", got, c.expected)
})
@@ -93,31 +93,31 @@ func TestRoleMarshalJSON(t *testing.T) {
cases := []struct {
desc string
expected []byte
role clients.Role
role things.Role
err error
}{
{
desc: "User",
expected: []byte(`"user"`),
role: clients.UserRole,
role: things.UserRole,
err: nil,
},
{
desc: "Admin",
expected: []byte(`"admin"`),
role: clients.AdminRole,
role: things.AdminRole,
err: nil,
},
{
desc: "All",
expected: []byte(`"all"`),
role: clients.AllRole,
role: things.AllRole,
err: nil,
},
{
desc: "Unknown",
expected: []byte(`"unknown"`),
role: clients.Role(100),
role: things.Role(100),
err: nil,
},
}
@@ -134,31 +134,31 @@ func TestRoleMarshalJSON(t *testing.T) {
func TestRoleUnmarshalJSON(t *testing.T) {
cases := []struct {
desc string
expected clients.Role
expected things.Role
role []byte
err error
}{
{
desc: "User",
expected: clients.UserRole,
expected: things.UserRole,
role: []byte(`"user"`),
err: nil,
},
{
desc: "Admin",
expected: clients.AdminRole,
expected: things.AdminRole,
role: []byte(`"admin"`),
err: nil,
},
{
desc: "All",
expected: clients.AllRole,
expected: things.AllRole,
role: []byte(`"all"`),
err: nil,
},
{
desc: "Unknown",
expected: clients.Role(0),
expected: things.Role(0),
role: []byte(`"unknown"`),
err: apiutil.ErrInvalidRole,
},
@@ -166,7 +166,7 @@ func TestRoleUnmarshalJSON(t *testing.T) {
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
var r clients.Role
var r things.Role
err := r.UnmarshalJSON(tc.role)
assert.Equal(t, tc.err, err, "UnmarshalJSON() error = %v, expected %v", err, tc.err)
assert.Equal(t, tc.expected, r, "UnmarshalJSON() = %v, expected %v", r, tc.expected)
+79 -84
View File
@@ -9,38 +9,33 @@ import (
"github.com/absmach/magistrala"
mgauth "github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/pkg/authn"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
mggroups "github.com/absmach/magistrala/pkg/groups"
"github.com/absmach/magistrala/pkg/policies"
"github.com/absmach/magistrala/things/postgres"
"golang.org/x/sync/errgroup"
)
type service struct {
evaluator policies.Evaluator
policysvc policies.Service
clients postgres.Repository
clients Repository
clientCache Cache
idProvider magistrala.IDProvider
grepo mggroups.Repository
}
// NewService returns a new Clients service implementation.
func NewService(policyEvaluator policies.Evaluator, policyService policies.Service, c postgres.Repository, grepo mggroups.Repository, tcache Cache, idp magistrala.IDProvider) Service {
// NewService returns a new Things service implementation.
func NewService(policyEvaluator policies.Evaluator, policyService policies.Service, c Repository, tcache Cache, idp magistrala.IDProvider) Service {
return service{
evaluator: policyEvaluator,
policysvc: policyService,
clients: c,
grepo: grepo,
clientCache: tcache,
idProvider: idp,
}
}
func (svc service) Authorize(ctx context.Context, req AuthzReq) (string, error) {
thingID, err := svc.Identify(ctx, req.ThingKey)
clientID, err := svc.Identify(ctx, req.ClientKey)
if err != nil {
return "", err
}
@@ -49,7 +44,7 @@ func (svc service) Authorize(ctx context.Context, req AuthzReq) (string, error)
SubjectType: policies.GroupType,
Subject: req.ChannelID,
ObjectType: policies.ThingType,
Object: thingID,
Object: clientID,
Permission: req.Permission,
}
err = svc.evaluator.CheckPolicy(ctx, r)
@@ -57,41 +52,41 @@ func (svc service) Authorize(ctx context.Context, req AuthzReq) (string, error)
return "", errors.Wrap(svcerr.ErrAuthorization, err)
}
return thingID, nil
return clientID, nil
}
func (svc service) CreateThings(ctx context.Context, session authn.Session, cls ...mgclients.Client) ([]mgclients.Client, error) {
var clients []mgclients.Client
for _, c := range cls {
func (svc service) CreateClients(ctx context.Context, session authn.Session, cli ...Client) ([]Client, error) {
var clients []Client
for _, c := range cli {
if c.ID == "" {
clientID, err := svc.idProvider.ID()
if err != nil {
return []mgclients.Client{}, err
return []Client{}, err
}
c.ID = clientID
}
if c.Credentials.Secret == "" {
key, err := svc.idProvider.ID()
if err != nil {
return []mgclients.Client{}, err
return []Client{}, err
}
c.Credentials.Secret = key
}
if c.Status != mgclients.DisabledStatus && c.Status != mgclients.EnabledStatus {
return []mgclients.Client{}, svcerr.ErrInvalidStatus
if c.Status != DisabledStatus && c.Status != EnabledStatus {
return []Client{}, svcerr.ErrInvalidStatus
}
c.Domain = session.DomainID
c.CreatedAt = time.Now()
clients = append(clients, c)
}
err := svc.addThingPolicies(ctx, session.DomainUserID, session.DomainID, clients)
err := svc.addClientPolicies(ctx, session.DomainUserID, session.DomainID, clients)
if err != nil {
return []mgclients.Client{}, err
return []Client{}, err
}
defer func() {
if err != nil {
if errRollback := svc.addThingPoliciesRollback(ctx, session.DomainUserID, session.DomainID, clients); errRollback != nil {
if errRollback := svc.addClientPoliciesRollback(ctx, session.DomainUserID, session.DomainID, clients); errRollback != nil {
err = errors.Wrap(errors.Wrap(errors.ErrRollbackTx, errRollback), err)
}
}
@@ -105,16 +100,16 @@ func (svc service) CreateThings(ctx context.Context, session authn.Session, cls
return saved, nil
}
func (svc service) ViewClient(ctx context.Context, session authn.Session, id string) (mgclients.Client, error) {
func (svc service) View(ctx context.Context, session authn.Session, id string) (Client, error) {
client, err := svc.clients.RetrieveByID(ctx, id)
if err != nil {
return mgclients.Client{}, errors.Wrap(svcerr.ErrViewEntity, err)
return Client{}, errors.Wrap(svcerr.ErrViewEntity, err)
}
return client, nil
}
func (svc service) ViewClientPerms(ctx context.Context, session authn.Session, id string) ([]string, error) {
permissions, err := svc.listUserThingPermission(ctx, session.DomainUserID, id)
func (svc service) ViewPerms(ctx context.Context, session authn.Session, id string) ([]string, error) {
permissions, err := svc.listUserClientPermission(ctx, session.DomainUserID, id)
if err != nil {
return nil, err
}
@@ -124,18 +119,18 @@ func (svc service) ViewClientPerms(ctx context.Context, session authn.Session, i
return permissions, nil
}
func (svc service) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm mgclients.Page) (mgclients.ClientsPage, error) {
func (svc service) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm Page) (ClientsPage, error) {
var ids []string
var err error
switch {
case (reqUserID != "" && reqUserID != session.UserID):
rtids, err := svc.listClientIDs(ctx, mgauth.EncodeDomainUserID(session.DomainID, reqUserID), pm.Permission)
if err != nil {
return mgclients.ClientsPage{}, errors.Wrap(svcerr.ErrNotFound, err)
return ClientsPage{}, errors.Wrap(svcerr.ErrNotFound, err)
}
ids, err = svc.filterAllowedThingIDs(ctx, session.DomainUserID, pm.Permission, rtids)
ids, err = svc.filterAllowedClientIDs(ctx, session.DomainUserID, pm.Permission, rtids)
if err != nil {
return mgclients.ClientsPage{}, errors.Wrap(svcerr.ErrNotFound, err)
return ClientsPage{}, errors.Wrap(svcerr.ErrNotFound, err)
}
default:
switch session.SuperAdmin {
@@ -144,18 +139,18 @@ func (svc service) ListClients(ctx context.Context, session authn.Session, reqUs
default:
ids, err = svc.listClientIDs(ctx, session.DomainUserID, pm.Permission)
if err != nil {
return mgclients.ClientsPage{}, errors.Wrap(svcerr.ErrNotFound, err)
return ClientsPage{}, errors.Wrap(svcerr.ErrNotFound, err)
}
}
}
if len(ids) == 0 && pm.Domain == "" {
return mgclients.ClientsPage{}, nil
return ClientsPage{}, nil
}
pm.IDs = ids
tp, err := svc.clients.SearchClients(ctx, pm)
if err != nil {
return mgclients.ClientsPage{}, errors.Wrap(svcerr.ErrViewEntity, err)
return ClientsPage{}, errors.Wrap(svcerr.ErrViewEntity, err)
}
if pm.ListPerms && len(tp.Clients) > 0 {
@@ -170,15 +165,15 @@ func (svc service) ListClients(ctx context.Context, session authn.Session, reqUs
}
if err := g.Wait(); err != nil {
return mgclients.ClientsPage{}, err
return ClientsPage{}, err
}
}
return tp, nil
}
// Experimental functions used for async calling of svc.listUserThingPermission. This might be helpful during listing of large number of entities.
func (svc service) retrievePermissions(ctx context.Context, userID string, client *mgclients.Client) error {
permissions, err := svc.listUserThingPermission(ctx, userID, client.ID)
// Experimental functions used for async calling of svc.listUserClientPermission. This might be helpful during listing of large number of entities.
func (svc service) retrievePermissions(ctx context.Context, userID string, client *Client) error {
permissions, err := svc.listUserClientPermission(ctx, userID, client.ID)
if err != nil {
return err
}
@@ -186,11 +181,11 @@ func (svc service) retrievePermissions(ctx context.Context, userID string, clien
return nil
}
func (svc service) listUserThingPermission(ctx context.Context, userID, thingID string) ([]string, error) {
func (svc service) listUserClientPermission(ctx context.Context, userID, clientID string) ([]string, error) {
permissions, err := svc.policysvc.ListPermissions(ctx, policies.Policy{
SubjectType: policies.UserType,
Subject: userID,
Object: thingID,
Object: clientID,
ObjectType: policies.ThingType,
}, []string{})
if err != nil {
@@ -212,7 +207,7 @@ func (svc service) listClientIDs(ctx context.Context, userID, permission string)
return tids.Policies, nil
}
func (svc service) filterAllowedThingIDs(ctx context.Context, userID, permission string, thingIDs []string) ([]string, error) {
func (svc service) filterAllowedClientIDs(ctx context.Context, userID, permission string, clientIDs []string) ([]string, error) {
var ids []string
tids, err := svc.policysvc.ListAllObjects(ctx, policies.Policy{
SubjectType: policies.UserType,
@@ -223,85 +218,85 @@ func (svc service) filterAllowedThingIDs(ctx context.Context, userID, permission
if err != nil {
return nil, errors.Wrap(svcerr.ErrNotFound, err)
}
for _, thingID := range thingIDs {
for _, clientID := range clientIDs {
for _, tid := range tids.Policies {
if thingID == tid {
ids = append(ids, thingID)
if clientID == tid {
ids = append(ids, clientID)
}
}
}
return ids, nil
}
func (svc service) UpdateClient(ctx context.Context, session authn.Session, cli mgclients.Client) (mgclients.Client, error) {
client := mgclients.Client{
ID: cli.ID,
Name: cli.Name,
Metadata: cli.Metadata,
func (svc service) Update(ctx context.Context, session authn.Session, thi Client) (Client, error) {
client := Client{
ID: thi.ID,
Name: thi.Name,
Metadata: thi.Metadata,
UpdatedAt: time.Now(),
UpdatedBy: session.UserID,
}
client, err := svc.clients.Update(ctx, client)
if err != nil {
return mgclients.Client{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
return Client{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
}
return client, nil
}
func (svc service) UpdateClientTags(ctx context.Context, session authn.Session, cli mgclients.Client) (mgclients.Client, error) {
client := mgclients.Client{
ID: cli.ID,
Tags: cli.Tags,
func (svc service) UpdateTags(ctx context.Context, session authn.Session, thi Client) (Client, error) {
client := Client{
ID: thi.ID,
Tags: thi.Tags,
UpdatedAt: time.Now(),
UpdatedBy: session.UserID,
}
client, err := svc.clients.UpdateTags(ctx, client)
if err != nil {
return mgclients.Client{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
return Client{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
}
return client, nil
}
func (svc service) UpdateClientSecret(ctx context.Context, session authn.Session, id, key string) (mgclients.Client, error) {
client := mgclients.Client{
func (svc service) UpdateSecret(ctx context.Context, session authn.Session, id, key string) (Client, error) {
client := Client{
ID: id,
Credentials: mgclients.Credentials{
Credentials: Credentials{
Secret: key,
},
UpdatedAt: time.Now(),
UpdatedBy: session.UserID,
Status: mgclients.EnabledStatus,
Status: EnabledStatus,
}
client, err := svc.clients.UpdateSecret(ctx, client)
if err != nil {
return mgclients.Client{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
return Client{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
}
return client, nil
}
func (svc service) EnableClient(ctx context.Context, session authn.Session, id string) (mgclients.Client, error) {
client := mgclients.Client{
func (svc service) Enable(ctx context.Context, session authn.Session, id string) (Client, error) {
client := Client{
ID: id,
Status: mgclients.EnabledStatus,
Status: EnabledStatus,
UpdatedAt: time.Now(),
}
client, err := svc.changeClientStatus(ctx, session, client)
if err != nil {
return mgclients.Client{}, errors.Wrap(mgclients.ErrEnableClient, err)
return Client{}, errors.Wrap(ErrEnableClient, err)
}
return client, nil
}
func (svc service) DisableClient(ctx context.Context, session authn.Session, id string) (mgclients.Client, error) {
client := mgclients.Client{
func (svc service) Disable(ctx context.Context, session authn.Session, id string) (Client, error) {
client := Client{
ID: id,
Status: mgclients.DisabledStatus,
Status: DisabledStatus,
UpdatedAt: time.Now(),
}
client, err := svc.changeClientStatus(ctx, session, client)
if err != nil {
return mgclients.Client{}, errors.Wrap(mgclients.ErrDisableClient, err)
return Client{}, errors.Wrap(ErrDisableClient, err)
}
if err := svc.clientCache.Remove(ctx, client.ID); err != nil {
@@ -347,7 +342,7 @@ func (svc service) Unshare(ctx context.Context, session authn.Session, id, relat
return nil
}
func (svc service) DeleteClient(ctx context.Context, session authn.Session, id string) error {
func (svc service) Delete(ctx context.Context, session authn.Session, id string) error {
if err := svc.clientCache.Remove(ctx, id); err != nil {
return errors.Wrap(svcerr.ErrRemoveEntity, err)
}
@@ -368,25 +363,25 @@ func (svc service) DeleteClient(ctx context.Context, session authn.Session, id s
return nil
}
func (svc service) changeClientStatus(ctx context.Context, session authn.Session, client mgclients.Client) (mgclients.Client, error) {
func (svc service) changeClientStatus(ctx context.Context, session authn.Session, client Client) (Client, error) {
dbClient, err := svc.clients.RetrieveByID(ctx, client.ID)
if err != nil {
return mgclients.Client{}, errors.Wrap(svcerr.ErrViewEntity, err)
return Client{}, errors.Wrap(svcerr.ErrViewEntity, err)
}
if dbClient.Status == client.Status {
return mgclients.Client{}, errors.ErrStatusAlreadyAssigned
return Client{}, errors.ErrStatusAlreadyAssigned
}
client.UpdatedBy = session.UserID
client, err = svc.clients.ChangeStatus(ctx, client)
if err != nil {
return mgclients.Client{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
return Client{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
}
return client, nil
}
func (svc service) ListClientsByGroup(ctx context.Context, session authn.Session, groupID string, pm mgclients.Page) (mgclients.MembersPage, error) {
func (svc service) ListClientsByGroup(ctx context.Context, session authn.Session, groupID string, pm Page) (MembersPage, error) {
tids, err := svc.policysvc.ListAllObjects(ctx, policies.Policy{
SubjectType: policies.GroupType,
Subject: groupID,
@@ -394,14 +389,14 @@ func (svc service) ListClientsByGroup(ctx context.Context, session authn.Session
ObjectType: policies.ThingType,
})
if err != nil {
return mgclients.MembersPage{}, errors.Wrap(svcerr.ErrNotFound, err)
return MembersPage{}, errors.Wrap(svcerr.ErrNotFound, err)
}
pm.IDs = tids.Policies
cp, err := svc.clients.RetrieveAllByIDs(ctx, pm)
if err != nil {
return mgclients.MembersPage{}, errors.Wrap(svcerr.ErrViewEntity, err)
return MembersPage{}, errors.Wrap(svcerr.ErrViewEntity, err)
}
if pm.ListPerms && len(cp.Clients) > 0 {
@@ -416,11 +411,11 @@ func (svc service) ListClientsByGroup(ctx context.Context, session authn.Session
}
if err := g.Wait(); err != nil {
return mgclients.MembersPage{}, err
return MembersPage{}, err
}
}
return mgclients.MembersPage{
return MembersPage{
Page: cp.Page,
Members: cp.Clients,
}, nil
@@ -443,9 +438,9 @@ func (svc service) Identify(ctx context.Context, key string) (string, error) {
return client.ID, nil
}
func (svc service) addThingPolicies(ctx context.Context, userID, domainID string, things []mgclients.Client) error {
func (svc service) addClientPolicies(ctx context.Context, userID, domainID string, clients []Client) error {
policyList := []policies.Policy{}
for _, thing := range things {
for _, client := range clients {
policyList = append(policyList, policies.Policy{
Domain: domainID,
SubjectType: policies.UserType,
@@ -453,7 +448,7 @@ func (svc service) addThingPolicies(ctx context.Context, userID, domainID string
Relation: policies.AdministratorRelation,
ObjectKind: policies.NewThingKind,
ObjectType: policies.ThingType,
Object: thing.ID,
Object: client.ID,
})
policyList = append(policyList, policies.Policy{
Domain: domainID,
@@ -461,7 +456,7 @@ func (svc service) addThingPolicies(ctx context.Context, userID, domainID string
Subject: domainID,
Relation: policies.DomainRelation,
ObjectType: policies.ThingType,
Object: thing.ID,
Object: client.ID,
})
}
if err := svc.policysvc.AddPolicies(ctx, policyList); err != nil {
@@ -471,9 +466,9 @@ func (svc service) addThingPolicies(ctx context.Context, userID, domainID string
return nil
}
func (svc service) addThingPoliciesRollback(ctx context.Context, userID, domainID string, things []mgclients.Client) error {
func (svc service) addClientPoliciesRollback(ctx context.Context, userID, domainID string, clients []Client) error {
policyList := []policies.Policy{}
for _, thing := range things {
for _, client := range clients {
policyList = append(policyList, policies.Policy{
Domain: domainID,
SubjectType: policies.UserType,
@@ -481,7 +476,7 @@ func (svc service) addThingPoliciesRollback(ctx context.Context, userID, domainI
Relation: policies.AdministratorRelation,
ObjectKind: policies.NewThingKind,
ObjectType: policies.ThingType,
Object: thing.ID,
Object: client.ID,
})
policyList = append(policyList, policies.Policy{
Domain: domainID,
@@ -489,7 +484,7 @@ func (svc service) addThingPoliciesRollback(ctx context.Context, userID, domainI
Subject: domainID,
Relation: policies.DomainRelation,
ObjectType: policies.ThingType,
Object: thing.ID,
Object: client.ID,
})
}
if err := svc.policysvc.DeletePolicies(ctx, policyList); err != nil {
+324 -327
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -1,7 +1,7 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package clients
package things
import (
"encoding/json"
@@ -54,7 +54,7 @@ func (s Status) String() string {
}
}
// ToStatus converts string value to a valid Client/Group status.
// ToStatus converts string value to a valid Client status.
func ToStatus(status string) (Status, error) {
switch status {
case "", Enabled:
@@ -69,7 +69,7 @@ func ToStatus(status string) (Status, error) {
return Status(0), svcerr.ErrInvalidStatus
}
// Custom Marshaller for Client/Groups.
// Custom Marshaller for Client.
func (s Status) MarshalJSON() ([]byte, error) {
return json.Marshal(s.String())
}
@@ -85,7 +85,7 @@ func (client Client) MarshalJSON() ([]byte, error) {
})
}
// Custom Unmarshaler for Client/Groups.
// Custom Unmarshaler for Client.
func (s *Status) UnmarshalJSON(data []byte) error {
str := strings.Trim(string(data), "\"")
val, err := ToStatus(str)
@@ -1,45 +1,45 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package clients_test
package things_test
import (
"testing"
"github.com/absmach/magistrala/pkg/clients"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/things"
"github.com/stretchr/testify/assert"
)
func TestStatusString(t *testing.T) {
cases := []struct {
desc string
status clients.Status
status things.Status
expected string
}{
{
desc: "Enabled",
status: clients.EnabledStatus,
status: things.EnabledStatus,
expected: "enabled",
},
{
desc: "Disabled",
status: clients.DisabledStatus,
status: things.DisabledStatus,
expected: "disabled",
},
{
desc: "Deleted",
status: clients.DeletedStatus,
status: things.DeletedStatus,
expected: "deleted",
},
{
desc: "All",
status: clients.AllStatus,
status: things.AllStatus,
expected: "all",
},
{
desc: "Unknown",
status: clients.Status(100),
status: things.Status(100),
expected: "unknown",
},
}
@@ -56,44 +56,44 @@ func TestToStatus(t *testing.T) {
cases := []struct {
desc string
status string
expetcted clients.Status
expetcted things.Status
err error
}{
{
desc: "Enabled",
status: "enabled",
expetcted: clients.EnabledStatus,
expetcted: things.EnabledStatus,
err: nil,
},
{
desc: "Disabled",
status: "disabled",
expetcted: clients.DisabledStatus,
expetcted: things.DisabledStatus,
err: nil,
},
{
desc: "Deleted",
status: "deleted",
expetcted: clients.DeletedStatus,
expetcted: things.DeletedStatus,
err: nil,
},
{
desc: "All",
status: "all",
expetcted: clients.AllStatus,
expetcted: things.AllStatus,
err: nil,
},
{
desc: "Unknown",
status: "unknown",
expetcted: clients.Status(0),
expetcted: things.Status(0),
err: svcerr.ErrInvalidStatus,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
got, err := clients.ToStatus(tc.status)
got, err := things.ToStatus(tc.status)
assert.Equal(t, tc.err, err, "ToStatus() error = %v, expected %v", err, tc.err)
assert.Equal(t, tc.expetcted, got, "ToStatus() = %v, expected %v", got, tc.expetcted)
})
@@ -104,37 +104,37 @@ func TestStatusMarshalJSON(t *testing.T) {
cases := []struct {
desc string
expected []byte
status clients.Status
status things.Status
err error
}{
{
desc: "Enabled",
expected: []byte(`"enabled"`),
status: clients.EnabledStatus,
status: things.EnabledStatus,
err: nil,
},
{
desc: "Disabled",
expected: []byte(`"disabled"`),
status: clients.DisabledStatus,
status: things.DisabledStatus,
err: nil,
},
{
desc: "Deleted",
expected: []byte(`"deleted"`),
status: clients.DeletedStatus,
status: things.DeletedStatus,
err: nil,
},
{
desc: "All",
expected: []byte(`"all"`),
status: clients.AllStatus,
status: things.AllStatus,
err: nil,
},
{
desc: "Unknown",
expected: []byte(`"unknown"`),
status: clients.Status(100),
status: things.Status(100),
err: nil,
},
}
@@ -151,37 +151,37 @@ func TestStatusMarshalJSON(t *testing.T) {
func TestStatusUnmarshalJSON(t *testing.T) {
cases := []struct {
desc string
expected clients.Status
expected things.Status
status []byte
err error
}{
{
desc: "Enabled",
expected: clients.EnabledStatus,
expected: things.EnabledStatus,
status: []byte(`"enabled"`),
err: nil,
},
{
desc: "Disabled",
expected: clients.DisabledStatus,
expected: things.DisabledStatus,
status: []byte(`"disabled"`),
err: nil,
},
{
desc: "Deleted",
expected: clients.DeletedStatus,
expected: things.DeletedStatus,
status: []byte(`"deleted"`),
err: nil,
},
{
desc: "All",
expected: clients.AllStatus,
expected: things.AllStatus,
status: []byte(`"all"`),
err: nil,
},
{
desc: "Unknown",
expected: clients.Status(0),
expected: things.Status(0),
status: []byte(`"unknown"`),
err: svcerr.ErrInvalidStatus,
},
@@ -189,7 +189,7 @@ func TestStatusUnmarshalJSON(t *testing.T) {
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
var s clients.Status
var s things.Status
err := s.UnmarshalJSON(tc.status)
assert.Equal(t, tc.err, err, "UnmarshalJSON() error = %v, expected %v", err, tc.err)
assert.Equal(t, tc.expected, s, "UnmarshalJSON() = %v, expected %v", s, tc.expected)
@@ -201,37 +201,37 @@ func TestUserMarshalJSON(t *testing.T) {
cases := []struct {
desc string
expected []byte
user clients.Client
user things.Client
err error
}{
{
desc: "Enabled",
expected: []byte(`{"id":"","credentials":{},"created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","status":"enabled"}`),
user: clients.Client{Status: clients.EnabledStatus},
user: things.Client{Status: things.EnabledStatus},
err: nil,
},
{
desc: "Disabled",
expected: []byte(`{"id":"","credentials":{},"created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","status":"disabled"}`),
user: clients.Client{Status: clients.DisabledStatus},
user: things.Client{Status: things.DisabledStatus},
err: nil,
},
{
desc: "Deleted",
expected: []byte(`{"id":"","credentials":{},"created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","status":"deleted"}`),
user: clients.Client{Status: clients.DeletedStatus},
user: things.Client{Status: things.DeletedStatus},
err: nil,
},
{
desc: "All",
expected: []byte(`{"id":"","credentials":{},"created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","status":"all"}`),
user: clients.Client{Status: clients.AllStatus},
user: things.Client{Status: things.AllStatus},
err: nil,
},
{
desc: "Unknown",
expected: []byte(`{"id":"","credentials":{},"created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","status":"unknown"}`),
user: clients.Client{Status: clients.Status(100)},
user: things.Client{Status: things.Status(100)},
err: nil,
},
}
-86
View File
@@ -1,86 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package things
import (
"context"
"github.com/absmach/magistrala/pkg/authn"
"github.com/absmach/magistrala/pkg/clients"
)
type AuthzReq struct {
ChannelID string
ThingID string
ThingKey string
Permission string
}
// Service specifies an API that must be fullfiled by the domain service
// implementation, and all of its decorators (e.g. logging & metrics).
//
//go:generate mockery --name Service --filename service.go --quiet --note "Copyright (c) Abstract Machines"
type Service interface {
// CreateThings creates new client. In case of the failed registration, a
// non-nil error value is returned.
CreateThings(ctx context.Context, session authn.Session, client ...clients.Client) ([]clients.Client, error)
// ViewClient retrieves client info for a given client ID and an authorized token.
ViewClient(ctx context.Context, session authn.Session, id string) (clients.Client, error)
// ViewClientPerms retrieves permissions on the client id for the given authorized token.
ViewClientPerms(ctx context.Context, session authn.Session, id string) ([]string, error)
// ListClients retrieves clients list for a valid auth token.
ListClients(ctx context.Context, session authn.Session, reqUserID string, pm clients.Page) (clients.ClientsPage, error)
// ListClientsByGroup retrieves data about subset of things that are
// connected or not connected to specified channel and belong to the user identified by
// the provided key.
ListClientsByGroup(ctx context.Context, session authn.Session, groupID string, pm clients.Page) (clients.MembersPage, error)
// UpdateClient updates the client's name and metadata.
UpdateClient(ctx context.Context, session authn.Session, client clients.Client) (clients.Client, error)
// UpdateClientTags updates the client's tags.
UpdateClientTags(ctx context.Context, session authn.Session, client clients.Client) (clients.Client, error)
// UpdateClientSecret updates the client's secret
UpdateClientSecret(ctx context.Context, session authn.Session, id, key string) (clients.Client, error)
// EnableClient logically enableds the client identified with the provided ID
EnableClient(ctx context.Context, session authn.Session, id string) (clients.Client, error)
// DisableClient logically disables the client identified with the provided ID
DisableClient(ctx context.Context, session authn.Session, id string) (clients.Client, error)
// Share add share policy to thing id with given relation for given user ids
Share(ctx context.Context, session authn.Session, id string, relation string, userids ...string) error
// Unshare remove share policy to thing id with given relation for given user ids
Unshare(ctx context.Context, session authn.Session, id string, relation string, userids ...string) error
// Identify returns thing ID for given thing key.
Identify(ctx context.Context, key string) (string, error)
// Authorize used for Things authorization.
Authorize(ctx context.Context, req AuthzReq) (string, error)
// DeleteClient deletes client with given ID.
DeleteClient(ctx context.Context, session authn.Session, id string) error
}
// Cache contains thing caching interface.
//
//go:generate mockery --name Cache --filename cache.go --quiet --note "Copyright (c) Abstract Machines"
type Cache interface {
// Save stores pair thing secret, thing id.
Save(ctx context.Context, thingSecret, thingID string) error
// ID returns thing ID for given thing secret.
ID(ctx context.Context, thingSecret string) (string, error)
// Removes thing from cache.
Remove(ctx context.Context, thingID string) error
}
+32 -33
View File
@@ -7,7 +7,6 @@ import (
"context"
"github.com/absmach/magistrala/pkg/authn"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/things"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
@@ -25,81 +24,81 @@ func New(svc things.Service, tracer trace.Tracer) things.Service {
return &tracingMiddleware{tracer, svc}
}
// CreateThings traces the "CreateThings" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) CreateThings(ctx context.Context, session authn.Session, clis ...mgclients.Client) ([]mgclients.Client, error) {
// CreateClients traces the "CreateClients" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) CreateClients(ctx context.Context, session authn.Session, cli ...things.Client) ([]things.Client, error) {
ctx, span := tm.tracer.Start(ctx, "svc_create_client")
defer span.End()
return tm.svc.CreateThings(ctx, session, clis...)
return tm.svc.CreateClients(ctx, session, cli...)
}
// ViewClient traces the "ViewClient" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) ViewClient(ctx context.Context, session authn.Session, id string) (mgclients.Client, error) {
// View traces the "View" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) View(ctx context.Context, session authn.Session, id string) (things.Client, error) {
ctx, span := tm.tracer.Start(ctx, "svc_view_client", trace.WithAttributes(attribute.String("id", id)))
defer span.End()
return tm.svc.ViewClient(ctx, session, id)
return tm.svc.View(ctx, session, id)
}
// ViewClientPerms traces the "ViewClientPerms" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) ViewClientPerms(ctx context.Context, session authn.Session, id string) ([]string, error) {
// ViewPerms traces the "ViewPerms" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) ViewPerms(ctx context.Context, session authn.Session, id string) ([]string, error) {
ctx, span := tm.tracer.Start(ctx, "svc_view_client_permissions", trace.WithAttributes(attribute.String("id", id)))
defer span.End()
return tm.svc.ViewClientPerms(ctx, session, id)
return tm.svc.ViewPerms(ctx, session, id)
}
// ListClients traces the "ListClients" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm mgclients.Page) (mgclients.ClientsPage, error) {
func (tm *tracingMiddleware) ListClients(ctx context.Context, session authn.Session, reqUserID string, pm things.Page) (things.ClientsPage, error) {
ctx, span := tm.tracer.Start(ctx, "svc_list_clients")
defer span.End()
return tm.svc.ListClients(ctx, session, reqUserID, pm)
}
// UpdateClient traces the "UpdateClient" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) UpdateClient(ctx context.Context, session authn.Session, cli mgclients.Client) (mgclients.Client, error) {
ctx, span := tm.tracer.Start(ctx, "svc_update_client_name_and_metadata", trace.WithAttributes(attribute.String("id", cli.ID)))
// Update traces the "Update" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) Update(ctx context.Context, session authn.Session, cli things.Client) (things.Client, error) {
ctx, span := tm.tracer.Start(ctx, "svc_update_client", trace.WithAttributes(attribute.String("id", cli.ID)))
defer span.End()
return tm.svc.UpdateClient(ctx, session, cli)
return tm.svc.Update(ctx, session, cli)
}
// UpdateClientTags traces the "UpdateClientTags" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) UpdateClientTags(ctx context.Context, session authn.Session, cli mgclients.Client) (mgclients.Client, error) {
// UpdateTags traces the "UpdateTags" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) UpdateTags(ctx context.Context, session authn.Session, cli things.Client) (things.Client, error) {
ctx, span := tm.tracer.Start(ctx, "svc_update_client_tags", trace.WithAttributes(
attribute.String("id", cli.ID),
attribute.StringSlice("tags", cli.Tags),
))
defer span.End()
return tm.svc.UpdateClientTags(ctx, session, cli)
return tm.svc.UpdateTags(ctx, session, cli)
}
// UpdateClientSecret traces the "UpdateClientSecret" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) UpdateClientSecret(ctx context.Context, session authn.Session, oldSecret, newSecret string) (mgclients.Client, error) {
// UpdateSecret traces the "UpdateSecret" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) UpdateSecret(ctx context.Context, session authn.Session, oldSecret, newSecret string) (things.Client, error) {
ctx, span := tm.tracer.Start(ctx, "svc_update_client_secret")
defer span.End()
return tm.svc.UpdateClientSecret(ctx, session, oldSecret, newSecret)
return tm.svc.UpdateSecret(ctx, session, oldSecret, newSecret)
}
// EnableClient traces the "EnableClient" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) EnableClient(ctx context.Context, session authn.Session, id string) (mgclients.Client, error) {
// Enable traces the "Enable" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) Enable(ctx context.Context, session authn.Session, id string) (things.Client, error) {
ctx, span := tm.tracer.Start(ctx, "svc_enable_client", trace.WithAttributes(attribute.String("id", id)))
defer span.End()
return tm.svc.EnableClient(ctx, session, id)
return tm.svc.Enable(ctx, session, id)
}
// DisableClient traces the "DisableClient" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) DisableClient(ctx context.Context, session authn.Session, id string) (mgclients.Client, error) {
// Disable traces the "Disable" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) Disable(ctx context.Context, session authn.Session, id string) (things.Client, error) {
ctx, span := tm.tracer.Start(ctx, "svc_disable_client", trace.WithAttributes(attribute.String("id", id)))
defer span.End()
return tm.svc.DisableClient(ctx, session, id)
return tm.svc.Disable(ctx, session, id)
}
// ListClientsByGroup traces the "ListClientsByGroup" operation of the wrapped policies.Service.
func (tm *tracingMiddleware) ListClientsByGroup(ctx context.Context, session authn.Session, groupID string, pm mgclients.Page) (mgclients.MembersPage, error) {
ctx, span := tm.tracer.Start(ctx, "svc_list_things_by_channel", trace.WithAttributes(attribute.String("groupID", groupID)))
func (tm *tracingMiddleware) ListClientsByGroup(ctx context.Context, session authn.Session, groupID string, pm things.Page) (things.MembersPage, error) {
ctx, span := tm.tracer.Start(ctx, "svc_list_clients_by_channel", trace.WithAttributes(attribute.String("groupID", groupID)))
defer span.End()
return tm.svc.ListClientsByGroup(ctx, session, groupID, pm)
@@ -115,7 +114,7 @@ func (tm *tracingMiddleware) Identify(ctx context.Context, key string) (string,
// Authorize traces the "Authorize" operation of the wrapped things.Service.
func (tm *tracingMiddleware) Authorize(ctx context.Context, req things.AuthzReq) (string, error) {
ctx, span := tm.tracer.Start(ctx, "connect", trace.WithAttributes(attribute.String("thingKey", req.ThingKey), attribute.String("channelID", req.ChannelID)))
ctx, span := tm.tracer.Start(ctx, "connect", trace.WithAttributes(attribute.String("thingKey", req.ClientKey), attribute.String("channelID", req.ChannelID)))
defer span.End()
return tm.svc.Authorize(ctx, req)
@@ -135,9 +134,9 @@ func (tm *tracingMiddleware) Unshare(ctx context.Context, session authn.Session,
return tm.svc.Unshare(ctx, session, id, relation, userids...)
}
// DeleteClient traces the "DeleteClient" operation of the wrapped things.Service.
func (tm *tracingMiddleware) DeleteClient(ctx context.Context, session authn.Session, id string) error {
// Delete traces the "Delete" operation of the wrapped things.Service.
func (tm *tracingMiddleware) Delete(ctx context.Context, session authn.Session, id string) error {
ctx, span := tm.tracer.Start(ctx, "delete_client", trace.WithAttributes(attribute.String("id", id)))
defer span.End()
return tm.svc.DeleteClient(ctx, session, id)
return tm.svc.Delete(ctx, session, id)
}
+1 -1
View File
@@ -249,7 +249,7 @@ func decodeViewProfile(_ context.Context, r *http.Request) (interface{}, error)
}
func decodeListUsers(_ context.Context, r *http.Request) (interface{}, error) {
s, err := apiutil.ReadStringQuery(r, api.StatusKey, api.DefClientStatus)
s, err := apiutil.ReadStringQuery(r, api.StatusKey, api.DefUserStatus)
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
+14
View File
@@ -0,0 +1,14 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package users
import "errors"
var (
// ErrEnableClient indicates error in enabling client.
ErrEnableClient = errors.New("failed to enable client")
// ErrDisableClient indicates error in disabling client.
ErrDisableClient = errors.New("failed to disable client")
)
+1 -2
View File
@@ -12,7 +12,6 @@ import (
"time"
"github.com/absmach/magistrala/internal/api"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
"github.com/absmach/magistrala/pkg/groups"
@@ -65,7 +64,7 @@ func (repo *userRepo) Save(ctx context.Context, c users.User) (users.User, error
func (repo *userRepo) CheckSuperAdmin(ctx context.Context, adminID string) error {
q := "SELECT 1 FROM users WHERE id = $1 AND role = $2"
rows, err := repo.Repository.DB.QueryContext(ctx, q, adminID, mgclients.AdminRole)
rows, err := repo.Repository.DB.QueryContext(ctx, q, adminID, users.AdminRole)
if err != nil {
return postgres.HandleError(repoerr.ErrViewEntity, err)
}
+1 -2
View File
@@ -11,7 +11,6 @@ import (
"github.com/absmach/magistrala"
mgauth "github.com/absmach/magistrala/auth"
"github.com/absmach/magistrala/pkg/authn"
mgclients "github.com/absmach/magistrala/pkg/clients"
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
@@ -408,7 +407,7 @@ func (svc service) Enable(ctx context.Context, session authn.Session, id string)
}
user, err := svc.changeUserStatus(ctx, session, u)
if err != nil {
return User{}, errors.Wrap(mgclients.ErrEnableClient, err)
return User{}, errors.Wrap(ErrEnableClient, err)
}
return user, nil