mirror of
https://github.com/absmach/magistrala.git
synced 2026-06-23 04:10:28 +00:00
SMQ-3108 - Add support for public and private metadata for users and clients (#3155)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
This commit is contained in:
@@ -161,17 +161,18 @@ type User struct {
|
||||
LastName string `protobuf:"bytes,3,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"`
|
||||
Tags []string `protobuf:"bytes,4,rep,name=tags,proto3" json:"tags,omitempty"`
|
||||
Metadata *structpb.Struct `protobuf:"bytes,5,opt,name=metadata,proto3" json:"metadata,omitempty"`
|
||||
Status uint32 `protobuf:"varint,6,opt,name=status,proto3" json:"status,omitempty"`
|
||||
Role uint32 `protobuf:"varint,7,opt,name=role,proto3" json:"role,omitempty"`
|
||||
ProfilePicture string `protobuf:"bytes,8,opt,name=profile_picture,json=profilePicture,proto3" json:"profile_picture,omitempty"`
|
||||
Username string `protobuf:"bytes,9,opt,name=username,proto3" json:"username,omitempty"`
|
||||
Email string `protobuf:"bytes,10,opt,name=email,proto3" json:"email,omitempty"`
|
||||
CreatedAt *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
|
||||
UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
|
||||
UpdatedBy string `protobuf:"bytes,13,opt,name=updated_by,json=updatedBy,proto3" json:"updated_by,omitempty"`
|
||||
VerifiedAt *timestamppb.Timestamp `protobuf:"bytes,14,opt,name=verified_at,json=verifiedAt,proto3" json:"verified_at,omitempty"`
|
||||
AuthProvider string `protobuf:"bytes,15,opt,name=auth_provider,json=authProvider,proto3" json:"auth_provider,omitempty"`
|
||||
Permissions []string `protobuf:"bytes,16,rep,name=permissions,proto3" json:"permissions,omitempty"`
|
||||
PublicMetadata *structpb.Struct `protobuf:"bytes,6,opt,name=public_metadata,json=publicMetadata,proto3" json:"public_metadata,omitempty"`
|
||||
Status uint32 `protobuf:"varint,7,opt,name=status,proto3" json:"status,omitempty"`
|
||||
Role uint32 `protobuf:"varint,8,opt,name=role,proto3" json:"role,omitempty"`
|
||||
ProfilePicture string `protobuf:"bytes,9,opt,name=profile_picture,json=profilePicture,proto3" json:"profile_picture,omitempty"`
|
||||
Username string `protobuf:"bytes,10,opt,name=username,proto3" json:"username,omitempty"`
|
||||
Email string `protobuf:"bytes,11,opt,name=email,proto3" json:"email,omitempty"`
|
||||
CreatedAt *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
|
||||
UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
|
||||
UpdatedBy string `protobuf:"bytes,14,opt,name=updated_by,json=updatedBy,proto3" json:"updated_by,omitempty"`
|
||||
VerifiedAt *timestamppb.Timestamp `protobuf:"bytes,15,opt,name=verified_at,json=verifiedAt,proto3" json:"verified_at,omitempty"`
|
||||
AuthProvider string `protobuf:"bytes,16,opt,name=auth_provider,json=authProvider,proto3" json:"auth_provider,omitempty"`
|
||||
Permissions []string `protobuf:"bytes,17,rep,name=permissions,proto3" json:"permissions,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -241,6 +242,13 @@ func (x *User) GetMetadata() *structpb.Struct {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *User) GetPublicMetadata() *structpb.Struct {
|
||||
if x != nil {
|
||||
return x.PublicMetadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *User) GetStatus() uint32 {
|
||||
if x != nil {
|
||||
return x.Status
|
||||
@@ -331,30 +339,31 @@ const file_users_v1_users_proto_rawDesc = "" +
|
||||
"\x05total\x18\x01 \x01(\x04R\x05total\x12\x14\n" +
|
||||
"\x05limit\x18\x02 \x01(\x04R\x05limit\x12\x16\n" +
|
||||
"\x06offset\x18\x03 \x01(\x04R\x06offset\x12$\n" +
|
||||
"\x05users\x18\x04 \x03(\v2\x0e.users.v1.UserR\x05users\"\xbb\x04\n" +
|
||||
"\x05users\x18\x04 \x03(\v2\x0e.users.v1.UserR\x05users\"\xfd\x04\n" +
|
||||
"\x04User\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\tR\x02id\x12\x1d\n" +
|
||||
"\n" +
|
||||
"first_name\x18\x02 \x01(\tR\tfirstName\x12\x1b\n" +
|
||||
"\tlast_name\x18\x03 \x01(\tR\blastName\x12\x12\n" +
|
||||
"\x04tags\x18\x04 \x03(\tR\x04tags\x123\n" +
|
||||
"\bmetadata\x18\x05 \x01(\v2\x17.google.protobuf.StructR\bmetadata\x12\x16\n" +
|
||||
"\x06status\x18\x06 \x01(\rR\x06status\x12\x12\n" +
|
||||
"\x04role\x18\a \x01(\rR\x04role\x12'\n" +
|
||||
"\x0fprofile_picture\x18\b \x01(\tR\x0eprofilePicture\x12\x1a\n" +
|
||||
"\busername\x18\t \x01(\tR\busername\x12\x14\n" +
|
||||
"\x05email\x18\n" +
|
||||
" \x01(\tR\x05email\x129\n" +
|
||||
"\bmetadata\x18\x05 \x01(\v2\x17.google.protobuf.StructR\bmetadata\x12@\n" +
|
||||
"\x0fpublic_metadata\x18\x06 \x01(\v2\x17.google.protobuf.StructR\x0epublicMetadata\x12\x16\n" +
|
||||
"\x06status\x18\a \x01(\rR\x06status\x12\x12\n" +
|
||||
"\x04role\x18\b \x01(\rR\x04role\x12'\n" +
|
||||
"\x0fprofile_picture\x18\t \x01(\tR\x0eprofilePicture\x12\x1a\n" +
|
||||
"\busername\x18\n" +
|
||||
" \x01(\tR\busername\x12\x14\n" +
|
||||
"\x05email\x18\v \x01(\tR\x05email\x129\n" +
|
||||
"\n" +
|
||||
"created_at\x18\v \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" +
|
||||
"created_at\x18\f \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" +
|
||||
"\n" +
|
||||
"updated_at\x18\f \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\x12\x1d\n" +
|
||||
"updated_at\x18\r \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\x12\x1d\n" +
|
||||
"\n" +
|
||||
"updated_by\x18\r \x01(\tR\tupdatedBy\x12;\n" +
|
||||
"\vverified_at\x18\x0e \x01(\v2\x1a.google.protobuf.TimestampR\n" +
|
||||
"updated_by\x18\x0e \x01(\tR\tupdatedBy\x12;\n" +
|
||||
"\vverified_at\x18\x0f \x01(\v2\x1a.google.protobuf.TimestampR\n" +
|
||||
"verifiedAt\x12#\n" +
|
||||
"\rauth_provider\x18\x0f \x01(\tR\fauthProvider\x12 \n" +
|
||||
"\vpermissions\x18\x10 \x03(\tR\vpermissions2Y\n" +
|
||||
"\rauth_provider\x18\x10 \x01(\tR\fauthProvider\x12 \n" +
|
||||
"\vpermissions\x18\x11 \x03(\tR\vpermissions2Y\n" +
|
||||
"\fUsersService\x12I\n" +
|
||||
"\rRetrieveUsers\x12\x1a.users.v1.RetrieveUsersReq\x1a\x1a.users.v1.RetrieveUsersRes\"\x00B.Z,github.com/absmach/supermq/api/grpc/users/v1b\x06proto3"
|
||||
|
||||
@@ -381,16 +390,17 @@ var file_users_v1_users_proto_goTypes = []any{
|
||||
var file_users_v1_users_proto_depIdxs = []int32{
|
||||
2, // 0: users.v1.RetrieveUsersRes.users:type_name -> users.v1.User
|
||||
3, // 1: users.v1.User.metadata:type_name -> google.protobuf.Struct
|
||||
4, // 2: users.v1.User.created_at:type_name -> google.protobuf.Timestamp
|
||||
4, // 3: users.v1.User.updated_at:type_name -> google.protobuf.Timestamp
|
||||
4, // 4: users.v1.User.verified_at:type_name -> google.protobuf.Timestamp
|
||||
0, // 5: users.v1.UsersService.RetrieveUsers:input_type -> users.v1.RetrieveUsersReq
|
||||
1, // 6: users.v1.UsersService.RetrieveUsers:output_type -> users.v1.RetrieveUsersRes
|
||||
6, // [6:7] is the sub-list for method output_type
|
||||
5, // [5:6] is the sub-list for method input_type
|
||||
5, // [5:5] is the sub-list for extension type_name
|
||||
5, // [5:5] is the sub-list for extension extendee
|
||||
0, // [0:5] is the sub-list for field type_name
|
||||
3, // 2: users.v1.User.public_metadata:type_name -> google.protobuf.Struct
|
||||
4, // 3: users.v1.User.created_at:type_name -> google.protobuf.Timestamp
|
||||
4, // 4: users.v1.User.updated_at:type_name -> google.protobuf.Timestamp
|
||||
4, // 5: users.v1.User.verified_at:type_name -> google.protobuf.Timestamp
|
||||
0, // 6: users.v1.UsersService.RetrieveUsers:input_type -> users.v1.RetrieveUsersReq
|
||||
1, // 7: users.v1.UsersService.RetrieveUsers:output_type -> users.v1.RetrieveUsersRes
|
||||
7, // [7:8] is the sub-list for method output_type
|
||||
6, // [6:7] is the sub-list for method input_type
|
||||
6, // [6:6] is the sub-list for extension type_name
|
||||
6, // [6:6] is the sub-list for extension extendee
|
||||
0, // [0:6] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_users_v1_users_proto_init() }
|
||||
|
||||
@@ -943,10 +943,14 @@ components:
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
minimum: 8
|
||||
description: Free-form account secret used for acquiring auth token(s).
|
||||
metadata:
|
||||
public_metadata:
|
||||
type: object
|
||||
example: { "model": "example" }
|
||||
description: Arbitrary, object-encoded client's data.
|
||||
metadata:
|
||||
type: object
|
||||
example: { "model": "example" }
|
||||
description: Arbitrary, object-encoded client's data, private to the client.
|
||||
status:
|
||||
type: string
|
||||
description: Client Status
|
||||
@@ -1001,10 +1005,14 @@ components:
|
||||
type: string
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
description: Client secret password.
|
||||
metadata:
|
||||
public_metadata:
|
||||
type: object
|
||||
example: { "model": "example" }
|
||||
description: Arbitrary, object-encoded client's data.
|
||||
metadata:
|
||||
type: object
|
||||
example: { "model": "example" }
|
||||
description: Arbitrary, object-encoded client's data, private to the client.
|
||||
status:
|
||||
type: string
|
||||
description: Client Status
|
||||
@@ -1058,10 +1066,14 @@ components:
|
||||
type: string
|
||||
example: ""
|
||||
description: Client secret password.
|
||||
metadata:
|
||||
public_metadata:
|
||||
type: object
|
||||
example: { "model": "example" }
|
||||
description: Arbitrary, object-encoded client's data.
|
||||
metadata:
|
||||
type: object
|
||||
example: { "model": "example" }
|
||||
description: Arbitrary, object-encoded client's data, private to the client.
|
||||
status:
|
||||
type: string
|
||||
description: Client Status
|
||||
@@ -1113,9 +1125,14 @@ components:
|
||||
metadata:
|
||||
type: object
|
||||
example: { "role": "general" }
|
||||
description: Arbitrary, object-encoded client's data.
|
||||
description: Arbitrary, object-encoded client's data, private to the client.
|
||||
public_metadata:
|
||||
type: object
|
||||
example: { "role": "general" }
|
||||
description: Arbitrary, object-encoded client's data.
|
||||
required:
|
||||
- name
|
||||
- public_metadata
|
||||
- metadata
|
||||
|
||||
ClientTags:
|
||||
|
||||
@@ -712,6 +712,10 @@ components:
|
||||
- username
|
||||
- secret
|
||||
metadata:
|
||||
type: object
|
||||
example: { "domain": "example.com" }
|
||||
description: Arbitrary, object-encoded user's data private to the user.
|
||||
public_metadata:
|
||||
type: object
|
||||
example: { "domain": "example.com" }
|
||||
description: Arbitrary, object-encoded user's data.
|
||||
@@ -768,6 +772,10 @@ components:
|
||||
example: john_doe
|
||||
description: User's username for example john_doe for Mr John Doe.
|
||||
metadata:
|
||||
type: object
|
||||
example: { "address": "example" }
|
||||
description: Arbitrary, object-encoded user's data private to the user.
|
||||
public_metadata:
|
||||
type: object
|
||||
example: { "address": "example" }
|
||||
description: Arbitrary, object-encoded user's data.
|
||||
@@ -1252,7 +1260,7 @@ components:
|
||||
|
||||
Metadata:
|
||||
name: metadata
|
||||
description: Metadata filter. Filtering is performed matching the parameter with metadata on top level. Parameter is json.
|
||||
description: Metadata filter. Filtering is performed matching the parameter with public metadata on top level. Parameter is json.
|
||||
in: query
|
||||
schema:
|
||||
type: object
|
||||
@@ -1334,7 +1342,7 @@ components:
|
||||
$ref: "#/components/schemas/UserReqObj"
|
||||
|
||||
UserUpdateReq:
|
||||
description: JSON-formated document describing the metadata and name of user to be update
|
||||
description: JSON-formated document describing the name, metadata and public_metadata of user to be update
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
|
||||
+93
-7
@@ -28,6 +28,8 @@ var (
|
||||
relation = "administrator"
|
||||
all = "all"
|
||||
conntype = `["publish","subscribe"]`
|
||||
|
||||
errEndJSONInput = errors.New("unexpected end of JSON input")
|
||||
)
|
||||
|
||||
var client = smqsdk.Client{
|
||||
@@ -295,6 +297,8 @@ func TestUpdateClientCmd(t *testing.T) {
|
||||
newTagsJson := "[\"tag1\", \"tag2\"]"
|
||||
newTagString := []string{"tag1", "tag2"}
|
||||
newNameandMeta := "{\"name\": \"clientName\", \"metadata\": {\"role\": \"general\"}}"
|
||||
newMetadata := "{\"metadata\": {\"role\": \"general\"}}"
|
||||
newPublicMeta := "{\"public_metadata\": {\"role\": \"general\"}}"
|
||||
newSecret := "secret"
|
||||
|
||||
cases := []struct {
|
||||
@@ -305,6 +309,26 @@ func TestUpdateClientCmd(t *testing.T) {
|
||||
client smqsdk.Client
|
||||
logType outputLog
|
||||
}{
|
||||
{
|
||||
desc: "update client name and public metadata successfully",
|
||||
args: []string{
|
||||
client.ID,
|
||||
updateCmd,
|
||||
newNameandMeta,
|
||||
domainID,
|
||||
token,
|
||||
},
|
||||
client: smqsdk.Client{
|
||||
Name: "clientName",
|
||||
PublicMetadata: map[string]any{
|
||||
"role": "general",
|
||||
},
|
||||
ID: client.ID,
|
||||
DomainID: client.DomainID,
|
||||
Status: client.Status,
|
||||
},
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "update client name and metadata successfully",
|
||||
args: []string{
|
||||
@@ -317,9 +341,7 @@ func TestUpdateClientCmd(t *testing.T) {
|
||||
client: smqsdk.Client{
|
||||
Name: "clientName",
|
||||
Metadata: map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"role": "general",
|
||||
},
|
||||
"role": "general",
|
||||
},
|
||||
ID: client.ID,
|
||||
DomainID: client.DomainID,
|
||||
@@ -327,6 +349,70 @@ func TestUpdateClientCmd(t *testing.T) {
|
||||
},
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "update client public metadata successfully",
|
||||
args: []string{
|
||||
client.ID,
|
||||
updateCmd,
|
||||
newPublicMeta,
|
||||
domainID,
|
||||
token,
|
||||
},
|
||||
client: smqsdk.Client{
|
||||
PublicMetadata: map[string]any{
|
||||
"role": "general",
|
||||
},
|
||||
ID: client.ID,
|
||||
DomainID: client.DomainID,
|
||||
Status: client.Status,
|
||||
},
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "update client metadata successfully",
|
||||
args: []string{
|
||||
client.ID,
|
||||
updateCmd,
|
||||
newMetadata,
|
||||
domainID,
|
||||
token,
|
||||
},
|
||||
client: smqsdk.Client{
|
||||
Metadata: map[string]any{
|
||||
"role": "general",
|
||||
},
|
||||
ID: client.ID,
|
||||
DomainID: client.DomainID,
|
||||
Status: client.Status,
|
||||
},
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "update client public metadata with invalid json",
|
||||
args: []string{
|
||||
client.ID,
|
||||
updateCmd,
|
||||
"{\"public_metadata\": {\"role\": \"general\"}",
|
||||
domainID,
|
||||
token,
|
||||
},
|
||||
sdkErr: errors.NewSDKError(errEndJSONInput),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errEndJSONInput),
|
||||
logType: errLog,
|
||||
},
|
||||
{
|
||||
desc: "update client metadata with invalid json",
|
||||
args: []string{
|
||||
client.ID,
|
||||
updateCmd,
|
||||
"{\"metadata\": {\"role\": \"general\"}",
|
||||
domainID,
|
||||
token,
|
||||
},
|
||||
sdkErr: errors.NewSDKError(errEndJSONInput),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errEndJSONInput),
|
||||
logType: errLog,
|
||||
},
|
||||
{
|
||||
desc: "update client name and metadata with invalid json",
|
||||
args: []string{
|
||||
@@ -336,8 +422,8 @@ func TestUpdateClientCmd(t *testing.T) {
|
||||
domainID,
|
||||
token,
|
||||
},
|
||||
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
|
||||
sdkErr: errors.NewSDKError(errEndJSONInput),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errEndJSONInput),
|
||||
logType: errLog,
|
||||
},
|
||||
{
|
||||
@@ -383,8 +469,8 @@ func TestUpdateClientCmd(t *testing.T) {
|
||||
token,
|
||||
},
|
||||
logType: errLog,
|
||||
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
|
||||
sdkErr: errors.NewSDKError(errEndJSONInput),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errEndJSONInput),
|
||||
},
|
||||
{
|
||||
desc: "update client tags with invalid client id",
|
||||
|
||||
+53
-5
@@ -519,6 +519,8 @@ func TestUpdateUserCmd(t *testing.T) {
|
||||
newRole := "administrator"
|
||||
newTagsJSON := "[\"tag1\", \"tag2\"]"
|
||||
newNameMetadataJSON := "{\"name\":\"new name\", \"metadata\":{\"key\": \"value\"}}"
|
||||
newMetadataJSON := "{\"metadata\":{\"key\": \"value\"}}"
|
||||
newPublicMetadataJSON := "{\"public_metadata\":{\"key\": \"value\"}}"
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -550,8 +552,8 @@ func TestUpdateUserCmd(t *testing.T) {
|
||||
"[\"tag1\", \"tag2\"",
|
||||
validToken,
|
||||
},
|
||||
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
|
||||
sdkErr: errors.NewSDKError(errEndJSONInput),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errEndJSONInput),
|
||||
logType: errLog,
|
||||
},
|
||||
{
|
||||
@@ -567,6 +569,52 @@ func TestUpdateUserCmd(t *testing.T) {
|
||||
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
|
||||
},
|
||||
{
|
||||
desc: "update user public metadata successfully",
|
||||
args: []string{
|
||||
userID,
|
||||
updateCmd,
|
||||
newPublicMetadataJSON,
|
||||
validToken,
|
||||
},
|
||||
logType: entityLog,
|
||||
user: user,
|
||||
},
|
||||
{
|
||||
desc: "update user public metadata with invalid json",
|
||||
args: []string{
|
||||
userID,
|
||||
updateCmd,
|
||||
"{\"public_metadata\":{\"key\": \"value\"",
|
||||
validToken,
|
||||
},
|
||||
sdkErr: errors.NewSDKError(errEndJSONInput),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errEndJSONInput),
|
||||
logType: errLog,
|
||||
},
|
||||
{
|
||||
desc: "update user metadata successfully",
|
||||
args: []string{
|
||||
userID,
|
||||
updateCmd,
|
||||
newMetadataJSON,
|
||||
validToken,
|
||||
},
|
||||
logType: entityLog,
|
||||
user: user,
|
||||
},
|
||||
{
|
||||
desc: "update user metadata with invalid json",
|
||||
args: []string{
|
||||
userID,
|
||||
updateCmd,
|
||||
"{\"metadata\":{\"key\": \"value\"",
|
||||
validToken,
|
||||
},
|
||||
sdkErr: errors.NewSDKError(errEndJSONInput),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errEndJSONInput),
|
||||
logType: errLog,
|
||||
},
|
||||
{
|
||||
desc: "update user email successfully",
|
||||
args: []string{
|
||||
@@ -623,8 +671,8 @@ func TestUpdateUserCmd(t *testing.T) {
|
||||
"{\"name\":\"new name\", \"metadata\":{\"key\": \"value\"}",
|
||||
validToken,
|
||||
},
|
||||
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
|
||||
sdkErr: errors.NewSDKError(errEndJSONInput),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errEndJSONInput),
|
||||
logType: errLog,
|
||||
},
|
||||
{
|
||||
@@ -708,7 +756,7 @@ Available update options:
|
||||
case len(tc.args) == 4: // Basic user update
|
||||
sdkCall = sdkMock.On("UpdateUser", mock.Anything, mgsdk.User{
|
||||
FirstName: "new name",
|
||||
Metadata: mgsdk.Metadata{
|
||||
PublicMetadata: mgsdk.Metadata{
|
||||
"key": "value",
|
||||
},
|
||||
}, tc.args[3]).Return(tc.user, tc.sdkErr)
|
||||
|
||||
@@ -143,9 +143,10 @@ func updateClientEndpoint(svc clients.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
cli := clients.Client{
|
||||
ID: req.id,
|
||||
Name: req.Name,
|
||||
Metadata: req.Metadata,
|
||||
ID: req.id,
|
||||
Name: req.Name,
|
||||
Metadata: req.Metadata,
|
||||
PublicMetadata: req.PublicMetadata,
|
||||
}
|
||||
client, err := svc.Update(ctx, session, cli)
|
||||
if err != nil {
|
||||
|
||||
@@ -32,16 +32,17 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
secret = "strongsecret"
|
||||
validCMetadata = clients.Metadata{"role": "client"}
|
||||
ID = testsutil.GenerateUUID(&testing.T{})
|
||||
client = clients.Client{
|
||||
ID: ID,
|
||||
Name: "clientname",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Credentials: clients.Credentials{Identity: "clientidentity", Secret: secret},
|
||||
Metadata: validCMetadata,
|
||||
Status: clients.EnabledStatus,
|
||||
secret = "strongsecret"
|
||||
validMetadata = clients.Metadata{"role": "client"}
|
||||
ID = testsutil.GenerateUUID(&testing.T{})
|
||||
client = clients.Client{
|
||||
ID: ID,
|
||||
Name: "clientname",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Credentials: clients.Credentials{Identity: "clientidentity", Secret: secret},
|
||||
PublicMetadata: validMetadata,
|
||||
Metadata: validMetadata,
|
||||
Status: clients.EnabledStatus,
|
||||
}
|
||||
validToken = "token"
|
||||
inValidToken = "invalid"
|
||||
@@ -170,7 +171,7 @@ func TestCreateClient(t *testing.T) {
|
||||
Identity: "user@example.com",
|
||||
Secret: "12345678",
|
||||
},
|
||||
Metadata: map[string]any{
|
||||
PublicMetadata: map[string]any{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -260,8 +261,9 @@ func TestCreateClients(t *testing.T) {
|
||||
Identity: fmt.Sprintf("%s@example.com", namesgen.Generate()),
|
||||
Secret: secret,
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: clients.Metadata{},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
}
|
||||
items = append(items, client)
|
||||
}
|
||||
@@ -362,7 +364,7 @@ func TestCreateClients(t *testing.T) {
|
||||
Identity: "user@example.com",
|
||||
Secret: "12345678",
|
||||
},
|
||||
Metadata: map[string]any{
|
||||
PublicMetadata: map[string]any{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -870,14 +872,14 @@ func TestUpdateClient(t *testing.T) {
|
||||
domainID: domainID,
|
||||
id: client.ID,
|
||||
authnRes: smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
|
||||
data: fmt.Sprintf(`{"name":"%s","tags":["%s"],"metadata":%s}`, newName, newTag, toJSON(newMetadata)),
|
||||
data: fmt.Sprintf(`{"name":"%s","tags":["%s"],"public_metadata":%s}`, newName, newTag, toJSON(newMetadata)),
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
clientResponse: clients.Client{
|
||||
ID: client.ID,
|
||||
Name: newName,
|
||||
Tags: []string{newTag},
|
||||
Metadata: newMetadata,
|
||||
ID: client.ID,
|
||||
Name: newName,
|
||||
Tags: []string{newTag},
|
||||
PublicMetadata: newMetadata,
|
||||
},
|
||||
status: http.StatusOK,
|
||||
|
||||
@@ -886,7 +888,7 @@ func TestUpdateClient(t *testing.T) {
|
||||
{
|
||||
desc: "update client with invalid token",
|
||||
id: client.ID,
|
||||
data: fmt.Sprintf(`{"name":"%s","tags":["%s"],"metadata":%s}`, newName, newTag, toJSON(newMetadata)),
|
||||
data: fmt.Sprintf(`{"name":"%s","tags":["%s"],"public_metadata":%s}`, newName, newTag, toJSON(newMetadata)),
|
||||
domainID: domainID,
|
||||
token: inValidToken,
|
||||
contentType: contentType,
|
||||
@@ -897,7 +899,7 @@ func TestUpdateClient(t *testing.T) {
|
||||
{
|
||||
desc: "update client with empty token",
|
||||
id: client.ID,
|
||||
data: fmt.Sprintf(`{"name":"%s","tags":["%s"],"metadata":%s}`, newName, newTag, toJSON(newMetadata)),
|
||||
data: fmt.Sprintf(`{"name":"%s","tags":["%s"],"public_metadata":%s}`, newName, newTag, toJSON(newMetadata)),
|
||||
domainID: domainID,
|
||||
token: "",
|
||||
contentType: contentType,
|
||||
@@ -907,7 +909,7 @@ func TestUpdateClient(t *testing.T) {
|
||||
{
|
||||
desc: "update client with invalid contentype",
|
||||
id: client.ID,
|
||||
data: fmt.Sprintf(`{"name":"%s","tags":["%s"],"metadata":%s}`, newName, newTag, toJSON(newMetadata)),
|
||||
data: fmt.Sprintf(`{"name":"%s","tags":["%s"],"public_metadata":%s}`, newName, newTag, toJSON(newMetadata)),
|
||||
domainID: domainID,
|
||||
token: validToken,
|
||||
authnRes: smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
|
||||
@@ -929,7 +931,7 @@ func TestUpdateClient(t *testing.T) {
|
||||
{
|
||||
desc: "update client with empty id",
|
||||
id: " ",
|
||||
data: fmt.Sprintf(`{"name":"%s","tags":["%s"],"metadata":%s}`, newName, newTag, toJSON(newMetadata)),
|
||||
data: fmt.Sprintf(`{"name":"%s","tags":["%s"],"public_metadata":%s}`, newName, newTag, toJSON(newMetadata)),
|
||||
domainID: domainID,
|
||||
token: validToken,
|
||||
authnRes: smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
|
||||
@@ -941,7 +943,7 @@ func TestUpdateClient(t *testing.T) {
|
||||
desc: "update client with name that is too long",
|
||||
id: client.ID,
|
||||
authnRes: smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID},
|
||||
data: fmt.Sprintf(`{"name":"%s","tags":["%s"],"metadata":%s}`, strings.Repeat("a", api.MaxNameSize+1), newTag, toJSON(newMetadata)),
|
||||
data: fmt.Sprintf(`{"name":"%s","tags":["%s"],"public_metadata":%s}`, strings.Repeat("a", api.MaxNameSize+1), newTag, toJSON(newMetadata)),
|
||||
domainID: domainID,
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
|
||||
@@ -112,10 +112,11 @@ func (req listMembersReq) validate() error {
|
||||
}
|
||||
|
||||
type updateClientReq struct {
|
||||
id string
|
||||
Name string `json:"name,omitempty"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
id string
|
||||
Name string `json:"name,omitempty"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
PublicMetadata map[string]any `json:"public_metadata,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
func (req updateClientReq) validate() error {
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
const (
|
||||
valid = "valid"
|
||||
invalid = "invalid"
|
||||
name = "client"
|
||||
)
|
||||
|
||||
var validID = testsutil.GenerateUUID(&testing.T{})
|
||||
|
||||
+13
-12
@@ -153,18 +153,19 @@ type Cache interface {
|
||||
// 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"`
|
||||
ParentGroup string `json:"parent_group_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
|
||||
Identity string `json:"identity,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Domain string `json:"domain_id,omitempty"`
|
||||
ParentGroup string `json:"parent_group_id,omitempty"`
|
||||
Credentials Credentials `json:"credentials,omitempty"`
|
||||
Metadata Metadata `json:"metadata,omitempty"`
|
||||
PublicMetadata Metadata `json:"public_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
|
||||
Identity string `json:"identity,omitempty"`
|
||||
// Extended
|
||||
ParentGroupPath string `json:"parent_group_path,omitempty"`
|
||||
RoleID string `json:"role_id,omitempty"`
|
||||
|
||||
@@ -70,6 +70,9 @@ func (cce createClientEvent) Encode() (map[string]any, error) {
|
||||
if cce.Metadata != nil {
|
||||
val["metadata"] = cce.Metadata
|
||||
}
|
||||
if cce.PublicMetadata != nil {
|
||||
val["public_metadata"] = cce.PublicMetadata
|
||||
}
|
||||
if cce.Credentials.Identity != "" {
|
||||
val["identity"] = cce.Credentials.Identity
|
||||
}
|
||||
@@ -110,6 +113,9 @@ func (uce updateClientEvent) Encode() (map[string]any, error) {
|
||||
if uce.Metadata != nil {
|
||||
val["metadata"] = uce.Metadata
|
||||
}
|
||||
if uce.PublicMetadata != nil {
|
||||
val["public_metadata"] = uce.PublicMetadata
|
||||
}
|
||||
if !uce.CreatedAt.IsZero() {
|
||||
val["created_at"] = uce.CreatedAt
|
||||
}
|
||||
@@ -174,6 +180,9 @@ func (vce viewClientEvent) Encode() (map[string]any, error) {
|
||||
if vce.Metadata != nil {
|
||||
val["metadata"] = vce.Metadata
|
||||
}
|
||||
if vce.PublicMetadata != nil {
|
||||
val["public_metadata"] = vce.PublicMetadata
|
||||
}
|
||||
if !vce.CreatedAt.IsZero() {
|
||||
val["created_at"] = vce.CreatedAt
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ func (lm *loggingMiddleware) Update(ctx context.Context, session authn.Session,
|
||||
slog.Group("client",
|
||||
slog.String("id", client.ID),
|
||||
slog.String("name", client.Name),
|
||||
slog.Any("metadata", client.Metadata),
|
||||
slog.Any("public_metadata", client.PublicMetadata),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
+58
-48
@@ -64,9 +64,9 @@ func (repo *clientRepo) Save(ctx context.Context, cls ...clients.Client) ([]clie
|
||||
}
|
||||
dbClients = append(dbClients, dbcli)
|
||||
}
|
||||
q := `INSERT INTO clients (id, name, tags, domain_id, parent_group_id, identity, secret, metadata, created_at, updated_at, updated_by, status)
|
||||
VALUES (:id, :name, :tags, :domain_id, :parent_group_id, :identity, :secret, :metadata, :created_at, :updated_at, :updated_by, :status)
|
||||
RETURNING id, name, tags, identity, secret, metadata, COALESCE(domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_id, status, created_at, updated_at, updated_by`
|
||||
q := `INSERT INTO clients (id, name, tags, domain_id, parent_group_id, identity, secret, metadata, public_metadata, created_at, updated_at, updated_by, status)
|
||||
VALUES (:id, :name, :tags, :domain_id, :parent_group_id, :identity, :secret, :metadata, :public_metadata, :created_at, :updated_at, :updated_by, :status)
|
||||
RETURNING id, name, tags, identity, secret, metadata, public_metadata, COALESCE(domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_id, status, created_at, updated_at, updated_by`
|
||||
|
||||
row, err := repo.DB.NamedQueryContext(ctx, q, dbClients)
|
||||
if err != nil {
|
||||
@@ -92,7 +92,7 @@ func (repo *clientRepo) Save(ctx context.Context, cls ...clients.Client) ([]clie
|
||||
}
|
||||
|
||||
func (repo *clientRepo) RetrieveBySecret(ctx context.Context, key, id string, prefix authn.AuthPrefix) (clients.Client, error) {
|
||||
q := fmt.Sprintf(`SELECT id, name, tags, COALESCE(domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_id, identity, secret, metadata, created_at, updated_at, updated_by, status
|
||||
q := fmt.Sprintf(`SELECT id, name, tags, COALESCE(domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_id, identity, secret, metadata, public_metadata, created_at, updated_at, updated_by, status
|
||||
FROM clients
|
||||
WHERE secret = :secret AND status = %d`, clients.EnabledStatus)
|
||||
switch prefix {
|
||||
@@ -139,6 +139,9 @@ func (repo *clientRepo) Update(ctx context.Context, client clients.Client) (clie
|
||||
if client.Name != "" {
|
||||
query = append(query, "name = :name,")
|
||||
}
|
||||
if client.PublicMetadata != nil {
|
||||
query = append(query, "public_metadata = :public_metadata,")
|
||||
}
|
||||
if client.Metadata != nil {
|
||||
query = append(query, "metadata = :metadata,")
|
||||
}
|
||||
@@ -148,7 +151,7 @@ func (repo *clientRepo) Update(ctx context.Context, client clients.Client) (clie
|
||||
|
||||
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, COALESCE(parent_group_id, '') AS parent_group_id, status, created_at, updated_at, updated_by`,
|
||||
RETURNING id, name, tags, identity, secret, metadata, public_metadata, COALESCE(domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_id, status, created_at, updated_at, updated_by`,
|
||||
upq)
|
||||
client.Status = clients.EnabledStatus
|
||||
return repo.update(ctx, client, q)
|
||||
@@ -157,7 +160,7 @@ func (repo *clientRepo) Update(ctx context.Context, client clients.Client) (clie
|
||||
func (repo *clientRepo) 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, COALESCE(parent_group_id, '') AS parent_group_id, status, created_at, updated_at, updated_by`
|
||||
RETURNING id, name, tags, identity, metadata, public_metadata, COALESCE(domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_id, status, created_at, updated_at, updated_by`
|
||||
client.Status = clients.EnabledStatus
|
||||
return repo.update(ctx, client, q)
|
||||
}
|
||||
@@ -165,7 +168,7 @@ func (repo *clientRepo) UpdateTags(ctx context.Context, client clients.Client) (
|
||||
func (repo *clientRepo) 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, COALESCE(parent_group_id, '') AS parent_group_id, created_at, updated_at, updated_by`
|
||||
RETURNING id, name, tags, identity, metadata, public_metadata, COALESCE(domain_id, '') AS domain_id, status, COALESCE(parent_group_id, '') AS parent_group_id, created_at, updated_at, updated_by`
|
||||
client.Status = clients.EnabledStatus
|
||||
return repo.update(ctx, client, q)
|
||||
}
|
||||
@@ -173,7 +176,7 @@ func (repo *clientRepo) UpdateIdentity(ctx context.Context, client clients.Clien
|
||||
func (repo *clientRepo) 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, COALESCE(parent_group_id, '') AS parent_group_id, status, created_at, updated_at, updated_by`
|
||||
RETURNING id, name, tags, identity, metadata, public_metadata, COALESCE(domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_id, status, created_at, updated_at, updated_by`
|
||||
client.Status = clients.EnabledStatus
|
||||
return repo.update(ctx, client, q)
|
||||
}
|
||||
@@ -181,7 +184,7 @@ func (repo *clientRepo) UpdateSecret(ctx context.Context, client clients.Client)
|
||||
func (repo *clientRepo) 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, COALESCE(parent_group_id, '') AS parent_group_id, status, created_at, updated_at, updated_by`
|
||||
RETURNING id, name, tags, identity, metadata, public_metadata, COALESCE(domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_id, status, created_at, updated_at, updated_by`
|
||||
|
||||
return repo.update(ctx, client, q)
|
||||
}
|
||||
@@ -353,7 +356,7 @@ func (repo *clientRepo) RetrieveByIDWithRoles(ctx context.Context, id, memberID
|
||||
COALESCE(c2.parent_group_id, '') AS parent_group_id,
|
||||
c2."identity",
|
||||
c2.secret,
|
||||
c2.metadata,
|
||||
c2.public_metadata,
|
||||
c2.created_at,
|
||||
c2.updated_at,
|
||||
c2.updated_by,
|
||||
@@ -386,7 +389,7 @@ func (repo *clientRepo) RetrieveByIDWithRoles(ctx context.Context, id, memberID
|
||||
}
|
||||
|
||||
func (repo *clientRepo) RetrieveByID(ctx context.Context, id string) (clients.Client, error) {
|
||||
q := `SELECT id, name, tags, COALESCE(domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_id, identity, secret, metadata, created_at, updated_at, updated_by, status
|
||||
q := `SELECT id, name, tags, COALESCE(domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_id, identity, secret, metadata, public_metadata, created_at, updated_at, updated_by, status
|
||||
FROM clients WHERE id = :id`
|
||||
|
||||
dbc := DBClient{
|
||||
@@ -446,7 +449,7 @@ func (repo *clientRepo) RetrieveAll(ctx context.Context, pm clients.Page) (clien
|
||||
c.name,
|
||||
c.tags,
|
||||
c.identity,
|
||||
c.metadata,
|
||||
c.public_metadata,
|
||||
COALESCE(c.domain_id, '') AS domain_id,
|
||||
COALESCE(parent_group_id, '') AS parent_group_id,
|
||||
COALESCE((SELECT path FROM groups WHERE id = c.parent_group_id), ''::::ltree) AS parent_group_path,
|
||||
@@ -561,7 +564,7 @@ func (repo *clientRepo) retrieveClients(ctx context.Context, domainID, userID st
|
||||
c.identity,
|
||||
c.secret,
|
||||
c.tags,
|
||||
c.metadata,
|
||||
c.public_metadata,
|
||||
c.created_at,
|
||||
c.updated_at,
|
||||
c.updated_by,
|
||||
@@ -622,7 +625,7 @@ func (repo *clientRepo) retrieveClients(ctx context.Context, domainID, userID st
|
||||
c.identity,
|
||||
c.secret,
|
||||
c.tags,
|
||||
c.metadata,
|
||||
c.public_metadata,
|
||||
c.created_at,
|
||||
c.updated_at,
|
||||
c.updated_by,
|
||||
@@ -667,7 +670,7 @@ func (repo *clientRepo) userClientBaseQuery(domainID, userID string) string {
|
||||
c.domain_id,
|
||||
c.parent_group_id,
|
||||
c.tags,
|
||||
c.metadata,
|
||||
c.public_metadata,
|
||||
c.identity,
|
||||
c.secret,
|
||||
c.created_at,
|
||||
@@ -832,7 +835,7 @@ func (repo *clientRepo) userClientBaseQuery(domainID, userID string) string {
|
||||
c.domain_id,
|
||||
c.parent_group_id,
|
||||
c.tags,
|
||||
c.metadata,
|
||||
c.public_metadata,
|
||||
c.identity,
|
||||
c.secret,
|
||||
c.created_at,
|
||||
@@ -864,7 +867,7 @@ func (repo *clientRepo) userClientBaseQuery(domainID, userID string) string {
|
||||
gc.domain_id,
|
||||
gc.parent_group_id,
|
||||
gc.tags,
|
||||
gc.metadata,
|
||||
gc.public_metadata,
|
||||
gc.identity,
|
||||
gc.secret,
|
||||
gc.created_at,
|
||||
@@ -889,7 +892,7 @@ func (repo *clientRepo) userClientBaseQuery(domainID, userID string) string {
|
||||
dc.domain_id,
|
||||
dc.parent_group_id,
|
||||
dc.tags,
|
||||
dc.metadata,
|
||||
dc.public_metadata,
|
||||
dc.identity,
|
||||
dc.secret,
|
||||
dc.created_at,
|
||||
@@ -940,7 +943,7 @@ func (repo *clientRepo) SearchClients(ctx context.Context, pm clients.Page) (cli
|
||||
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)
|
||||
q := fmt.Sprintf(`SELECT c.id, c.name, c.public_metadata, c.created_at, c.updated_at FROM clients c %s LIMIT :limit OFFSET :offset;`, query)
|
||||
|
||||
dbPage, err := ToDBClientsPage(pm)
|
||||
if err != nil {
|
||||
@@ -1036,6 +1039,7 @@ type DBClient struct {
|
||||
ParentGroup sql.NullString `db:"parent_group_id,omitempty"`
|
||||
Secret string `db:"secret"`
|
||||
Metadata []byte `db:"metadata,omitempty"`
|
||||
PublicMetadata []byte `db:"public_metadata,omitempty"`
|
||||
CreatedAt time.Time `db:"created_at,omitempty"`
|
||||
UpdatedAt sql.NullTime `db:"updated_at,omitempty"`
|
||||
UpdatedBy *string `db:"updated_by,omitempty"`
|
||||
@@ -1055,13 +1059,21 @@ type DBClient struct {
|
||||
}
|
||||
|
||||
func ToDBClient(c clients.Client) (DBClient, error) {
|
||||
data := []byte("{}")
|
||||
publicMetadata := []byte("{}")
|
||||
if len(c.PublicMetadata) > 0 {
|
||||
b, err := json.Marshal(c.PublicMetadata)
|
||||
if err != nil {
|
||||
return DBClient{}, errors.Wrap(repoerr.ErrMalformedEntity, err)
|
||||
}
|
||||
publicMetadata = b
|
||||
}
|
||||
metadata := []byte("{}")
|
||||
if len(c.Metadata) > 0 {
|
||||
b, err := json.Marshal(c.Metadata)
|
||||
if err != nil {
|
||||
return DBClient{}, errors.Wrap(repoerr.ErrMalformedEntity, err)
|
||||
}
|
||||
data = b
|
||||
metadata = b
|
||||
}
|
||||
var tags pgtype.TextArray
|
||||
if err := tags.Set(c.Tags); err != nil {
|
||||
@@ -1077,26 +1089,32 @@ func ToDBClient(c clients.Client) (DBClient, error) {
|
||||
}
|
||||
|
||||
return DBClient{
|
||||
ID: c.ID,
|
||||
Name: c.Name,
|
||||
Tags: tags,
|
||||
Domain: c.Domain,
|
||||
ParentGroup: toNullString(c.ParentGroup),
|
||||
Identity: c.Credentials.Identity,
|
||||
Secret: c.Credentials.Secret,
|
||||
Metadata: data,
|
||||
CreatedAt: c.CreatedAt,
|
||||
UpdatedAt: updatedAt,
|
||||
UpdatedBy: updatedBy,
|
||||
Status: c.Status,
|
||||
ID: c.ID,
|
||||
Name: c.Name,
|
||||
Tags: tags,
|
||||
Domain: c.Domain,
|
||||
ParentGroup: toNullString(c.ParentGroup),
|
||||
Identity: c.Credentials.Identity,
|
||||
Secret: c.Credentials.Secret,
|
||||
Metadata: metadata,
|
||||
PublicMetadata: publicMetadata,
|
||||
CreatedAt: c.CreatedAt,
|
||||
UpdatedAt: updatedAt,
|
||||
UpdatedBy: updatedBy,
|
||||
Status: c.Status,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ToClient(t DBClient) (clients.Client, error) {
|
||||
var metadata clients.Metadata
|
||||
var publicMetadata, metadata clients.Metadata
|
||||
if t.PublicMetadata != nil {
|
||||
if err := json.Unmarshal([]byte(t.PublicMetadata), &publicMetadata); err != nil {
|
||||
return clients.Client{}, errors.Wrap(repoerr.ErrMalformedEntity, err)
|
||||
}
|
||||
}
|
||||
if t.Metadata != nil {
|
||||
if err := json.Unmarshal(t.Metadata, &metadata); err != nil {
|
||||
return clients.Client{}, errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
if err := json.Unmarshal([]byte(t.Metadata), &metadata); err != nil {
|
||||
return clients.Client{}, errors.Wrap(repoerr.ErrMalformedEntity, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1142,6 +1160,7 @@ func ToClient(t DBClient) (clients.Client, error) {
|
||||
Secret: t.Secret,
|
||||
},
|
||||
Metadata: metadata,
|
||||
PublicMetadata: publicMetadata,
|
||||
CreatedAt: t.CreatedAt.UTC(),
|
||||
UpdatedAt: updatedAt,
|
||||
UpdatedBy: updatedBy,
|
||||
@@ -1206,11 +1225,6 @@ type dbClientsPage struct {
|
||||
}
|
||||
|
||||
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, "c.name ILIKE '%' || :name || '%'")
|
||||
@@ -1225,10 +1239,6 @@ func PageQuery(pm clients.Page) (string, error) {
|
||||
query = append(query, "EXISTS (SELECT 1 FROM unnest(tags) AS tag WHERE tag ILIKE '%' || :tag || '%')")
|
||||
}
|
||||
|
||||
if mq != "" {
|
||||
query = append(query, mq)
|
||||
}
|
||||
|
||||
if len(pm.IDs) != 0 {
|
||||
query = append(query, fmt.Sprintf("c.id IN ('%s')", strings.Join(pm.IDs, "','")))
|
||||
}
|
||||
@@ -1268,7 +1278,7 @@ func PageQuery(pm clients.Page) (string, error) {
|
||||
query = append(query, "c.actions @> :actions")
|
||||
}
|
||||
if len(pm.Metadata) > 0 {
|
||||
query = append(query, "c.metadata @> :metadata")
|
||||
query = append(query, "c.public_metadata @> :metadata")
|
||||
}
|
||||
|
||||
var emq string
|
||||
@@ -1333,7 +1343,7 @@ func (repo *clientRepo) RetrieveByIds(ctx context.Context, ids []string) (client
|
||||
return clients.ClientsPage{}, errors.Wrap(repoerr.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
q := fmt.Sprintf(`SELECT c.id, c.name, c.tags, c.identity, c.metadata, COALESCE(c.domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_id, c.status,
|
||||
q := fmt.Sprintf(`SELECT c.id, c.name, c.tags, c.identity, c.public_metadata, COALESCE(c.domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_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`, query)
|
||||
|
||||
dbPage, err := ToDBClientsPage(pm)
|
||||
@@ -1498,7 +1508,7 @@ func (repo *clientRepo) RemoveClientConnections(ctx context.Context, clientID st
|
||||
}
|
||||
|
||||
func (repo *clientRepo) RetrieveParentGroupClients(ctx context.Context, parentGroupID string) ([]clients.Client, error) {
|
||||
query := `SELECT c.id, c.name, c.tags, c.metadata, COALESCE(c.domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_id, c.status,
|
||||
query := `SELECT c.id, c.name, c.tags, c.public_metadata, COALESCE(c.domain_id, '') AS domain_id, COALESCE(parent_group_id, '') AS parent_group_id, c.status,
|
||||
c.created_at, c.updated_at, COALESCE(c.updated_by, '') AS updated_by FROM clients c WHERE c.parent_group_id = :parent_group_id ;`
|
||||
|
||||
rows, err := repo.DB.NamedQueryContext(ctx, query, DBClient{ParentGroup: toNullString(parentGroupID)})
|
||||
|
||||
@@ -44,12 +44,13 @@ var (
|
||||
namegen = namegenerator.NewGenerator()
|
||||
validTimestamp = time.Now().UTC().Truncate(time.Millisecond)
|
||||
validClient = clients.Client{
|
||||
ID: testsutil.GenerateUUID(&testing.T{}),
|
||||
Domain: testsutil.GenerateUUID(&testing.T{}),
|
||||
Name: namegen.Generate(),
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
|
||||
Status: clients.EnabledStatus,
|
||||
ID: testsutil.GenerateUUID(&testing.T{}),
|
||||
Domain: testsutil.GenerateUUID(&testing.T{}),
|
||||
Name: namegen.Generate(),
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
|
||||
Status: clients.EnabledStatus,
|
||||
}
|
||||
invalidID = strings.Repeat("a", 37)
|
||||
directAccess = "direct"
|
||||
@@ -134,8 +135,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Identity: clientIdentity,
|
||||
Secret: secret,
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
@@ -150,8 +152,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Credentials: clients.Credentials{
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
{
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
@@ -160,8 +163,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Credentials: clients.Credentials{
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
{
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
@@ -170,8 +174,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Credentials: clients.Credentials{
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
@@ -187,8 +192,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Identity: clientIdentity,
|
||||
Secret: secret,
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
},
|
||||
err: errClientSecretNotAvailable,
|
||||
@@ -203,8 +209,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Credentials: clients.Credentials{
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
{
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
@@ -214,8 +221,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Identity: clientIdentity,
|
||||
Secret: secret,
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
},
|
||||
err: errClientSecretNotAvailable,
|
||||
@@ -230,8 +238,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Identity: "withoutdomain-client@example.com",
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
@@ -247,8 +256,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Identity: "invalidid-client@example.com",
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
},
|
||||
err: repoerr.ErrCreateEntity,
|
||||
@@ -263,8 +273,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Credentials: clients.Credentials{
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
{
|
||||
ID: invalidName,
|
||||
@@ -273,8 +284,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Credentials: clients.Credentials{
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
},
|
||||
err: repoerr.ErrCreateEntity,
|
||||
@@ -290,8 +302,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Identity: "invalidname-client@example.com",
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
},
|
||||
err: repoerr.ErrCreateEntity,
|
||||
@@ -306,8 +319,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Identity: "invaliddomainid-client@example.com",
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
},
|
||||
err: repoerr.ErrCreateEntity,
|
||||
@@ -322,8 +336,9 @@ func TestClientsSave(t *testing.T) {
|
||||
Identity: invalidName,
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
},
|
||||
err: repoerr.ErrCreateEntity,
|
||||
@@ -339,7 +354,8 @@ func TestClientsSave(t *testing.T) {
|
||||
Identity: "",
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
@@ -354,11 +370,29 @@ func TestClientsSave(t *testing.T) {
|
||||
Identity: "missing-client-secret@example.com",
|
||||
Secret: "",
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "add a client with invalid public metadata",
|
||||
clients: []clients.Client{
|
||||
{
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Name: namegen.Generate(),
|
||||
Credentials: clients.Credentials{
|
||||
Identity: fmt.Sprintf("%s@example.com", namegen.Generate()),
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
PublicMetadata: map[string]any{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
},
|
||||
err: errors.ErrMalformedEntity,
|
||||
},
|
||||
{
|
||||
desc: "add a client with invalid metadata",
|
||||
clients: []clients.Client{
|
||||
@@ -369,7 +403,7 @@ func TestClientsSave(t *testing.T) {
|
||||
Identity: fmt.Sprintf("%s@example.com", namegen.Generate()),
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: map[string]any{
|
||||
PublicMetadata: map[string]any{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -380,12 +414,13 @@ func TestClientsSave(t *testing.T) {
|
||||
desc: "add client with duplicate name",
|
||||
clients: []clients.Client{
|
||||
{
|
||||
ID: duplicateClientID,
|
||||
Domain: validClient.Domain,
|
||||
Name: validClient.Name,
|
||||
Metadata: map[string]any{"key": "different_value"},
|
||||
CreatedAt: validTimestamp,
|
||||
Status: clients.EnabledStatus,
|
||||
ID: duplicateClientID,
|
||||
Domain: validClient.Domain,
|
||||
Name: validClient.Name,
|
||||
PublicMetadata: map[string]any{"key": "different_value"},
|
||||
Metadata: map[string]any{},
|
||||
CreatedAt: validTimestamp,
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
@@ -419,9 +454,10 @@ func TestClientsRetrieveBySecret(t *testing.T) {
|
||||
Identity: clientIdentity,
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Domain: testsutil.GenerateUUID(t),
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
Domain: testsutil.GenerateUUID(t),
|
||||
PublicMetadata: clients.Metadata{},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
}
|
||||
|
||||
_, err := repo.Save(context.Background(), client)
|
||||
@@ -488,9 +524,11 @@ func TestClientsRetrieveBySecret(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
res, err := repo.RetrieveBySecret(context.Background(), tc.secret, tc.id, tc.prefix)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
assert.Equal(t, res, tc.response, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, res))
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
res, err := repo.RetrieveBySecret(context.Background(), tc.secret, tc.id, tc.prefix)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
assert.Equal(t, res, tc.response, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, res))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,8 +546,13 @@ func TestRetrieveByID(t *testing.T) {
|
||||
Identity: clientIdentity,
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
PublicMetadata: clients.Metadata{
|
||||
"key": "value",
|
||||
},
|
||||
Metadata: clients.Metadata{
|
||||
"key": "value",
|
||||
},
|
||||
Status: clients.EnabledStatus,
|
||||
}
|
||||
|
||||
_, err := repo.Save(context.Background(), client)
|
||||
@@ -547,6 +590,7 @@ func TestRetrieveByID(t *testing.T) {
|
||||
if err == nil {
|
||||
assert.Equal(t, client.ID, cli.ID)
|
||||
assert.Equal(t, client.Name, cli.Name)
|
||||
assert.Equal(t, client.PublicMetadata, cli.PublicMetadata)
|
||||
assert.Equal(t, client.Metadata, cli.Metadata)
|
||||
assert.Equal(t, client.Credentials.Identity, cli.Credentials.Identity)
|
||||
assert.Equal(t, client.Credentials.Secret, cli.Credentials.Secret)
|
||||
@@ -577,11 +621,12 @@ func TestUpdate(t *testing.T) {
|
||||
desc: "update client successfully",
|
||||
update: "all",
|
||||
client: clients.Client{
|
||||
ID: validClient.ID,
|
||||
Name: namegen.Generate(),
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
UpdatedAt: validTimestamp,
|
||||
UpdatedBy: testsutil.GenerateUUID(t),
|
||||
ID: validClient.ID,
|
||||
Name: namegen.Generate(),
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
UpdatedAt: validTimestamp,
|
||||
UpdatedBy: testsutil.GenerateUUID(t),
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
@@ -596,6 +641,17 @@ func TestUpdate(t *testing.T) {
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update client public metadata",
|
||||
update: "public_metadata",
|
||||
client: clients.Client{
|
||||
ID: validClient.ID,
|
||||
PublicMetadata: map[string]any{"key1": "value1"},
|
||||
UpdatedAt: validTimestamp,
|
||||
UpdatedBy: testsutil.GenerateUUID(t),
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update client metadata",
|
||||
update: "metadata",
|
||||
@@ -611,11 +667,12 @@ func TestUpdate(t *testing.T) {
|
||||
desc: "update client with invalid ID",
|
||||
update: "all",
|
||||
client: clients.Client{
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Name: namegen.Generate(),
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
UpdatedAt: validTimestamp,
|
||||
UpdatedBy: testsutil.GenerateUUID(t),
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Name: namegen.Generate(),
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
UpdatedAt: validTimestamp,
|
||||
UpdatedBy: testsutil.GenerateUUID(t),
|
||||
},
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
@@ -623,10 +680,11 @@ func TestUpdate(t *testing.T) {
|
||||
desc: "update client with empty ID",
|
||||
update: "all",
|
||||
client: clients.Client{
|
||||
Name: namegen.Generate(),
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
UpdatedAt: validTimestamp,
|
||||
UpdatedBy: testsutil.GenerateUUID(t),
|
||||
Name: namegen.Generate(),
|
||||
PublicMetadata: map[string]any{"key": "value"},
|
||||
Metadata: map[string]any{"key": "value"},
|
||||
UpdatedAt: validTimestamp,
|
||||
UpdatedBy: testsutil.GenerateUUID(t),
|
||||
},
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
@@ -643,9 +701,12 @@ func TestUpdate(t *testing.T) {
|
||||
switch tc.update {
|
||||
case "all":
|
||||
assert.Equal(t, tc.client.Name, client.Name, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.Name, client.Name))
|
||||
assert.Equal(t, tc.client.PublicMetadata, client.PublicMetadata, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.PublicMetadata, client.PublicMetadata))
|
||||
assert.Equal(t, tc.client.Metadata, client.Metadata, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.Metadata, client.Metadata))
|
||||
case "name":
|
||||
assert.Equal(t, tc.client.Name, client.Name, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.Name, client.Name))
|
||||
case "public_metadata":
|
||||
assert.Equal(t, tc.client.PublicMetadata, client.PublicMetadata, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.PublicMetadata, client.PublicMetadata))
|
||||
case "metadata":
|
||||
assert.Equal(t, tc.client.Metadata, client.Metadata, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.Metadata, client.Metadata))
|
||||
}
|
||||
@@ -936,7 +997,7 @@ func TestRetrieveByIDsWithRoles(t *testing.T) {
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Tags: namegen.GenerateMultiple(5),
|
||||
Metadata: clients.Metadata{
|
||||
PublicMetadata: clients.Metadata{
|
||||
"department": namegen.Generate(),
|
||||
},
|
||||
Status: clients.EnabledStatus,
|
||||
@@ -1059,7 +1120,7 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Tags: namegen.GenerateMultiple(5),
|
||||
Metadata: clients.Metadata{
|
||||
PublicMetadata: clients.Metadata{
|
||||
"department": namegen.Generate(),
|
||||
},
|
||||
Status: clients.EnabledStatus,
|
||||
@@ -1116,6 +1177,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
pm: clients.Page{
|
||||
Offset: 50,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1129,16 +1192,18 @@ func TestRetrieveAll(t *testing.T) {
|
||||
{
|
||||
desc: "with limit only",
|
||||
pm: clients.Page{
|
||||
Limit: 50,
|
||||
Limit: 10,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
Total: nClients,
|
||||
Offset: 0,
|
||||
Limit: 50,
|
||||
Limit: 10,
|
||||
},
|
||||
Clients: expectedClients[:50],
|
||||
Clients: expectedClients[:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1147,6 +1212,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Offset: 0,
|
||||
Limit: nClients,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1163,6 +1230,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Offset: 50,
|
||||
Limit: 50,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1179,6 +1248,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Offset: 1000,
|
||||
Limit: 50,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1195,6 +1266,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Offset: 170,
|
||||
Limit: 50,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1206,12 +1279,14 @@ func TestRetrieveAll(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "with metadata",
|
||||
desc: "with public metadata",
|
||||
pm: clients.Page{
|
||||
Offset: 0,
|
||||
Limit: nClients,
|
||||
Metadata: expectedClients[0].Metadata,
|
||||
Metadata: expectedClients[0].PublicMetadata,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1231,6 +1306,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
"faculty": namegen.Generate(),
|
||||
},
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1250,6 +1327,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
"faculty": make(chan int),
|
||||
},
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1268,6 +1347,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Limit: nClients,
|
||||
Name: expectedClients[0].Name,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1302,6 +1383,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Limit: nClients,
|
||||
Identity: expectedClients[0].Credentials.Identity,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1336,6 +1419,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Limit: nClients,
|
||||
Domain: expectedClients[0].Domain,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1353,6 +1438,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Limit: nClients,
|
||||
Domain: testsutil.GenerateUUID(t),
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1369,6 +1456,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Status: clients.EnabledStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1385,6 +1474,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Offset: 0,
|
||||
Limit: nClients,
|
||||
Status: clients.DisabledStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1401,6 +1492,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Offset: 0,
|
||||
Limit: nClients,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1434,6 +1527,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Limit: nClients,
|
||||
Tag: expectedClients[0].Tags[0],
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1451,6 +1546,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Limit: nClients,
|
||||
Tag: namegen.Generate(),
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1466,12 +1563,14 @@ func TestRetrieveAll(t *testing.T) {
|
||||
pm: clients.Page{
|
||||
Offset: 0,
|
||||
Limit: nClients,
|
||||
Metadata: expectedClients[0].Metadata,
|
||||
Metadata: expectedClients[0].PublicMetadata,
|
||||
Name: expectedClients[0].Name,
|
||||
Tag: expectedClients[0].Tags[0],
|
||||
Identity: expectedClients[0].Credentials.Identity,
|
||||
Domain: expectedClients[0].Domain,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1489,6 +1588,8 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Limit: nClients,
|
||||
ID: expectedClients[0].ID,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
},
|
||||
response: clients.ClientsPage{
|
||||
Page: clients.Page{
|
||||
@@ -1728,7 +1829,7 @@ func TestRetrieveUserClients(t *testing.T) {
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Tags: namegen.GenerateMultiple(5),
|
||||
Metadata: clients.Metadata{
|
||||
PublicMetadata: clients.Metadata{
|
||||
"department": namegen.Generate(),
|
||||
},
|
||||
Status: clients.EnabledStatus,
|
||||
@@ -1935,7 +2036,7 @@ func TestRetrieveUserClients(t *testing.T) {
|
||||
pm: clients.Page{
|
||||
Offset: 0,
|
||||
Limit: nClients,
|
||||
Metadata: directClients[0].Metadata,
|
||||
Metadata: directClients[0].PublicMetadata,
|
||||
Status: clients.AllStatus,
|
||||
Order: defOrder,
|
||||
Dir: ascDir,
|
||||
@@ -1994,7 +2095,7 @@ func TestRetrieveUserClients(t *testing.T) {
|
||||
},
|
||||
Clients: []clients.Client(nil),
|
||||
},
|
||||
err: repoerr.ErrMalformedEntity,
|
||||
err: repoerr.ErrViewEntity,
|
||||
},
|
||||
{
|
||||
desc: "retrieve clients with name",
|
||||
@@ -2129,7 +2230,7 @@ func TestRetrieveUserClients(t *testing.T) {
|
||||
pm: clients.Page{
|
||||
Offset: 0,
|
||||
Limit: nClients,
|
||||
Metadata: directClients[0].Metadata,
|
||||
Metadata: directClients[0].PublicMetadata,
|
||||
Name: directClients[0].Name,
|
||||
Tag: directClients[0].Tags[0],
|
||||
Identity: directClients[0].Credentials.Identity,
|
||||
@@ -2592,6 +2693,9 @@ func TestSearchClients(t *testing.T) {
|
||||
Identity: username,
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
PublicMetadata: clients.Metadata{
|
||||
"department": namegen.Generate(),
|
||||
},
|
||||
Metadata: clients.Metadata{},
|
||||
Status: clients.EnabledStatus,
|
||||
CreatedAt: baseTime.Add(time.Duration(i) * time.Microsecond),
|
||||
@@ -2600,9 +2704,10 @@ func TestSearchClients(t *testing.T) {
|
||||
require.Nil(t, err, fmt.Sprintf("save client unexpected error: %s", err))
|
||||
|
||||
expectedClients = append(expectedClients, clients.Client{
|
||||
ID: client.ID,
|
||||
Name: client.Name,
|
||||
CreatedAt: client.CreatedAt,
|
||||
ID: client.ID,
|
||||
Name: client.Name,
|
||||
PublicMetadata: client.PublicMetadata,
|
||||
CreatedAt: client.CreatedAt,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2973,10 +3078,10 @@ func TestRetrieveByIDs(t *testing.T) {
|
||||
Identity: name + emailSuffix,
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Tags: namegen.GenerateMultiple(5),
|
||||
Metadata: map[string]any{"name": name},
|
||||
CreatedAt: baseTime.Add(time.Duration(i) * time.Microsecond),
|
||||
Status: clients.EnabledStatus,
|
||||
Tags: namegen.GenerateMultiple(5),
|
||||
PublicMetadata: map[string]any{"name": name},
|
||||
CreatedAt: baseTime.Add(time.Duration(i) * time.Microsecond),
|
||||
Status: clients.EnabledStatus,
|
||||
}
|
||||
_, err := repo.Save(context.Background(), client)
|
||||
require.Nil(t, err, fmt.Sprintf("add new client: expected nil got %s\n", err))
|
||||
@@ -3601,13 +3706,13 @@ func TestRetrieveParentGroupClients(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
name := namegen.Generate()
|
||||
client := clients.Client{
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Domain: testsutil.GenerateUUID(t),
|
||||
ParentGroup: parentID,
|
||||
Name: name,
|
||||
Metadata: map[string]any{"name": name},
|
||||
CreatedAt: baseTime.Add(time.Duration(i) * time.Microsecond),
|
||||
Status: clients.EnabledStatus,
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Domain: testsutil.GenerateUUID(t),
|
||||
ParentGroup: parentID,
|
||||
Name: name,
|
||||
PublicMetadata: map[string]any{"name": name},
|
||||
CreatedAt: baseTime.Add(time.Duration(i) * time.Microsecond),
|
||||
Status: clients.EnabledStatus,
|
||||
}
|
||||
items = append(items, client)
|
||||
}
|
||||
@@ -3669,13 +3774,13 @@ func TestUnsetParentGroupFromClients(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
name := namegen.Generate()
|
||||
client := clients.Client{
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Domain: testsutil.GenerateUUID(t),
|
||||
ParentGroup: parentID,
|
||||
Name: name,
|
||||
Metadata: map[string]any{"name": name},
|
||||
CreatedAt: baseTime.Add(time.Duration(i) * time.Microsecond),
|
||||
Status: clients.EnabledStatus,
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Domain: testsutil.GenerateUUID(t),
|
||||
ParentGroup: parentID,
|
||||
Name: name,
|
||||
PublicMetadata: map[string]any{"name": name},
|
||||
CreatedAt: baseTime.Add(time.Duration(i) * time.Microsecond),
|
||||
Status: clients.EnabledStatus,
|
||||
}
|
||||
items = append(items, client)
|
||||
}
|
||||
@@ -3722,6 +3827,9 @@ func generateClient(t *testing.T, status clients.Status, repo clients.Repository
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Tags: namegen.GenerateMultiple(5),
|
||||
PublicMetadata: clients.Metadata{
|
||||
"name": namegen.Generate(),
|
||||
},
|
||||
Metadata: clients.Metadata{
|
||||
"name": namegen.Generate(),
|
||||
},
|
||||
|
||||
@@ -76,6 +76,15 @@ func Migration() (*migrate.MemoryMigrationSource, error) {
|
||||
`ALTER TABLE clients ALTER COLUMN updated_at TYPE TIMESTAMP;`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "clients_04",
|
||||
Up: []string{
|
||||
`ALTER TABLE clients ADD COLUMN public_metadata JSONB;`,
|
||||
},
|
||||
Down: []string{
|
||||
`ALTER TABLE clients DROP COLUMN public_metadata;`,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+6
-5
@@ -166,11 +166,12 @@ func (svc service) ListUserClients(ctx context.Context, session authn.Session, u
|
||||
|
||||
func (svc service) Update(ctx context.Context, session authn.Session, cli Client) (Client, error) {
|
||||
client := Client{
|
||||
ID: cli.ID,
|
||||
Name: cli.Name,
|
||||
Metadata: cli.Metadata,
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
UpdatedBy: session.UserID,
|
||||
ID: cli.ID,
|
||||
Name: cli.Name,
|
||||
Metadata: cli.Metadata,
|
||||
PublicMetadata: cli.PublicMetadata,
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
UpdatedBy: session.UserID,
|
||||
}
|
||||
client, err := svc.repo.Update(ctx, client)
|
||||
if err != nil {
|
||||
|
||||
+38
-19
@@ -29,24 +29,26 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
secret = "strongsecret"
|
||||
validTMetadata = clients.Metadata{"role": "client"}
|
||||
ID = "6e5e10b3-d4df-4758-b426-4929d55ad740"
|
||||
client = clients.Client{
|
||||
ID: ID,
|
||||
Name: "clientname",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Credentials: clients.Credentials{Identity: "clientidentity", Secret: secret},
|
||||
Metadata: validTMetadata,
|
||||
Status: clients.EnabledStatus,
|
||||
secret = "strongsecret"
|
||||
validMetadata = clients.Metadata{"role": "client"}
|
||||
ID = "6e5e10b3-d4df-4758-b426-4929d55ad740"
|
||||
client = clients.Client{
|
||||
ID: ID,
|
||||
Name: "clientname",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Credentials: clients.Credentials{Identity: "clientidentity", Secret: secret},
|
||||
PublicMetadata: validMetadata,
|
||||
Metadata: validMetadata,
|
||||
Status: clients.EnabledStatus,
|
||||
}
|
||||
clientWithRoles = clients.Client{
|
||||
ID: ID,
|
||||
Name: "clientname",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Credentials: clients.Credentials{Identity: "clientidentity", Secret: secret},
|
||||
Metadata: validTMetadata,
|
||||
Status: clients.EnabledStatus,
|
||||
ID: ID,
|
||||
Name: "clientname",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Credentials: clients.Credentials{Identity: "clientidentity", Secret: secret},
|
||||
PublicMetadata: validMetadata,
|
||||
Metadata: validMetadata,
|
||||
Status: clients.EnabledStatus,
|
||||
Roles: []roles.MemberRoleActions{
|
||||
{
|
||||
RoleID: "test_role_id",
|
||||
@@ -186,6 +188,19 @@ func TestCreateClients(t *testing.T) {
|
||||
token: validToken,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "create a new enabled client with public metadata",
|
||||
client: clients.Client{
|
||||
Credentials: clients.Credentials{
|
||||
Identity: "newclientwithmetadata@example.com",
|
||||
Secret: secret,
|
||||
},
|
||||
PublicMetadata: validMetadata,
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
token: validToken,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "create a new enabled client with metadata",
|
||||
client: clients.Client{
|
||||
@@ -193,20 +208,20 @@ func TestCreateClients(t *testing.T) {
|
||||
Identity: "newclientwithmetadata@example.com",
|
||||
Secret: secret,
|
||||
},
|
||||
Metadata: validTMetadata,
|
||||
Metadata: validMetadata,
|
||||
Status: clients.EnabledStatus,
|
||||
},
|
||||
token: validToken,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "create a new disabled client with metadata",
|
||||
desc: "create a new disabled client with public metadata",
|
||||
client: clients.Client{
|
||||
Credentials: clients.Credentials{
|
||||
Identity: "newclientwithmetadata@example.com",
|
||||
Secret: secret,
|
||||
},
|
||||
Metadata: validTMetadata,
|
||||
PublicMetadata: validMetadata,
|
||||
},
|
||||
token: validToken,
|
||||
err: nil,
|
||||
@@ -243,6 +258,9 @@ func TestCreateClients(t *testing.T) {
|
||||
Identity: "newclientwithallfields@example.com",
|
||||
Secret: secret,
|
||||
},
|
||||
PublicMetadata: clients.Metadata{
|
||||
"name": "newclientwithallfields",
|
||||
},
|
||||
Metadata: clients.Metadata{
|
||||
"name": "newclientwithallfields",
|
||||
},
|
||||
@@ -592,6 +610,7 @@ func TestUpdateClient(t *testing.T) {
|
||||
client1 := client
|
||||
client2 := client
|
||||
client1.Name = "Updated client"
|
||||
client2.PublicMetadata = clients.Metadata{"role": "test"}
|
||||
client2.Metadata = clients.Metadata{"role": "test"}
|
||||
|
||||
cases := []struct {
|
||||
|
||||
@@ -59,6 +59,7 @@ services:
|
||||
AM_CERTS_SECRET_ID_PATH: ${AM_CERTS_SECRET_ID_PATH}
|
||||
AM_CERTS_SECRET_RENEW_THRESHOLD: ${AM_CERTS_SECRET_RENEW_THRESHOLD}
|
||||
AM_CERTS_SECRET_CHECK_INTERVAL: ${AM_CERTS_SECRET_CHECK_INTERVAL}
|
||||
SMQ_ALLOW_UNVERIFIED_USER: ${SMQ_ALLOW_UNVERIFIED_USER}
|
||||
ports:
|
||||
- ${AM_CERTS_HTTP_PORT}:${AM_CERTS_HTTP_PORT}
|
||||
- ${AM_CERTS_GRPC_PORT}:${AM_CERTS_GRPC_PORT}
|
||||
|
||||
@@ -35,15 +35,16 @@ message User {
|
||||
string last_name = 3;
|
||||
repeated string tags = 4;
|
||||
google.protobuf.Struct metadata = 5;
|
||||
uint32 status = 6;
|
||||
uint32 role = 7;
|
||||
string profile_picture = 8;
|
||||
string username = 9;
|
||||
string email = 10;
|
||||
google.protobuf.Timestamp created_at = 11;
|
||||
google.protobuf.Timestamp updated_at = 12;
|
||||
string updated_by = 13;
|
||||
google.protobuf.Timestamp verified_at = 14;
|
||||
string auth_provider = 15;
|
||||
repeated string permissions = 16;
|
||||
google.protobuf.Struct public_metadata = 6;
|
||||
uint32 status = 7;
|
||||
uint32 role = 8;
|
||||
string profile_picture = 9;
|
||||
string username = 10;
|
||||
string email = 11;
|
||||
google.protobuf.Timestamp created_at = 12;
|
||||
google.protobuf.Timestamp updated_at = 13;
|
||||
string updated_by = 14;
|
||||
google.protobuf.Timestamp verified_at = 15;
|
||||
string auth_provider = 16;
|
||||
repeated string permissions = 17;
|
||||
}
|
||||
|
||||
@@ -95,6 +95,11 @@ func ToClient(data map[string]any) (clients.Client, error) {
|
||||
c.Metadata = meta
|
||||
}
|
||||
|
||||
pmeta, ok := data["public_metadata"].(map[string]any)
|
||||
if ok {
|
||||
c.PublicMetadata = pmeta
|
||||
}
|
||||
|
||||
uby, ok := data["updated_by"].(string)
|
||||
if ok {
|
||||
c.UpdatedBy = uby
|
||||
|
||||
+14
-13
@@ -27,19 +27,20 @@ const (
|
||||
|
||||
// Client represents supermq client.
|
||||
type Client struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
DomainID string `json:"domain_id,omitempty"`
|
||||
ParentGroup string `json:"parent_group_id,omitempty"`
|
||||
Credentials ClientCredentials `json:"credentials"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
UpdatedBy string `json:"updated_by,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
Roles []roles.MemberRoleActions `json:"roles,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
DomainID string `json:"domain_id,omitempty"`
|
||||
ParentGroup string `json:"parent_group_id,omitempty"`
|
||||
Credentials ClientCredentials `json:"credentials"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
PublicMetadata map[string]any `json:"public_metadata,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
UpdatedBy string `json:"updated_by,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
Roles []roles.MemberRoleActions `json:"roles,omitempty"`
|
||||
}
|
||||
|
||||
type ClientCredentials struct {
|
||||
|
||||
+43
-39
@@ -51,11 +51,12 @@ func TestCreateClient(t *testing.T) {
|
||||
|
||||
client := generateTestClient(t, false)
|
||||
createClientReq := sdk.Client{
|
||||
Name: client.Name,
|
||||
Tags: client.Tags,
|
||||
Credentials: client.Credentials,
|
||||
Metadata: client.Metadata,
|
||||
Status: client.Status,
|
||||
Name: client.Name,
|
||||
Tags: client.Tags,
|
||||
Credentials: client.Credentials,
|
||||
Metadata: client.Metadata,
|
||||
PublicMetadata: client.PublicMetadata,
|
||||
Status: client.Status,
|
||||
}
|
||||
|
||||
conf := sdk.Config{
|
||||
@@ -126,11 +127,12 @@ func TestCreateClient(t *testing.T) {
|
||||
domainID: domainID,
|
||||
token: validToken,
|
||||
createClientReq: sdk.Client{
|
||||
Name: strings.Repeat("a", 1025),
|
||||
Tags: client.Tags,
|
||||
Credentials: client.Credentials,
|
||||
Metadata: client.Metadata,
|
||||
Status: client.Status,
|
||||
Name: strings.Repeat("a", 1025),
|
||||
Tags: client.Tags,
|
||||
Credentials: client.Credentials,
|
||||
PublicMetadata: client.PublicMetadata,
|
||||
Metadata: client.Metadata,
|
||||
Status: client.Status,
|
||||
},
|
||||
svcReq: clients.Client{},
|
||||
svcRes: []clients.Client{},
|
||||
@@ -143,12 +145,13 @@ func TestCreateClient(t *testing.T) {
|
||||
domainID: domainID,
|
||||
token: validToken,
|
||||
createClientReq: sdk.Client{
|
||||
ID: "123456789",
|
||||
Name: client.Name,
|
||||
Tags: client.Tags,
|
||||
Credentials: client.Credentials,
|
||||
Metadata: client.Metadata,
|
||||
Status: client.Status,
|
||||
ID: "123456789",
|
||||
Name: client.Name,
|
||||
Tags: client.Tags,
|
||||
Credentials: client.Credentials,
|
||||
PublicMetadata: client.PublicMetadata,
|
||||
Metadata: client.Metadata,
|
||||
Status: client.Status,
|
||||
},
|
||||
svcReq: clients.Client{},
|
||||
svcRes: []clients.Client{},
|
||||
@@ -162,7 +165,7 @@ func TestCreateClient(t *testing.T) {
|
||||
token: validToken,
|
||||
createClientReq: sdk.Client{
|
||||
Name: valid,
|
||||
Metadata: map[string]any{
|
||||
PublicMetadata: map[string]any{
|
||||
valid: make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -182,7 +185,7 @@ func TestCreateClient(t *testing.T) {
|
||||
Name: client.Name,
|
||||
Tags: client.Tags,
|
||||
Credentials: clients.Credentials(client.Credentials),
|
||||
Metadata: clients.Metadata{
|
||||
PublicMetadata: clients.Metadata{
|
||||
"test": make(chan int),
|
||||
},
|
||||
}},
|
||||
@@ -276,7 +279,7 @@ func TestCreateClients(t *testing.T) {
|
||||
desc: "create new clients with a request that can't be marshalled",
|
||||
domainID: domainID,
|
||||
token: validToken,
|
||||
createClientsRequest: []sdk.Client{{Name: "test", Metadata: map[string]any{"test": make(chan int)}}},
|
||||
createClientsRequest: []sdk.Client{{Name: "test", PublicMetadata: map[string]any{"test": make(chan int)}}},
|
||||
svcReq: convertClients(sdkClients...),
|
||||
svcRes: []clients.Client{},
|
||||
svcErr: nil,
|
||||
@@ -293,7 +296,7 @@ func TestCreateClients(t *testing.T) {
|
||||
Name: sdkClients[0].Name,
|
||||
Tags: sdkClients[0].Tags,
|
||||
Credentials: clients.Credentials(sdkClients[0].Credentials),
|
||||
Metadata: clients.Metadata{
|
||||
PublicMetadata: clients.Metadata{
|
||||
"test": make(chan int),
|
||||
},
|
||||
}},
|
||||
@@ -559,7 +562,7 @@ func TestListClients(t *testing.T) {
|
||||
Name: sdkClients[0].Name,
|
||||
Tags: sdkClients[0].Tags,
|
||||
Credentials: clients.Credentials(sdkClients[0].Credentials),
|
||||
Metadata: clients.Metadata{
|
||||
PublicMetadata: clients.Metadata{
|
||||
"test": make(chan int),
|
||||
},
|
||||
}},
|
||||
@@ -695,7 +698,7 @@ func TestViewClient(t *testing.T) {
|
||||
Name: sdkClient.Name,
|
||||
Tags: sdkClient.Tags,
|
||||
Credentials: clients.Credentials(sdkClient.Credentials),
|
||||
Metadata: clients.Metadata{
|
||||
PublicMetadata: clients.Metadata{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -742,13 +745,13 @@ func TestUpdateClient(t *testing.T) {
|
||||
sdkClient := generateTestClient(t, false)
|
||||
updatedClient := sdkClient
|
||||
updatedClient.Name = "newName"
|
||||
updatedClient.Metadata = map[string]any{
|
||||
updatedClient.PublicMetadata = map[string]any{
|
||||
"newKey": "newValue",
|
||||
}
|
||||
updateClientReq := sdk.Client{
|
||||
ID: sdkClient.ID,
|
||||
Name: updatedClient.Name,
|
||||
Metadata: updatedClient.Metadata,
|
||||
ID: sdkClient.ID,
|
||||
Name: updatedClient.Name,
|
||||
PublicMetadata: updatedClient.PublicMetadata,
|
||||
}
|
||||
|
||||
conf := sdk.Config{
|
||||
@@ -844,7 +847,7 @@ func TestUpdateClient(t *testing.T) {
|
||||
|
||||
updateClientReq: sdk.Client{
|
||||
ID: valid,
|
||||
Metadata: map[string]any{
|
||||
PublicMetadata: map[string]any{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -864,7 +867,7 @@ func TestUpdateClient(t *testing.T) {
|
||||
Name: updatedClient.Name,
|
||||
Tags: updatedClient.Tags,
|
||||
Credentials: clients.Credentials(updatedClient.Credentials),
|
||||
Metadata: clients.Metadata{
|
||||
PublicMetadata: clients.Metadata{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -996,7 +999,7 @@ func TestUpdateClientTags(t *testing.T) {
|
||||
token: validToken,
|
||||
updateClientReq: sdk.Client{
|
||||
ID: valid,
|
||||
Metadata: map[string]any{
|
||||
PublicMetadata: map[string]any{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -1016,7 +1019,7 @@ func TestUpdateClientTags(t *testing.T) {
|
||||
Name: updatedClient.Name,
|
||||
Tags: updatedClient.Tags,
|
||||
Credentials: clients.Credentials(updatedClient.Credentials),
|
||||
Metadata: clients.Metadata{
|
||||
PublicMetadata: clients.Metadata{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -1148,7 +1151,7 @@ func TestUpdateClientSecret(t *testing.T) {
|
||||
Name: updatedClient.Name,
|
||||
Tags: updatedClient.Tags,
|
||||
Credentials: clients.Credentials(updatedClient.Credentials),
|
||||
Metadata: clients.Metadata{
|
||||
PublicMetadata: clients.Metadata{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -1251,7 +1254,7 @@ func TestEnableClient(t *testing.T) {
|
||||
Name: enabledClient.Name,
|
||||
Tags: enabledClient.Tags,
|
||||
Credentials: clients.Credentials(enabledClient.Credentials),
|
||||
Metadata: clients.Metadata{
|
||||
PublicMetadata: clients.Metadata{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -1354,7 +1357,7 @@ func TestDisableClient(t *testing.T) {
|
||||
Name: disabledClient.Name,
|
||||
Tags: disabledClient.Tags,
|
||||
Credentials: clients.Credentials(disabledClient.Credentials),
|
||||
Metadata: clients.Metadata{
|
||||
PublicMetadata: clients.Metadata{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -3268,11 +3271,12 @@ func generateTestClient(t *testing.T, withRoles bool) sdk.Client {
|
||||
Identity: "client@example.com",
|
||||
Secret: generateUUID(t),
|
||||
},
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Metadata: validMetadata,
|
||||
Status: clients.EnabledStatus.String(),
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
Roles: rl,
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Metadata: validMetadata,
|
||||
PublicMetadata: validMetadata,
|
||||
Status: clients.EnabledStatus.String(),
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
Roles: rl,
|
||||
}
|
||||
}
|
||||
|
||||
+21
-18
@@ -172,6 +172,7 @@ func convertUser(c sdk.User) users.User {
|
||||
Email: c.Email,
|
||||
Credentials: users.Credentials(c.Credentials),
|
||||
Metadata: users.Metadata(c.Metadata),
|
||||
PublicMetadata: users.Metadata(c.PublicMetadata),
|
||||
CreatedAt: c.CreatedAt,
|
||||
UpdatedAt: c.UpdatedAt,
|
||||
Status: status,
|
||||
@@ -189,18 +190,19 @@ func convertClient(c sdk.Client) clients.Client {
|
||||
return clients.Client{}
|
||||
}
|
||||
return clients.Client{
|
||||
ID: c.ID,
|
||||
Name: c.Name,
|
||||
Tags: c.Tags,
|
||||
Domain: c.DomainID,
|
||||
ParentGroup: c.ParentGroup,
|
||||
Credentials: clients.Credentials(c.Credentials),
|
||||
Metadata: clients.Metadata(c.Metadata),
|
||||
CreatedAt: c.CreatedAt,
|
||||
UpdatedAt: c.UpdatedAt,
|
||||
UpdatedBy: c.UpdatedBy,
|
||||
Status: status,
|
||||
Roles: c.Roles,
|
||||
ID: c.ID,
|
||||
Name: c.Name,
|
||||
Tags: c.Tags,
|
||||
Domain: c.DomainID,
|
||||
ParentGroup: c.ParentGroup,
|
||||
Credentials: clients.Credentials(c.Credentials),
|
||||
Metadata: clients.Metadata(c.Metadata),
|
||||
PublicMetadata: clients.Metadata(c.PublicMetadata),
|
||||
CreatedAt: c.CreatedAt,
|
||||
UpdatedAt: c.UpdatedAt,
|
||||
UpdatedBy: c.UpdatedBy,
|
||||
Status: status,
|
||||
Roles: c.Roles,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,12 +267,13 @@ func generateTestUser(t *testing.T) sdk.User {
|
||||
Username: "username",
|
||||
Secret: secret,
|
||||
},
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Metadata: validMetadata,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: createdAt,
|
||||
Status: users.EnabledStatus.String(),
|
||||
Role: users.UserRole.String(),
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Metadata: validMetadata,
|
||||
PublicMetadata: validMetadata,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: createdAt,
|
||||
Status: users.EnabledStatus.String(),
|
||||
Role: users.UserRole.String(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ type User struct {
|
||||
Credentials Credentials `json:"credentials"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Metadata Metadata `json:"metadata,omitempty"`
|
||||
PublicMetadata Metadata `json:"public_metadata,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
+45
-40
@@ -56,13 +56,14 @@ func TestCreateUser(t *testing.T) {
|
||||
defer ts.Close()
|
||||
|
||||
createSdkUserReq := sdk.User{
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
Email: user.Email,
|
||||
Tags: user.Tags,
|
||||
Credentials: user.Credentials,
|
||||
Metadata: user.Metadata,
|
||||
Status: user.Status,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
Email: user.Email,
|
||||
Tags: user.Tags,
|
||||
Credentials: user.Credentials,
|
||||
Metadata: user.Metadata,
|
||||
PublicMetadata: user.PublicMetadata,
|
||||
Status: user.Status,
|
||||
}
|
||||
|
||||
conf := sdk.Config{
|
||||
@@ -142,10 +143,11 @@ func TestCreateUser(t *testing.T) {
|
||||
desc: "register user with first name too long",
|
||||
token: validToken,
|
||||
createSdkUserReq: sdk.User{
|
||||
FirstName: strings.Repeat("a", 1025),
|
||||
Credentials: createSdkUserReq.Credentials,
|
||||
Metadata: createSdkUserReq.Metadata,
|
||||
Tags: createSdkUserReq.Tags,
|
||||
FirstName: strings.Repeat("a", 1025),
|
||||
Credentials: createSdkUserReq.Credentials,
|
||||
PublicMetadata: createSdkUserReq.PublicMetadata,
|
||||
Metadata: createSdkUserReq.Metadata,
|
||||
Tags: createSdkUserReq.Tags,
|
||||
},
|
||||
svcReq: users.User{},
|
||||
svcRes: users.User{},
|
||||
@@ -164,8 +166,9 @@ func TestCreateUser(t *testing.T) {
|
||||
Username: "",
|
||||
Secret: createSdkUserReq.Credentials.Secret,
|
||||
},
|
||||
Metadata: createSdkUserReq.Metadata,
|
||||
Tags: createSdkUserReq.Tags,
|
||||
PublicMetadata: createSdkUserReq.PublicMetadata,
|
||||
Metadata: createSdkUserReq.Metadata,
|
||||
Tags: createSdkUserReq.Tags,
|
||||
},
|
||||
svcReq: users.User{},
|
||||
svcRes: users.User{},
|
||||
@@ -184,8 +187,9 @@ func TestCreateUser(t *testing.T) {
|
||||
Username: createSdkUserReq.Credentials.Username,
|
||||
Secret: "",
|
||||
},
|
||||
Metadata: createSdkUserReq.Metadata,
|
||||
Tags: createSdkUserReq.Tags,
|
||||
PublicMetadata: createSdkUserReq.PublicMetadata,
|
||||
Metadata: createSdkUserReq.Metadata,
|
||||
Tags: createSdkUserReq.Tags,
|
||||
},
|
||||
svcReq: users.User{},
|
||||
svcRes: users.User{},
|
||||
@@ -204,8 +208,9 @@ func TestCreateUser(t *testing.T) {
|
||||
Username: createSdkUserReq.Credentials.Username,
|
||||
Secret: "weak",
|
||||
},
|
||||
Metadata: createSdkUserReq.Metadata,
|
||||
Tags: createSdkUserReq.Tags,
|
||||
PublicMetadata: createSdkUserReq.PublicMetadata,
|
||||
Metadata: createSdkUserReq.Metadata,
|
||||
Tags: createSdkUserReq.Tags,
|
||||
},
|
||||
svcReq: users.User{},
|
||||
svcRes: users.User{},
|
||||
@@ -224,7 +229,7 @@ func TestCreateUser(t *testing.T) {
|
||||
FirstName: createSdkUserReq.FirstName,
|
||||
LastName: createSdkUserReq.LastName,
|
||||
Email: createSdkUserReq.Email,
|
||||
Metadata: map[string]any{
|
||||
PublicMetadata: map[string]any{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -248,7 +253,7 @@ func TestCreateUser(t *testing.T) {
|
||||
Username: createSdkUserReq.Credentials.Username,
|
||||
Secret: createSdkUserReq.Credentials.Secret,
|
||||
},
|
||||
Metadata: users.Metadata{
|
||||
PublicMetadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -290,9 +295,9 @@ func TestListUsers(t *testing.T) {
|
||||
Username: fmt.Sprintf("Username_%d", i),
|
||||
Secret: fmt.Sprintf("password_%d", i),
|
||||
},
|
||||
Metadata: sdk.Metadata{"name": fmt.Sprintf("user_%d", i)},
|
||||
Status: users.EnabledStatus.String(),
|
||||
Role: users.UserRole.String(),
|
||||
PublicMetadata: sdk.Metadata{"name": fmt.Sprintf("user_%d", i)},
|
||||
Status: users.EnabledStatus.String(),
|
||||
Role: users.UserRole.String(),
|
||||
}
|
||||
if i == 50 {
|
||||
cl.Status = users.DisabledStatus.String()
|
||||
@@ -546,7 +551,7 @@ func TestListUsers(t *testing.T) {
|
||||
{
|
||||
ID: id,
|
||||
FirstName: "user_99",
|
||||
Metadata: users.Metadata{
|
||||
PublicMetadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -600,9 +605,9 @@ func TestSearchUsers(t *testing.T) {
|
||||
Username: fmt.Sprintf("Username_%d", i),
|
||||
Secret: fmt.Sprintf("password_%d", i),
|
||||
},
|
||||
Metadata: sdk.Metadata{"name": fmt.Sprintf("user_%d", i)},
|
||||
Status: users.EnabledStatus.String(),
|
||||
Role: users.UserRole.String(),
|
||||
PublicMetadata: sdk.Metadata{"name": fmt.Sprintf("user_%d", i)},
|
||||
Status: users.EnabledStatus.String(),
|
||||
Role: users.UserRole.String(),
|
||||
}
|
||||
if i == 50 {
|
||||
cl.Status = users.DisabledStatus.String()
|
||||
@@ -782,7 +787,7 @@ func TestViewUser(t *testing.T) {
|
||||
ID: id,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
Metadata: users.Metadata{
|
||||
PublicMetadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -861,7 +866,7 @@ func TestUserProfile(t *testing.T) {
|
||||
svcRes: users.User{
|
||||
ID: id,
|
||||
FirstName: user.FirstName,
|
||||
Metadata: users.Metadata{
|
||||
PublicMetadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -1001,7 +1006,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: generateUUID(t),
|
||||
Metadata: map[string]any{
|
||||
PublicMetadata: map[string]any{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -1025,7 +1030,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
svcRes: users.User{
|
||||
ID: id,
|
||||
FirstName: updatedName,
|
||||
Metadata: users.Metadata{
|
||||
PublicMetadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -1162,7 +1167,7 @@ func TestUpdateUserTags(t *testing.T) {
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: generateUUID(t),
|
||||
Metadata: map[string]any{
|
||||
PublicMetadata: map[string]any{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -1186,7 +1191,7 @@ func TestUpdateUserTags(t *testing.T) {
|
||||
svcRes: users.User{
|
||||
ID: id,
|
||||
Tags: updatedTags,
|
||||
Metadata: users.Metadata{
|
||||
PublicMetadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -1334,7 +1339,7 @@ func TestUpdateUserEmail(t *testing.T) {
|
||||
svcRes: users.User{
|
||||
ID: id,
|
||||
FirstName: updatedEmail,
|
||||
Metadata: users.Metadata{
|
||||
PublicMetadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -1630,7 +1635,7 @@ func TestUpdatePassword(t *testing.T) {
|
||||
svcRes: users.User{
|
||||
ID: id,
|
||||
FirstName: user.FirstName,
|
||||
Metadata: users.Metadata{
|
||||
PublicMetadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -1764,7 +1769,7 @@ func TestUpdateUserRole(t *testing.T) {
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: generateUUID(t),
|
||||
Metadata: map[string]any{
|
||||
PublicMetadata: map[string]any{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -1788,7 +1793,7 @@ func TestUpdateUserRole(t *testing.T) {
|
||||
svcRes: users.User{
|
||||
ID: id,
|
||||
Role: users.AdminRole,
|
||||
Metadata: users.Metadata{
|
||||
PublicMetadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -1952,7 +1957,7 @@ func TestUpdateUsername(t *testing.T) {
|
||||
Credentials: users.Credentials{
|
||||
Username: updatedUsername,
|
||||
},
|
||||
Metadata: users.Metadata{
|
||||
PublicMetadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -2092,7 +2097,7 @@ func TestUpdateProfilePicture(t *testing.T) {
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: generateUUID(t),
|
||||
Metadata: map[string]any{
|
||||
PublicMetadata: map[string]any{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -2115,7 +2120,7 @@ func TestUpdateProfilePicture(t *testing.T) {
|
||||
},
|
||||
svcRes: users.User{
|
||||
ID: id,
|
||||
Metadata: users.Metadata{
|
||||
PublicMetadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -2293,7 +2298,7 @@ func TestDisableUser(t *testing.T) {
|
||||
svcRes: users.User{
|
||||
ID: id,
|
||||
Status: users.DisabledStatus,
|
||||
Metadata: users.Metadata{
|
||||
PublicMetadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
|
||||
+23
-22
@@ -37,14 +37,15 @@ var (
|
||||
secret = "strongsecret"
|
||||
validCMetadata = users.Metadata{"role": "user"}
|
||||
user = users.User{
|
||||
ID: testsutil.GenerateUUID(&testing.T{}),
|
||||
LastName: "doe",
|
||||
FirstName: "jane",
|
||||
Tags: []string{"foo", "bar"},
|
||||
Email: "useremail@example.com",
|
||||
Credentials: users.Credentials{Username: "username", Secret: secret},
|
||||
Metadata: validCMetadata,
|
||||
Status: users.EnabledStatus,
|
||||
ID: testsutil.GenerateUUID(&testing.T{}),
|
||||
LastName: "doe",
|
||||
FirstName: "jane",
|
||||
Tags: []string{"foo", "bar"},
|
||||
Email: "useremail@example.com",
|
||||
Credentials: users.Credentials{Username: "username", Secret: secret},
|
||||
PublicMetadata: validCMetadata,
|
||||
Metadata: validCMetadata,
|
||||
Status: users.EnabledStatus,
|
||||
}
|
||||
validToken = "valid"
|
||||
inValidToken = "invalid"
|
||||
@@ -145,7 +146,7 @@ func TestRegister(t *testing.T) {
|
||||
Credentials: users.Credentials{
|
||||
Secret: "12345678",
|
||||
},
|
||||
Metadata: map[string]any{
|
||||
PublicMetadata: map[string]any{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -917,14 +918,14 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update as admin user with valid token",
|
||||
id: user.ID,
|
||||
data: fmt.Sprintf(`{"name":"%s","metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
data: fmt.Sprintf(`{"name":"%s","public_metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
token: validToken,
|
||||
authnRes: verifiedSession,
|
||||
contentType: contentType,
|
||||
userResponse: users.User{
|
||||
ID: user.ID,
|
||||
FirstName: newName,
|
||||
Metadata: newMetadata,
|
||||
ID: user.ID,
|
||||
FirstName: newName,
|
||||
PublicMetadata: newMetadata,
|
||||
},
|
||||
status: http.StatusOK,
|
||||
err: nil,
|
||||
@@ -932,14 +933,14 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update as normal user with valid token",
|
||||
id: user.ID,
|
||||
data: fmt.Sprintf(`{"name":"%s","metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
data: fmt.Sprintf(`{"name":"%s","public_metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
token: validToken,
|
||||
authnRes: verifiedSession,
|
||||
contentType: contentType,
|
||||
userResponse: users.User{
|
||||
ID: user.ID,
|
||||
FirstName: newName,
|
||||
Metadata: newMetadata,
|
||||
ID: user.ID,
|
||||
FirstName: newName,
|
||||
PublicMetadata: newMetadata,
|
||||
},
|
||||
status: http.StatusOK,
|
||||
err: nil,
|
||||
@@ -947,7 +948,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update user with invalid token",
|
||||
id: user.ID,
|
||||
data: fmt.Sprintf(`{"name":"%s","metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
data: fmt.Sprintf(`{"name":"%s","public_metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
token: inValidToken,
|
||||
authnRes: smqauthn.Session{UserID: validID, DomainID: validID, Verified: true},
|
||||
contentType: contentType,
|
||||
@@ -958,7 +959,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update user with empty token",
|
||||
id: user.ID,
|
||||
data: fmt.Sprintf(`{"name":"%s","metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
data: fmt.Sprintf(`{"name":"%s","public_metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
token: "",
|
||||
authnRes: smqauthn.Session{UserID: validID, DomainID: validID, Verified: true},
|
||||
contentType: contentType,
|
||||
@@ -969,7 +970,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update user with invalid id",
|
||||
id: inValid,
|
||||
data: fmt.Sprintf(`{"name":"%s","metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
data: fmt.Sprintf(`{"name":"%s","public_metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
token: validToken,
|
||||
authnRes: verifiedSession,
|
||||
contentType: contentType,
|
||||
@@ -979,7 +980,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update user with invalid contentype",
|
||||
id: user.ID,
|
||||
data: fmt.Sprintf(`{"name":"%s","metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
data: fmt.Sprintf(`{"name":"%s","public_metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
token: validToken,
|
||||
authnRes: verifiedSession,
|
||||
contentType: "application/xml",
|
||||
@@ -999,7 +1000,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update user with empty id",
|
||||
id: " ",
|
||||
data: fmt.Sprintf(`{"name":"%s","metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
data: fmt.Sprintf(`{"name":"%s","public_metadata":%s}`, newName, toJSON(newMetadata)),
|
||||
token: validToken,
|
||||
authnRes: verifiedSession,
|
||||
contentType: contentType,
|
||||
|
||||
@@ -209,9 +209,10 @@ func updateEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
usr := users.UserReq{
|
||||
FirstName: req.FirstName,
|
||||
LastName: req.LastName,
|
||||
Metadata: req.Metadata,
|
||||
FirstName: req.FirstName,
|
||||
LastName: req.LastName,
|
||||
Metadata: req.Metadata,
|
||||
PublicMetadata: req.PublicMetadata,
|
||||
}
|
||||
|
||||
user, err := svc.Update(ctx, session, req.id, usr)
|
||||
|
||||
@@ -110,6 +110,10 @@ func userFromProto(u *grpcUsersV1.User) (users.User, error) {
|
||||
if u.GetMetadata() != nil {
|
||||
metadata = users.Metadata(u.GetMetadata().AsMap())
|
||||
}
|
||||
publicMetadata := users.Metadata(nil)
|
||||
if u.GetPublicMetadata() != nil {
|
||||
publicMetadata = users.Metadata(u.GetPublicMetadata().AsMap())
|
||||
}
|
||||
|
||||
user := users.User{
|
||||
ID: u.GetId(),
|
||||
@@ -117,6 +121,7 @@ func userFromProto(u *grpcUsersV1.User) (users.User, error) {
|
||||
LastName: u.GetLastName(),
|
||||
Tags: u.GetTags(),
|
||||
Metadata: metadata,
|
||||
PublicMetadata: publicMetadata,
|
||||
Status: users.Status(u.GetStatus()),
|
||||
Role: users.Role(u.GetRole()),
|
||||
ProfilePicture: u.GetProfilePicture(),
|
||||
|
||||
@@ -82,10 +82,16 @@ func toProtoUsers(us []users.User) ([]*grpcUsersV1.User, error) {
|
||||
}
|
||||
|
||||
func toProtoUser(u users.User) (*grpcUsersV1.User, error) {
|
||||
var md *structpb.Struct
|
||||
var metadata, publicMetadata *structpb.Struct
|
||||
var err error
|
||||
if u.Metadata != nil {
|
||||
md, err = structpb.NewStruct(u.Metadata)
|
||||
metadata, err = structpb.NewStruct(u.Metadata)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(svcerr.ErrViewEntity, err)
|
||||
}
|
||||
}
|
||||
if u.PublicMetadata != nil {
|
||||
publicMetadata, err = structpb.NewStruct(u.PublicMetadata)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(svcerr.ErrViewEntity, err)
|
||||
}
|
||||
@@ -96,7 +102,8 @@ func toProtoUser(u users.User) (*grpcUsersV1.User, error) {
|
||||
FirstName: u.FirstName,
|
||||
LastName: u.LastName,
|
||||
Tags: u.Tags,
|
||||
Metadata: md,
|
||||
Metadata: metadata,
|
||||
PublicMetadata: publicMetadata,
|
||||
Status: uint32(u.Status),
|
||||
Role: uint32(u.Role),
|
||||
ProfilePicture: u.ProfilePicture,
|
||||
|
||||
@@ -147,10 +147,11 @@ func (req searchUsersReq) validate() error {
|
||||
}
|
||||
|
||||
type updateUserReq struct {
|
||||
id string
|
||||
FirstName *string `json:"first_name,omitempty"`
|
||||
LastName *string `json:"last_name,omitempty"`
|
||||
Metadata *users.Metadata `json:"metadata,omitempty"`
|
||||
id string
|
||||
FirstName *string `json:"first_name,omitempty"`
|
||||
LastName *string `json:"last_name,omitempty"`
|
||||
Metadata *users.Metadata `json:"metadata,omitempty"`
|
||||
PublicMetadata *users.Metadata `json:"public_metadata,omitempty"`
|
||||
}
|
||||
|
||||
func (req updateUserReq) validate() error {
|
||||
|
||||
+13
-1
@@ -92,6 +92,9 @@ func (uce createUserEvent) Encode() (map[string]any, error) {
|
||||
if uce.Metadata != nil {
|
||||
val["metadata"] = uce.Metadata
|
||||
}
|
||||
if uce.PublicMetadata != nil {
|
||||
val["public_metadata"] = uce.PublicMetadata
|
||||
}
|
||||
if uce.Credentials.Username != "" {
|
||||
val["username"] = uce.Credentials.Username
|
||||
}
|
||||
@@ -171,6 +174,9 @@ func (uce updateUserEvent) Encode() (map[string]any, error) {
|
||||
if uce.Metadata != nil {
|
||||
val["metadata"] = uce.Metadata
|
||||
}
|
||||
if uce.PublicMetadata != nil {
|
||||
val["public_metadata"] = uce.PublicMetadata
|
||||
}
|
||||
if !uce.CreatedAt.IsZero() {
|
||||
val["created_at"] = uce.CreatedAt
|
||||
}
|
||||
@@ -290,11 +296,14 @@ func (vue viewUserEvent) Encode() (map[string]any, error) {
|
||||
val["email"] = vue.Email
|
||||
}
|
||||
if vue.Credentials.Username != "" {
|
||||
val["email"] = vue.Credentials.Username
|
||||
val["username"] = vue.Credentials.Username
|
||||
}
|
||||
if vue.Metadata != nil {
|
||||
val["metadata"] = vue.Metadata
|
||||
}
|
||||
if vue.PublicMetadata != nil {
|
||||
val["public_metadata"] = vue.PublicMetadata
|
||||
}
|
||||
if !vue.CreatedAt.IsZero() {
|
||||
val["created_at"] = vue.CreatedAt
|
||||
}
|
||||
@@ -338,6 +347,9 @@ func (vpe viewProfileEvent) Encode() (map[string]any, error) {
|
||||
if vpe.Metadata != nil {
|
||||
val["metadata"] = vpe.Metadata
|
||||
}
|
||||
if vpe.PublicMetadata != nil {
|
||||
val["public_metadata"] = vpe.PublicMetadata
|
||||
}
|
||||
if !vpe.CreatedAt.IsZero() {
|
||||
val["created_at"] = vpe.CreatedAt
|
||||
}
|
||||
|
||||
@@ -32,9 +32,7 @@ const (
|
||||
viewProfileStream = supermqPrefix + profileView
|
||||
listStream = supermqPrefix + userList
|
||||
searchStream = supermqPrefix + userSearch
|
||||
listByGroupStream = supermqPrefix + userListByGroup
|
||||
identifyStream = supermqPrefix + userIdentify
|
||||
resetTokenStream = supermqPrefix + generateResetToken
|
||||
issueTokenStream = supermqPrefix + issueToken
|
||||
refreshTokenStream = supermqPrefix + refreshToken
|
||||
resetSecretStream = supermqPrefix + resetSecret
|
||||
|
||||
@@ -1157,7 +1157,7 @@ func generateTestUser(t *testing.T) users.User {
|
||||
Secret: "secret",
|
||||
},
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Metadata: users.Metadata{
|
||||
PublicMetadata: users.Metadata{
|
||||
"key1": "value1",
|
||||
"key2": "value2",
|
||||
},
|
||||
|
||||
@@ -229,7 +229,7 @@ func (lm *loggingMiddleware) Update(ctx context.Context, session authn.Session,
|
||||
slog.String("username", u.Credentials.Username),
|
||||
slog.String("first_name", u.FirstName),
|
||||
slog.String("last_name", u.LastName),
|
||||
slog.Any("metadata", u.Metadata),
|
||||
slog.Any("public_metadata", u.PublicMetadata),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -136,6 +136,15 @@ func Migration() *migrate.MemoryMigrationSource {
|
||||
`ALTER TABLE users DROP COLUMN auth_provider`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "clients_10",
|
||||
Up: []string{
|
||||
`ALTER TABLE users ADD COLUMN public_metadata JSONB;`,
|
||||
},
|
||||
Down: []string{
|
||||
`ALTER TABLE users DROP COLUMN public_metadata;`,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
+42
-28
@@ -36,9 +36,9 @@ func NewRepository(db postgres.Database) users.Repository {
|
||||
}
|
||||
|
||||
func (repo *userRepo) Save(ctx context.Context, c users.User) (users.User, error) {
|
||||
q := `INSERT INTO users (id, tags, email, secret, metadata, created_at, status, role, first_name, last_name, username, profile_picture, auth_provider)
|
||||
VALUES (:id, :tags, :email, :secret, :metadata, :created_at, :status, :role, :first_name, :last_name, :username, :profile_picture, :auth_provider)
|
||||
RETURNING id, tags, email, metadata, created_at, status, role, first_name, last_name, username, profile_picture, verified_at, auth_provider`
|
||||
q := `INSERT INTO users (id, tags, email, secret, metadata, public_metadata, created_at, status, role, first_name, last_name, username, profile_picture, auth_provider)
|
||||
VALUES (:id, :tags, :email, :secret, :metadata, :public_metadata, :created_at, :status, :role, :first_name, :last_name, :username, :profile_picture, :auth_provider)
|
||||
RETURNING id, tags, email, metadata, public_metadata, created_at, status, role, first_name, last_name, username, profile_picture, verified_at, auth_provider`
|
||||
|
||||
dbu, err := toDBUser(c)
|
||||
if err != nil {
|
||||
@@ -86,7 +86,7 @@ func (repo *userRepo) CheckSuperAdmin(ctx context.Context, adminID string) error
|
||||
}
|
||||
|
||||
func (repo *userRepo) RetrieveByID(ctx context.Context, id string) (users.User, error) {
|
||||
q := `SELECT id, tags, email, secret, metadata, created_at, updated_at, updated_by, status, role, first_name, last_name, username, profile_picture, verified_at, auth_provider
|
||||
q := `SELECT id, tags, email, secret, metadata, public_metadata, created_at, updated_at, updated_by, status, role, first_name, last_name, username, profile_picture, verified_at, auth_provider
|
||||
FROM users WHERE id = :id`
|
||||
|
||||
dbu := DBUser{
|
||||
@@ -124,7 +124,7 @@ func (repo *userRepo) RetrieveAll(ctx context.Context, pm users.Page) (users.Use
|
||||
|
||||
squery := applyOrdering(query, pm)
|
||||
|
||||
q := fmt.Sprintf(`SELECT u.id, u.tags, u.email, u.metadata, u.status, u.role, u.first_name, u.last_name, u.username,
|
||||
q := fmt.Sprintf(`SELECT u.id, u.tags, u.email, u.public_metadata, u.status, u.role, u.first_name, u.last_name, u.username,
|
||||
u.created_at, u.updated_at, u.profile_picture, COALESCE(u.updated_by, '') AS updated_by, u.verified_at
|
||||
FROM users u %s LIMIT :limit OFFSET :offset;`, squery)
|
||||
|
||||
@@ -178,7 +178,7 @@ func (repo *userRepo) RetrieveAll(ctx context.Context, pm users.Page) (users.Use
|
||||
func (repo *userRepo) UpdateUsername(ctx context.Context, user users.User) (users.User, error) {
|
||||
q := `UPDATE users SET username = :username, updated_at = :updated_at, updated_by = :updated_by
|
||||
WHERE id = :id AND status = :status
|
||||
RETURNING id, tags, metadata, status, created_at, updated_at, updated_by, first_name, last_name, username, email, role, verified_at`
|
||||
RETURNING id, tags, metadata, public_metadata, status, created_at, updated_at, updated_by, first_name, last_name, username, email, role, verified_at`
|
||||
|
||||
return repo.update(ctx, user, q)
|
||||
}
|
||||
@@ -195,6 +195,10 @@ func (repo *userRepo) Update(ctx context.Context, id string, ur users.UserReq) (
|
||||
query = append(query, "last_name = :last_name")
|
||||
u.LastName = *ur.LastName
|
||||
}
|
||||
if ur.PublicMetadata != nil {
|
||||
query = append(query, "public_metadata = :public_metadata")
|
||||
u.PublicMetadata = *ur.PublicMetadata
|
||||
}
|
||||
if ur.Metadata != nil {
|
||||
query = append(query, "metadata = :metadata")
|
||||
u.Metadata = *ur.Metadata
|
||||
@@ -223,7 +227,7 @@ func (repo *userRepo) Update(ctx context.Context, id string, ur users.UserReq) (
|
||||
|
||||
q := fmt.Sprintf(`UPDATE users SET %s
|
||||
WHERE id = :id AND status = :status
|
||||
RETURNING id, tags, metadata, status, created_at, updated_at, updated_by, last_name, first_name, username, profile_picture, email, role, verified_at`, upq)
|
||||
RETURNING id, tags, metadata, public_metadata, status, created_at, updated_at, updated_by, last_name, first_name, username, profile_picture, email, role, verified_at`, upq)
|
||||
|
||||
u.Status = users.EnabledStatus
|
||||
return repo.update(ctx, u, q)
|
||||
@@ -256,7 +260,7 @@ func (repo *userRepo) update(ctx context.Context, user users.User, query string)
|
||||
func (repo *userRepo) UpdateEmail(ctx context.Context, user users.User) (users.User, error) {
|
||||
q := `UPDATE users SET email = :email, verified_at = NULL, updated_at = :updated_at, updated_by = :updated_by
|
||||
WHERE id = :id AND status = :status
|
||||
RETURNING id, tags, email, metadata, status, created_at, updated_at, updated_by, first_name, last_name, username, role, verified_at`
|
||||
RETURNING id, tags, email, metadata, public_metadata, status, created_at, updated_at, updated_by, first_name, last_name, username, role, verified_at`
|
||||
user.Status = users.EnabledStatus
|
||||
return repo.update(ctx, user, q)
|
||||
}
|
||||
@@ -264,7 +268,7 @@ func (repo *userRepo) UpdateEmail(ctx context.Context, user users.User) (users.U
|
||||
func (repo *userRepo) UpdateRole(ctx context.Context, user users.User) (users.User, error) {
|
||||
q := `UPDATE users SET role = :role, updated_at = :updated_at, updated_by = :updated_by
|
||||
WHERE id = :id AND status = :status
|
||||
RETURNING id, tags, email, metadata, status, created_at, updated_at, updated_by, first_name, last_name, username, role, verified_at`
|
||||
RETURNING id, tags, email, metadata, public_metadata, status, created_at, updated_at, updated_by, first_name, last_name, username, role, verified_at`
|
||||
user.Status = users.EnabledStatus
|
||||
return repo.update(ctx, user, q)
|
||||
}
|
||||
@@ -272,7 +276,7 @@ func (repo *userRepo) UpdateRole(ctx context.Context, user users.User) (users.Us
|
||||
func (repo *userRepo) UpdateSecret(ctx context.Context, user users.User) (users.User, error) {
|
||||
q := `UPDATE users SET secret = :secret, updated_at = :updated_at, updated_by = :updated_by
|
||||
WHERE id = :id AND status = :status
|
||||
RETURNING id, tags, email, metadata, status, created_at, updated_at, updated_by, first_name, last_name, username, role, verified_at`
|
||||
RETURNING id, tags, email, metadata, public_metadata, status, created_at, updated_at, updated_by, first_name, last_name, username, role, verified_at`
|
||||
user.Status = users.EnabledStatus
|
||||
return repo.update(ctx, user, q)
|
||||
}
|
||||
@@ -280,7 +284,7 @@ func (repo *userRepo) UpdateSecret(ctx context.Context, user users.User) (users.
|
||||
func (repo *userRepo) ChangeStatus(ctx context.Context, user users.User) (users.User, error) {
|
||||
q := `UPDATE users SET status = :status, updated_at = :updated_at, updated_by = :updated_by
|
||||
WHERE id = :id
|
||||
RETURNING id, tags, email, metadata, status, created_at, updated_at, updated_by, first_name, last_name, username, role, verified_at`
|
||||
RETURNING id, tags, email, metadata, public_metadata, status, created_at, updated_at, updated_by, first_name, last_name, username, role, verified_at`
|
||||
|
||||
return repo.update(ctx, user, q)
|
||||
}
|
||||
@@ -288,7 +292,7 @@ func (repo *userRepo) ChangeStatus(ctx context.Context, user users.User) (users.
|
||||
func (repo *userRepo) UpdateVerifiedAt(ctx context.Context, user users.User) (users.User, error) {
|
||||
q := `UPDATE users SET verified_at = :verified_at
|
||||
WHERE id = :id and email = :email
|
||||
RETURNING id, tags, email, metadata, status, created_at, updated_at, updated_by, first_name, last_name, username, role, verified_at`
|
||||
RETURNING id, tags, email, metadata, public_metadata, status, created_at, updated_at, updated_by, first_name, last_name, username, role, verified_at`
|
||||
|
||||
return repo.update(ctx, user, q)
|
||||
}
|
||||
@@ -316,7 +320,7 @@ func (repo *userRepo) SearchUsers(ctx context.Context, pm users.Page) (users.Use
|
||||
tq := query
|
||||
query = applyOrdering(query, pm)
|
||||
|
||||
q := fmt.Sprintf(`SELECT u.id, u.username, u.first_name, u.last_name, u.created_at, u.updated_at FROM users u %s LIMIT :limit OFFSET :offset;`, query)
|
||||
q := fmt.Sprintf(`SELECT u.id, u.username, u.public_metadata, u.first_name, u.last_name, u.created_at, u.updated_at FROM users u %s LIMIT :limit OFFSET :offset;`, query)
|
||||
|
||||
dbPage, err := ToDBUsersPage(pm)
|
||||
if err != nil {
|
||||
@@ -375,7 +379,7 @@ func (repo *userRepo) RetrieveAllByIDs(ctx context.Context, pm users.Page) (user
|
||||
}
|
||||
squery := applyOrdering(query, pm)
|
||||
|
||||
q := fmt.Sprintf(`SELECT u.id, u.username, u.tags, u.email, u.metadata, u.status, u.role, u.first_name, u.last_name,
|
||||
q := fmt.Sprintf(`SELECT u.id, u.username, u.tags, u.email, u.public_metadata, u.status, u.role, u.first_name, u.last_name,
|
||||
u.created_at, u.updated_at, COALESCE(u.updated_by, '') AS updated_by FROM users u %s LIMIT :limit OFFSET :offset;`, squery)
|
||||
dbPage, err := ToDBUsersPage(pm)
|
||||
if err != nil {
|
||||
@@ -421,7 +425,7 @@ func (repo *userRepo) RetrieveAllByIDs(ctx context.Context, pm users.Page) (user
|
||||
}
|
||||
|
||||
func (repo *userRepo) RetrieveByEmail(ctx context.Context, email string) (users.User, error) {
|
||||
q := `SELECT id, tags, email, secret, metadata, created_at, updated_at, updated_by, status, role, first_name, last_name, username, verified_at, auth_provider
|
||||
q := `SELECT id, tags, email, secret, metadata, public_metadata, created_at, updated_at, updated_by, status, role, first_name, last_name, username, verified_at, auth_provider
|
||||
FROM users WHERE email = :email AND status = :status`
|
||||
|
||||
dbu := DBUser{
|
||||
@@ -448,7 +452,7 @@ func (repo *userRepo) RetrieveByEmail(ctx context.Context, email string) (users.
|
||||
}
|
||||
|
||||
func (repo *userRepo) RetrieveByUsername(ctx context.Context, username string) (users.User, error) {
|
||||
q := `SELECT id, tags, email, secret, metadata, created_at, updated_at, updated_by, status, role, first_name, last_name, username, verified_at, auth_provider
|
||||
q := `SELECT id, tags, email, secret, metadata, public_metadata, created_at, updated_at, updated_by, status, role, first_name, last_name, username, verified_at, auth_provider
|
||||
FROM users WHERE username = :username AND status = :status`
|
||||
|
||||
dbu := DBUser{
|
||||
@@ -479,6 +483,7 @@ type DBUser struct {
|
||||
Domain string `db:"domain_id"`
|
||||
Secret string `db:"secret"`
|
||||
Metadata []byte `db:"metadata,omitempty"`
|
||||
PublicMetadata []byte `db:"public_metadata,omitempty"`
|
||||
Tags pgtype.TextArray `db:"tags,omitempty"` // Tags
|
||||
CreatedAt time.Time `db:"created_at,omitempty"`
|
||||
UpdatedAt sql.NullTime `db:"updated_at,omitempty"`
|
||||
@@ -496,13 +501,21 @@ type DBUser struct {
|
||||
}
|
||||
|
||||
func toDBUser(u users.User) (DBUser, error) {
|
||||
data := []byte("{}")
|
||||
publicMetadata := []byte("{}")
|
||||
if len(u.PublicMetadata) > 0 {
|
||||
b, err := json.Marshal(u.PublicMetadata)
|
||||
if err != nil {
|
||||
return DBUser{}, errors.Wrap(repoerr.ErrMalformedEntity, err)
|
||||
}
|
||||
publicMetadata = b
|
||||
}
|
||||
metadata := []byte("{}")
|
||||
if len(u.Metadata) > 0 {
|
||||
b, err := json.Marshal(u.Metadata)
|
||||
if err != nil {
|
||||
return DBUser{}, errors.Wrap(repoerr.ErrMalformedEntity, err)
|
||||
}
|
||||
data = b
|
||||
metadata = b
|
||||
}
|
||||
var tags pgtype.TextArray
|
||||
if err := tags.Set(u.Tags); err != nil {
|
||||
@@ -530,7 +543,8 @@ func toDBUser(u users.User) (DBUser, error) {
|
||||
ID: u.ID,
|
||||
Tags: tags,
|
||||
Secret: u.Credentials.Secret,
|
||||
Metadata: data,
|
||||
Metadata: metadata,
|
||||
PublicMetadata: publicMetadata,
|
||||
CreatedAt: u.CreatedAt,
|
||||
UpdatedAt: updatedAt,
|
||||
UpdatedBy: updatedBy,
|
||||
@@ -547,7 +561,12 @@ func toDBUser(u users.User) (DBUser, error) {
|
||||
}
|
||||
|
||||
func ToUser(dbu DBUser) (users.User, error) {
|
||||
var metadata users.Metadata
|
||||
var publicMetadata, metadata users.Metadata
|
||||
if dbu.PublicMetadata != nil {
|
||||
if err := json.Unmarshal([]byte(dbu.PublicMetadata), &publicMetadata); err != nil {
|
||||
return users.User{}, errors.Wrap(repoerr.ErrMalformedEntity, err)
|
||||
}
|
||||
}
|
||||
if dbu.Metadata != nil {
|
||||
if err := json.Unmarshal([]byte(dbu.Metadata), &metadata); err != nil {
|
||||
return users.User{}, errors.Wrap(repoerr.ErrMalformedEntity, err)
|
||||
@@ -585,6 +604,7 @@ func ToUser(dbu DBUser) (users.User, error) {
|
||||
},
|
||||
Email: dbu.Email,
|
||||
Metadata: metadata,
|
||||
PublicMetadata: publicMetadata,
|
||||
CreatedAt: dbu.CreatedAt.UTC(),
|
||||
UpdatedAt: updatedAt,
|
||||
UpdatedBy: updatedBy,
|
||||
@@ -639,11 +659,6 @@ func ToDBUsersPage(pm users.Page) (DBUsersPage, error) {
|
||||
}
|
||||
|
||||
func PageQuery(pm users.Page) (string, error) {
|
||||
mq, _, err := postgres.CreateMetadataQuery("", pm.Metadata)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(errors.ErrMalformedEntity, err)
|
||||
}
|
||||
|
||||
var query []string
|
||||
if pm.FirstName != "" {
|
||||
query = append(query, "first_name ILIKE '%' || :first_name || '%'")
|
||||
@@ -666,9 +681,8 @@ func PageQuery(pm users.Page) (string, error) {
|
||||
if pm.Role != users.AllRole {
|
||||
query = append(query, "u.role = :role")
|
||||
}
|
||||
|
||||
if mq != "" {
|
||||
query = append(query, mq)
|
||||
if len(pm.Metadata) > 0 {
|
||||
query = append(query, "public_metadata @> :metadata")
|
||||
}
|
||||
|
||||
if len(pm.IDs) != 0 {
|
||||
|
||||
+126
-57
@@ -20,7 +20,11 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const maxNameSize = 254
|
||||
const (
|
||||
maxNameSize = 254
|
||||
defOrder = "created_at"
|
||||
defDir = "asc"
|
||||
)
|
||||
|
||||
var (
|
||||
invalidName = strings.Repeat("m", maxNameSize+10)
|
||||
@@ -49,10 +53,11 @@ func TestUsersSave(t *testing.T) {
|
||||
email := first_name + "@example.com"
|
||||
|
||||
externalUser := users.User{
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
FirstName: namesgen.Generate(),
|
||||
LastName: namesgen.Generate(),
|
||||
Metadata: users.Metadata{},
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
FirstName: namesgen.Generate(),
|
||||
LastName: namesgen.Generate(),
|
||||
PublicMetadata: users.Metadata{},
|
||||
Metadata: users.Metadata{},
|
||||
Credentials: users.Credentials{
|
||||
Username: namesgen.Generate(),
|
||||
},
|
||||
@@ -75,8 +80,13 @@ func TestUsersSave(t *testing.T) {
|
||||
Username: username,
|
||||
Secret: password,
|
||||
},
|
||||
Metadata: users.Metadata{},
|
||||
Status: users.EnabledStatus,
|
||||
PublicMetadata: users.Metadata{
|
||||
"organization": namesgen.Generate(),
|
||||
},
|
||||
Metadata: users.Metadata{
|
||||
"address": namesgen.Generate(),
|
||||
},
|
||||
Status: users.EnabledStatus,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
@@ -96,8 +106,13 @@ func TestUsersSave(t *testing.T) {
|
||||
Username: namesgen.Generate(),
|
||||
Secret: password,
|
||||
},
|
||||
Metadata: users.Metadata{},
|
||||
Status: users.EnabledStatus,
|
||||
PublicMetadata: users.Metadata{
|
||||
"organization": namesgen.Generate(),
|
||||
},
|
||||
Metadata: users.Metadata{
|
||||
"address": namesgen.Generate(),
|
||||
},
|
||||
Status: users.EnabledStatus,
|
||||
},
|
||||
err: errors.ErrEmailAlreadyExists,
|
||||
},
|
||||
@@ -112,8 +127,13 @@ func TestUsersSave(t *testing.T) {
|
||||
Username: username,
|
||||
Secret: password,
|
||||
},
|
||||
Metadata: users.Metadata{},
|
||||
Status: users.EnabledStatus,
|
||||
PublicMetadata: users.Metadata{
|
||||
"organization": namesgen.Generate(),
|
||||
},
|
||||
Metadata: users.Metadata{
|
||||
"address": namesgen.Generate(),
|
||||
},
|
||||
Status: users.EnabledStatus,
|
||||
},
|
||||
err: errors.ErrUsernameNotAvailable,
|
||||
},
|
||||
@@ -128,8 +148,13 @@ func TestUsersSave(t *testing.T) {
|
||||
Username: username,
|
||||
Secret: password,
|
||||
},
|
||||
Metadata: users.Metadata{},
|
||||
Status: users.EnabledStatus,
|
||||
PublicMetadata: users.Metadata{
|
||||
"organization": namesgen.Generate(),
|
||||
},
|
||||
Metadata: users.Metadata{
|
||||
"address": namesgen.Generate(),
|
||||
},
|
||||
Status: users.EnabledStatus,
|
||||
},
|
||||
err: repoerr.ErrCreateEntity,
|
||||
},
|
||||
@@ -144,8 +169,13 @@ func TestUsersSave(t *testing.T) {
|
||||
Username: invalidName,
|
||||
Secret: password,
|
||||
},
|
||||
Metadata: users.Metadata{},
|
||||
Status: users.EnabledStatus,
|
||||
PublicMetadata: users.Metadata{
|
||||
"organization": namesgen.Generate(),
|
||||
},
|
||||
Metadata: users.Metadata{
|
||||
"address": namesgen.Generate(),
|
||||
},
|
||||
Status: users.EnabledStatus,
|
||||
},
|
||||
err: repoerr.ErrCreateEntity,
|
||||
},
|
||||
@@ -159,7 +189,12 @@ func TestUsersSave(t *testing.T) {
|
||||
Credentials: users.Credentials{
|
||||
Secret: password,
|
||||
},
|
||||
Metadata: users.Metadata{},
|
||||
PublicMetadata: users.Metadata{
|
||||
"organization": namesgen.Generate(),
|
||||
},
|
||||
Metadata: users.Metadata{
|
||||
"address": namesgen.Generate(),
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
@@ -173,7 +208,12 @@ func TestUsersSave(t *testing.T) {
|
||||
Credentials: users.Credentials{
|
||||
Username: namesgen.Generate(),
|
||||
},
|
||||
Metadata: users.Metadata{},
|
||||
PublicMetadata: users.Metadata{
|
||||
"organization": namesgen.Generate(),
|
||||
},
|
||||
Metadata: users.Metadata{
|
||||
"address": namesgen.Generate(),
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
@@ -187,7 +227,7 @@ func TestUsersSave(t *testing.T) {
|
||||
Username: username,
|
||||
Secret: password,
|
||||
},
|
||||
Metadata: map[string]any{
|
||||
PublicMetadata: map[string]any{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
@@ -236,9 +276,10 @@ func TestIsPlatformAdmin(t *testing.T) {
|
||||
Username: username,
|
||||
Secret: password,
|
||||
},
|
||||
Metadata: users.Metadata{},
|
||||
Status: users.EnabledStatus,
|
||||
Role: users.AdminRole,
|
||||
PublicMetadata: users.Metadata{},
|
||||
Metadata: users.Metadata{},
|
||||
Status: users.EnabledStatus,
|
||||
Role: users.AdminRole,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
@@ -253,9 +294,10 @@ func TestIsPlatformAdmin(t *testing.T) {
|
||||
Username: namesgen.Generate(),
|
||||
Secret: password,
|
||||
},
|
||||
Metadata: users.Metadata{},
|
||||
Status: users.EnabledStatus,
|
||||
Role: users.UserRole,
|
||||
PublicMetadata: users.Metadata{},
|
||||
Metadata: users.Metadata{},
|
||||
Status: users.EnabledStatus,
|
||||
Role: users.UserRole,
|
||||
},
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
@@ -286,18 +328,24 @@ func TestRetrieveByID(t *testing.T) {
|
||||
Username: namesgen.Generate(),
|
||||
Secret: password,
|
||||
},
|
||||
Metadata: users.Metadata{},
|
||||
Status: users.EnabledStatus,
|
||||
PublicMetadata: users.Metadata{
|
||||
"organization": namesgen.Generate(),
|
||||
},
|
||||
Metadata: users.Metadata{
|
||||
"address": namesgen.Generate(),
|
||||
},
|
||||
Status: users.EnabledStatus,
|
||||
}
|
||||
|
||||
_, err := repo.Save(context.Background(), user)
|
||||
require.Nil(t, err, fmt.Sprintf("failed to save users %s", user.ID))
|
||||
|
||||
externalUser := users.User{
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
FirstName: namesgen.Generate(),
|
||||
LastName: namesgen.Generate(),
|
||||
Metadata: users.Metadata{},
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
FirstName: namesgen.Generate(),
|
||||
LastName: namesgen.Generate(),
|
||||
PublicMetadata: users.Metadata{},
|
||||
Metadata: users.Metadata{},
|
||||
Credentials: users.Credentials{
|
||||
Username: namesgen.Generate(),
|
||||
},
|
||||
@@ -369,14 +417,14 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Username: namesgen.Generate(),
|
||||
Secret: "",
|
||||
},
|
||||
Metadata: users.Metadata{},
|
||||
Status: users.EnabledStatus,
|
||||
Tags: []string{"tag1"},
|
||||
CreatedAt: baseTime.Add(time.Duration(i) * time.Millisecond),
|
||||
UpdatedAt: baseTime.Add(time.Duration(i) * time.Millisecond),
|
||||
PublicMetadata: users.Metadata{},
|
||||
Status: users.EnabledStatus,
|
||||
Tags: []string{"tag1"},
|
||||
CreatedAt: baseTime.Add(time.Duration(i) * time.Millisecond),
|
||||
UpdatedAt: baseTime.Add(time.Duration(i) * time.Millisecond),
|
||||
}
|
||||
if i%50 == 0 {
|
||||
user.Metadata = map[string]any{
|
||||
user.PublicMetadata = map[string]any{
|
||||
"key": "value",
|
||||
}
|
||||
user.Role = users.AdminRole
|
||||
@@ -405,7 +453,7 @@ func TestRetrieveAll(t *testing.T) {
|
||||
desc: "retrieve first page of users",
|
||||
pageMeta: users.Page{
|
||||
Offset: 0,
|
||||
Limit: 50,
|
||||
Limit: 1,
|
||||
Role: users.AllRole,
|
||||
Status: users.AllStatus,
|
||||
Order: "created_at",
|
||||
@@ -415,9 +463,9 @@ func TestRetrieveAll(t *testing.T) {
|
||||
Page: users.Page{
|
||||
Total: 200,
|
||||
Offset: 0,
|
||||
Limit: 50,
|
||||
Limit: 1,
|
||||
},
|
||||
Users: items[0:50],
|
||||
Users: items[0:1],
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
@@ -689,7 +737,7 @@ func TestRetrieveAll(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "retrieve with metadata",
|
||||
desc: "retrieve with public metadata",
|
||||
pageMeta: users.Page{
|
||||
Metadata: map[string]any{
|
||||
"key": "value",
|
||||
@@ -963,7 +1011,8 @@ func TestSearch(t *testing.T) {
|
||||
Credentials: users.Credentials{
|
||||
Username: user.Credentials.Username,
|
||||
},
|
||||
CreatedAt: user.CreatedAt,
|
||||
PublicMetadata: user.PublicMetadata,
|
||||
CreatedAt: user.CreatedAt,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1026,15 +1075,17 @@ func TestSearch(t *testing.T) {
|
||||
desc: "retrieve all users",
|
||||
page: users.Page{
|
||||
Offset: 0,
|
||||
Limit: nUsers,
|
||||
Limit: 10,
|
||||
Order: defOrder,
|
||||
Dir: defDir,
|
||||
},
|
||||
response: users.UsersPage{
|
||||
Page: users.Page{
|
||||
Total: nUsers,
|
||||
Offset: 0,
|
||||
Limit: nUsers,
|
||||
Limit: 10,
|
||||
},
|
||||
Users: expectedUsers,
|
||||
Users: expectedUsers[:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1280,7 +1331,7 @@ func TestSearch(t *testing.T) {
|
||||
assert.Equal(t, c.response.Total, response.Total)
|
||||
assert.Equal(t, c.response.Limit, response.Limit)
|
||||
assert.Equal(t, c.response.Offset, response.Offset)
|
||||
assert.ElementsMatch(t, response.Users, c.response.Users)
|
||||
assert.ElementsMatch(t, response.Users, c.response.Users, fmt.Sprintf("expected %v got %v\n", c.response.Users, response.Users))
|
||||
default:
|
||||
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("expected %s to contain %s\n", err, c.err))
|
||||
}
|
||||
@@ -1470,11 +1521,23 @@ func TestUpdate(t *testing.T) {
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update malformed metadata for enabled user",
|
||||
update: "metadata",
|
||||
desc: "update public metadata for enabled user",
|
||||
update: "public_metadata",
|
||||
userID: user1.ID,
|
||||
userReq: users.UserReq{
|
||||
Metadata: &malformedMetadata,
|
||||
PublicMetadata: &updatedMetadata,
|
||||
},
|
||||
userRes: users.User{
|
||||
PublicMetadata: updatedMetadata,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update malformed public metadata for enabled user",
|
||||
update: "public_metadata",
|
||||
userID: user1.ID,
|
||||
userReq: users.UserReq{
|
||||
PublicMetadata: &malformedMetadata,
|
||||
},
|
||||
err: repoerr.ErrMalformedEntity,
|
||||
},
|
||||
@@ -1495,7 +1558,7 @@ func TestUpdate(t *testing.T) {
|
||||
update: "metadata",
|
||||
userID: user2.ID,
|
||||
userReq: users.UserReq{
|
||||
Metadata: &updatedMetadata,
|
||||
PublicMetadata: &updatedMetadata,
|
||||
},
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
@@ -1531,11 +1594,11 @@ func TestUpdate(t *testing.T) {
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
{
|
||||
desc: "update metadata for invalid user",
|
||||
update: "metadata",
|
||||
desc: "update public metadata for invalid user",
|
||||
update: "public_metadata",
|
||||
userID: testsutil.GenerateUUID(t),
|
||||
userReq: users.UserReq{
|
||||
Metadata: &updatedMetadata,
|
||||
PublicMetadata: &updatedMetadata,
|
||||
},
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
@@ -1678,6 +1741,8 @@ func TestUpdate(t *testing.T) {
|
||||
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("expected %s to contain %s\n", err, c.err))
|
||||
if err == nil {
|
||||
switch c.update {
|
||||
case "public_metadata":
|
||||
assert.Equal(t, c.userRes.PublicMetadata, expected.PublicMetadata)
|
||||
case "metadata":
|
||||
assert.Equal(t, c.userRes.Metadata, expected.Metadata)
|
||||
case "first_name":
|
||||
@@ -1955,6 +2020,7 @@ func TestRetrieveByIDs(t *testing.T) {
|
||||
baseTime := time.Now().UTC().Truncate(time.Millisecond)
|
||||
for i := 0; i < num; i++ {
|
||||
user := generateUserWithTime(t, users.EnabledStatus, repo, baseTime.Add(time.Duration(i)*time.Millisecond))
|
||||
user.Metadata = nil
|
||||
items = append(items, user)
|
||||
}
|
||||
|
||||
@@ -2117,7 +2183,7 @@ func TestRetrieveByIDs(t *testing.T) {
|
||||
page: users.Page{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Metadata: items[0].Metadata,
|
||||
Metadata: items[0].PublicMetadata,
|
||||
IDs: getIDs(items[0:20]),
|
||||
},
|
||||
response: users.UsersPage{
|
||||
@@ -2148,7 +2214,7 @@ func TestRetrieveByIDs(t *testing.T) {
|
||||
},
|
||||
Users: []users.User(nil),
|
||||
},
|
||||
err: errors.ErrMalformedEntity,
|
||||
err: repoerr.ErrViewEntity,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2210,7 +2276,7 @@ func TestRetrieveByEmail(t *testing.T) {
|
||||
assert.Equal(t, user.ID, usr.ID)
|
||||
assert.Equal(t, user.FirstName, usr.FirstName)
|
||||
assert.Equal(t, user.LastName, usr.LastName)
|
||||
assert.Equal(t, user.Metadata, usr.Metadata)
|
||||
assert.Equal(t, user.PublicMetadata, usr.PublicMetadata)
|
||||
assert.Equal(t, user.Email, usr.Email)
|
||||
assert.Equal(t, user.Credentials.Username, usr.Credentials.Username)
|
||||
assert.Equal(t, user.Status, usr.Status)
|
||||
@@ -2261,7 +2327,7 @@ func TestRetrieveByUsername(t *testing.T) {
|
||||
assert.Equal(t, user.ID, usr.ID)
|
||||
assert.Equal(t, user.FirstName, usr.FirstName)
|
||||
assert.Equal(t, user.LastName, usr.LastName)
|
||||
assert.Equal(t, user.Metadata, usr.Metadata)
|
||||
assert.Equal(t, user.PublicMetadata, usr.PublicMetadata)
|
||||
assert.Equal(t, user.Email, usr.Email)
|
||||
assert.Equal(t, user.Credentials.Username, usr.Credentials.Username)
|
||||
assert.Equal(t, user.Status, usr.Status)
|
||||
@@ -2304,8 +2370,11 @@ func generateUserWithTime(t *testing.T, status users.Status, repo users.Reposito
|
||||
Secret: testsutil.GenerateUUID(t),
|
||||
},
|
||||
Tags: namesgen.GenerateMultiple(5),
|
||||
PublicMetadata: users.Metadata{
|
||||
"organization": namesgen.Generate(),
|
||||
},
|
||||
Metadata: users.Metadata{
|
||||
"name": namesgen.Generate(),
|
||||
"address": namesgen.Generate(),
|
||||
},
|
||||
Status: status,
|
||||
CreatedAt: createdAt,
|
||||
|
||||
+5
-4
@@ -238,10 +238,11 @@ func (svc service) View(ctx context.Context, session authn.Session, id string) (
|
||||
if session.UserID != id {
|
||||
if err := svc.checkSuperAdmin(ctx, session); err != nil {
|
||||
return User{
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
ID: user.ID,
|
||||
Credentials: Credentials{Username: user.Credentials.Username},
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
ID: user.ID,
|
||||
PublicMetadata: user.PublicMetadata,
|
||||
Credentials: Credentials{Username: user.Credentials.Username},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
+60
-18
@@ -34,14 +34,15 @@ var (
|
||||
validCMetadata = users.Metadata{"role": "user"}
|
||||
userID = "d8dd12ef-aa2a-43fe-8ef2-2e4fe514360f"
|
||||
user = users.User{
|
||||
ID: userID,
|
||||
FirstName: "firstname",
|
||||
LastName: "lastname",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Credentials: users.Credentials{Username: "username", Secret: secret},
|
||||
Email: "useremail@email.com",
|
||||
Metadata: validCMetadata,
|
||||
Status: users.EnabledStatus,
|
||||
ID: userID,
|
||||
FirstName: "firstname",
|
||||
LastName: "lastname",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Credentials: users.Credentials{Username: "username", Secret: secret},
|
||||
Email: "useremail@email.com",
|
||||
Metadata: validCMetadata,
|
||||
PublicMetadata: validCMetadata,
|
||||
Status: users.EnabledStatus,
|
||||
}
|
||||
basicUser = users.User{
|
||||
Credentials: users.Credentials{
|
||||
@@ -127,6 +128,9 @@ func TestRegister(t *testing.T) {
|
||||
Credentials: users.Credentials{
|
||||
Secret: secret,
|
||||
},
|
||||
PublicMetadata: users.Metadata{
|
||||
"name": "newuserwithallfields",
|
||||
},
|
||||
Metadata: users.Metadata{
|
||||
"name": "newuserwithallfields",
|
||||
},
|
||||
@@ -518,6 +522,8 @@ func TestUpdateUser(t *testing.T) {
|
||||
updateFirstName := "Updated user"
|
||||
user1.FirstName = updateFirstName
|
||||
updatedMetadata := users.Metadata{"role": "test"}
|
||||
invalidMetadata := users.Metadata{"role": make(chan int)}
|
||||
user2.PublicMetadata = updatedMetadata
|
||||
user2.Metadata = updatedMetadata
|
||||
adminID := testsutil.GenerateUUID(t)
|
||||
|
||||
@@ -535,7 +541,7 @@ func TestUpdateUser(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "update user name successfully as normal user",
|
||||
desc: "update user name successfully as normal user",
|
||||
userID: user1.ID,
|
||||
userReq: users.UserReq{
|
||||
FirstName: &updateFirstName,
|
||||
@@ -546,6 +552,29 @@ func TestUpdateUser(t *testing.T) {
|
||||
token: validToken,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update public metadata successfully as normal user",
|
||||
userID: user2.ID,
|
||||
userReq: users.UserReq{
|
||||
PublicMetadata: &updatedMetadata,
|
||||
},
|
||||
session: authn.Session{UserID: user2.ID},
|
||||
updateResponse: user2,
|
||||
token: validToken,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update public metadata with repo error",
|
||||
userID: user2.ID,
|
||||
userReq: users.UserReq{
|
||||
PublicMetadata: &invalidMetadata,
|
||||
},
|
||||
session: authn.Session{UserID: user2.ID},
|
||||
updateResponse: users.User{},
|
||||
token: validToken,
|
||||
updateErr: errors.ErrMalformedEntity,
|
||||
err: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
{
|
||||
desc: "update metadata successfully as normal user",
|
||||
userID: user2.ID,
|
||||
@@ -558,6 +587,19 @@ func TestUpdateUser(t *testing.T) {
|
||||
token: validToken,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update metadata with repo error",
|
||||
userID: user2.ID,
|
||||
userReq: users.UserReq{
|
||||
Metadata: &invalidMetadata,
|
||||
},
|
||||
session: authn.Session{UserID: user2.ID},
|
||||
updateResponse: users.User{},
|
||||
retrieveByIDResp: user2,
|
||||
token: validToken,
|
||||
updateErr: errors.ErrMalformedEntity,
|
||||
err: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
{
|
||||
desc: "update user name as normal user with repo error on update",
|
||||
userID: user1.ID,
|
||||
@@ -584,10 +626,10 @@ func TestUpdateUser(t *testing.T) {
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update user metadata as admin successfully",
|
||||
desc: "update user public metadata as admin successfully",
|
||||
userID: user2.ID,
|
||||
userReq: users.UserReq{
|
||||
Metadata: &updatedMetadata,
|
||||
PublicMetadata: &updatedMetadata,
|
||||
},
|
||||
session: authn.Session{UserID: adminID, SuperAdmin: true},
|
||||
updateResponse: user2,
|
||||
@@ -651,18 +693,18 @@ func TestUpdateUser(t *testing.T) {
|
||||
desc: "update user metadata with external auth provider should succeed",
|
||||
userID: user2.ID,
|
||||
userReq: users.UserReq{
|
||||
Metadata: &updatedMetadata,
|
||||
PublicMetadata: &updatedMetadata,
|
||||
},
|
||||
session: authn.Session{UserID: user2.ID},
|
||||
retrieveByIDResp: users.User{
|
||||
ID: user2.ID,
|
||||
AuthProvider: "google",
|
||||
Metadata: updatedMetadata,
|
||||
ID: user2.ID,
|
||||
AuthProvider: "google",
|
||||
PublicMetadata: updatedMetadata,
|
||||
},
|
||||
updateResponse: users.User{
|
||||
ID: user2.ID,
|
||||
AuthProvider: "google",
|
||||
Metadata: updatedMetadata,
|
||||
ID: user2.ID,
|
||||
AuthProvider: "google",
|
||||
PublicMetadata: updatedMetadata,
|
||||
},
|
||||
token: validToken,
|
||||
err: nil,
|
||||
|
||||
@@ -20,6 +20,7 @@ type User struct {
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Metadata Metadata `json:"metadata,omitempty"`
|
||||
PublicMetadata Metadata `json:"public_metadata,omitempty"`
|
||||
Status Status `json:"status"` // 0 for enabled, 1 for disabled
|
||||
Role Role `json:"role"` // 0 for normal user, 1 for admin
|
||||
ProfilePicture string `json:"profile_picture,omitempty"` // profile picture URL
|
||||
@@ -50,6 +51,7 @@ type UserReq struct {
|
||||
FirstName *string `json:"first_name,omitempty"`
|
||||
LastName *string `json:"last_name,omitempty"`
|
||||
Metadata *Metadata `json:"metadata,omitempty"`
|
||||
PublicMetadata *Metadata `json:"public_metadata,omitempty"`
|
||||
Tags *[]string `json:"tags,omitempty"`
|
||||
ProfilePicture *string `json:"profile_picture,omitempty"`
|
||||
UpdatedBy *string `json:"updated_by,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user