feat: User metadata (#2025)

* feat: user meta data events

* feat: user meta data set tests

* feat: user meta data tests

* feat: user meta data in protos

* feat: user meta data command api

* feat: user meta data query side

* feat: proto correct order, fix handlers

* feat: proto correct order

* feat: fixes of pr comments

* feat: fixes of pr comments

* feat: value as byte array

* feat: metadata feature

* Update internal/auth/repository/eventsourcing/handler/meta_data.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update internal/command/user_meta_data.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update proto/zitadel/metadata.proto

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* Update proto/zitadel/metadata.proto

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* fix: rename metadata files and table

* fix: rename meta data to metadat in protos

* Update internal/domain/metadata.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* fix: rename vars

* fix: rebiuld docs

* Update internal/iam/repository/view/metadata_view.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

Co-authored-by: Silvan <silvan.reusser@gmail.com>
This commit is contained in:
Fabi
2021-08-09 08:01:20 +02:00
committed by GitHub
parent ae50f57c2c
commit 7451ed58f2
40 changed files with 3725 additions and 4 deletions

View File

@@ -0,0 +1,80 @@
package view
import (
"github.com/jinzhu/gorm"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
)
func GetMetadataList(db *gorm.DB, table string, aggregateID string) ([]*model.MetadataView, error) {
metadatas := make([]*model.MetadataView, 0)
queries := []*domain.MetadataSearchQuery{
{
Key: domain.MetadataSearchKeyAggregateID,
Value: aggregateID,
Method: domain.SearchMethodEquals,
},
}
query := repository.PrepareSearchQuery(table, model.MetadataSearchRequest{Queries: queries})
_, err := query(db, &metadatas)
if err != nil {
return nil, err
}
return metadatas, nil
}
func MetadataByKey(db *gorm.DB, table, aggregateID, key string) (*model.MetadataView, error) {
metadata := new(model.MetadataView)
aggregateIDQuery := &model.MetadataSearchQuery{Key: domain.MetadataSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
keyQuery := &model.MetadataSearchQuery{Key: domain.MetadataSearchKeyKey, Value: key, Method: domain.SearchMethodEquals}
query := repository.PrepareGetByQuery(table, aggregateIDQuery, keyQuery)
err := query(db, metadata)
if caos_errs.IsNotFound(err) {
return nil, caos_errs.ThrowNotFound(nil, "VIEW-29kkd", "Errors.Metadata.NotExisting")
}
return metadata, err
}
func MetadataByKeyAndResourceOwner(db *gorm.DB, table, aggregateID, resourceOwner, key string) (*model.MetadataView, error) {
metadata := new(model.MetadataView)
aggregateIDQuery := &model.MetadataSearchQuery{Key: domain.MetadataSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
resourceOwnerQuery := &model.MetadataSearchQuery{Key: domain.MetadataSearchKeyResourceOwner, Value: resourceOwner, Method: domain.SearchMethodEquals}
keyQuery := &model.MetadataSearchQuery{Key: domain.MetadataSearchKeyKey, Value: key, Method: domain.SearchMethodEquals}
query := repository.PrepareGetByQuery(table, aggregateIDQuery, resourceOwnerQuery, keyQuery)
err := query(db, metadata)
if caos_errs.IsNotFound(err) {
return nil, caos_errs.ThrowNotFound(nil, "VIEW-29kkd", "Errors.Metadata.NotExisting")
}
return metadata, err
}
func SearchMetadata(db *gorm.DB, table string, req *domain.MetadataSearchRequest) ([]*model.MetadataView, uint64, error) {
metadata := make([]*model.MetadataView, 0)
query := repository.PrepareSearchQuery(table, model.MetadataSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
count, err := query(db, &metadata)
if err != nil {
return nil, 0, err
}
return metadata, count, nil
}
func PutMetadata(db *gorm.DB, table string, customText *model.MetadataView) error {
save := repository.PrepareSave(table)
return save(db, customText)
}
func DeleteMetadata(db *gorm.DB, table, aggregateID, key string) error {
aggregateIDQuery := repository.Key{Key: model.MetadataSearchKey(domain.MetadataSearchKeyAggregateID), Value: aggregateID}
keyQuery := repository.Key{Key: model.MetadataSearchKey(domain.MetadataSearchKeyKey), Value: key}
delete := repository.PrepareDeleteByKeys(table, aggregateIDQuery, keyQuery)
return delete(db)
}
func DeleteMetadataByAggregateID(db *gorm.DB, table, aggregateID string) error {
aggregateIDQuery := repository.Key{Key: model.MetadataSearchKey(domain.MetadataSearchKeyAggregateID), Value: aggregateID}
delete := repository.PrepareDeleteByKeys(table, aggregateIDQuery)
return delete(db)
}

View File

@@ -30,10 +30,10 @@ type CustomTextView struct {
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
Template string `json:"Template" gorm:"column:template;primary_key"`
Language string `json:"Language" gorm:"column:language;primary_key"`
Key string `json:"Key" gorm:"column:key;primary_key"`
Text string `json:"Text" gorm:"column:text"`
Template string `json:"template" gorm:"column:template;primary_key"`
Language string `json:"language" gorm:"column:language;primary_key"`
Key string `json:"key" gorm:"column:key;primary_key"`
Text string `json:"text" gorm:"column:text"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
}

View File

@@ -0,0 +1,79 @@
package model
import (
"encoding/json"
"time"
"github.com/caos/zitadel/internal/domain"
usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1/models"
)
const (
MetadataKeyAggregateID = "aggregate_id"
MetadataKeyResourceOwner = "resource_owner"
MetadataKeyKey = "key"
MetadataKeyValue = "value"
)
type MetadataView struct {
AggregateID string `json:"-" gorm:"column:aggregate_id;primary_key"`
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
Key string `json:"key" gorm:"column:key;primary_key"`
Value []byte `json:"value" gorm:"column:value"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
}
func MetadataViewsToDomain(texts []*MetadataView) []*domain.Metadata {
result := make([]*domain.Metadata, len(texts))
for i, text := range texts {
result[i] = MetadataViewToDomain(text)
}
return result
}
func MetadataViewToDomain(data *MetadataView) *domain.Metadata {
return &domain.Metadata{
ObjectRoot: models.ObjectRoot{
AggregateID: data.AggregateID,
Sequence: data.Sequence,
CreationDate: data.CreationDate,
ChangeDate: data.ChangeDate,
},
Key: data.Key,
Value: data.Value,
}
}
func (md *MetadataView) AppendEvent(event *models.Event) (err error) {
md.Sequence = event.Sequence
switch event.Type {
case usr_model.UserMetadataSet:
md.setRootData(event)
err = md.SetData(event)
}
return err
}
func (md *MetadataView) setRootData(event *models.Event) {
md.AggregateID = event.AggregateID
md.ResourceOwner = event.ResourceOwner
md.ChangeDate = event.CreationDate
md.Sequence = event.Sequence
}
func (md *MetadataView) SetData(event *models.Event) error {
if err := json.Unmarshal(event.Data, md); err != nil {
logging.Log("MODEL-3n9fs").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-5CVaR", "Could not unmarshal data")
}
return nil
}

View File

@@ -0,0 +1,64 @@
package model
import (
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/view/repository"
)
type MetadataSearchRequest domain.MetadataSearchRequest
type MetadataSearchQuery domain.MetadataSearchQuery
type MetadataSearchKey domain.MetadataSearchKey
func (req MetadataSearchRequest) GetLimit() uint64 {
return req.Limit
}
func (req MetadataSearchRequest) GetOffset() uint64 {
return req.Offset
}
func (req MetadataSearchRequest) GetSortingColumn() repository.ColumnKey {
if req.SortingColumn == domain.MetadataSearchKeyUnspecified {
return nil
}
return MetadataSearchKey(req.SortingColumn)
}
func (req MetadataSearchRequest) GetAsc() bool {
return req.Asc
}
func (req MetadataSearchRequest) GetQueries() []repository.SearchQuery {
result := make([]repository.SearchQuery, len(req.Queries))
for i, q := range req.Queries {
result[i] = MetadataSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
}
return result
}
func (req MetadataSearchQuery) GetKey() repository.ColumnKey {
return MetadataSearchKey(req.Key)
}
func (req MetadataSearchQuery) GetMethod() domain.SearchMethod {
return req.Method
}
func (req MetadataSearchQuery) GetValue() interface{} {
return req.Value
}
func (key MetadataSearchKey) ToColumnName() string {
switch domain.MetadataSearchKey(key) {
case domain.MetadataSearchKeyAggregateID:
return MetadataKeyAggregateID
case domain.MetadataSearchKeyResourceOwner:
return MetadataKeyResourceOwner
case domain.MetadataSearchKeyKey:
return MetadataKeyKey
case domain.MetadataSearchKeyValue:
return MetadataKeyValue
default:
return ""
}
}