mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:37:32 +00:00
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:
80
internal/iam/repository/view/metadata_view.go
Normal file
80
internal/iam/repository/view/metadata_view.go
Normal 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)
|
||||
}
|
@@ -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"`
|
||||
}
|
||||
|
79
internal/iam/repository/view/model/metadata.go
Normal file
79
internal/iam/repository/view/model/metadata.go
Normal 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
|
||||
}
|
64
internal/iam/repository/view/model/metadata_query.go
Normal file
64
internal/iam/repository/view/model/metadata_query.go
Normal 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 ""
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user