mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-07 23:07:45 +00:00
feat: store assets in database (#3290)
* feat: use database as asset storage * being only uploading assets if allowed * tests * fixes * cleanup after merge * renaming * various fixes * fix: change to repository event types and removed unused code * feat: set default features * error handling * error handling and naming * fix tests * fix tests * fix merge * rename
This commit is contained in:
parent
b949b8fc65
commit
4a0d61d75a
@ -2,21 +2,36 @@ package setup
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
command "github.com/caos/zitadel/internal/command/v2"
|
_ "embed"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DefaultInstance struct {
|
const (
|
||||||
cmd *command.Command
|
createAssets = `
|
||||||
InstanceSetup command.InstanceSetup
|
CREATE TABLE system.assets (
|
||||||
|
instance_id TEXT,
|
||||||
|
asset_type TEXT,
|
||||||
|
resource_owner TEXT,
|
||||||
|
name TEXT,
|
||||||
|
content_type TEXT,
|
||||||
|
hash TEXT AS (md5(data)) STORED,
|
||||||
|
data BYTES,
|
||||||
|
updated_at TIMESTAMPTZ,
|
||||||
|
|
||||||
|
PRIMARY KEY (instance_id, resource_owner, name)
|
||||||
|
);
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
type AssetTable struct {
|
||||||
|
dbClient *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mig *DefaultInstance) Execute(ctx context.Context) error {
|
func (mig *AssetTable) Execute(ctx context.Context) error {
|
||||||
_, err := mig.cmd.SetUpInstance(ctx, &mig.InstanceSetup)
|
_, err := mig.dbClient.ExecContext(ctx, createAssets)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mig *DefaultInstance) String() string {
|
func (mig *AssetTable) String() string {
|
||||||
return "02_default_instance"
|
return "02_assets"
|
||||||
}
|
}
|
||||||
|
22
cmd/admin/setup/03.go
Normal file
22
cmd/admin/setup/03.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package setup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DefaultInstance struct {
|
||||||
|
cmd *command.Command
|
||||||
|
InstanceSetup command.InstanceSetup
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mig *DefaultInstance) Execute(ctx context.Context) error {
|
||||||
|
_, err := mig.cmd.SetUpInstance(ctx, &mig.InstanceSetup)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mig *DefaultInstance) String() string {
|
||||||
|
return "03_default_instance"
|
||||||
|
}
|
@ -35,8 +35,9 @@ func MustNewConfig(v *viper.Viper) *Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Steps struct {
|
type Steps struct {
|
||||||
S1ProjectionTable *ProjectionTable
|
s1ProjectionTable *ProjectionTable
|
||||||
S2DefaultInstance *DefaultInstance
|
s2AssetsTable *AssetTable
|
||||||
|
S3DefaultInstance *DefaultInstance
|
||||||
}
|
}
|
||||||
|
|
||||||
func MustNewSteps(v *viper.Viper) *Steps {
|
func MustNewSteps(v *viper.Viper) *Steps {
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
http_util "github.com/caos/zitadel/internal/api/http"
|
http_util "github.com/caos/zitadel/internal/api/http"
|
||||||
command "github.com/caos/zitadel/internal/command/v2"
|
"github.com/caos/zitadel/internal/command/v2"
|
||||||
"github.com/caos/zitadel/internal/database"
|
"github.com/caos/zitadel/internal/database"
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
"github.com/caos/zitadel/internal/migration"
|
"github.com/caos/zitadel/internal/migration"
|
||||||
@ -46,12 +46,14 @@ func Setup(config *Config, steps *Steps) {
|
|||||||
|
|
||||||
cmd := command.New(eventstoreClient, "localhost", config.SystemDefaults)
|
cmd := command.New(eventstoreClient, "localhost", config.SystemDefaults)
|
||||||
|
|
||||||
steps.S2DefaultInstance.cmd = cmd
|
steps.s1ProjectionTable = &ProjectionTable{dbClient: dbClient}
|
||||||
steps.S1ProjectionTable = &ProjectionTable{dbClient: dbClient}
|
steps.s2AssetsTable = &AssetTable{dbClient: dbClient}
|
||||||
steps.S2DefaultInstance.InstanceSetup.Zitadel.IsDevMode = !config.ExternalSecure
|
steps.S3DefaultInstance.cmd = cmd
|
||||||
steps.S2DefaultInstance.InstanceSetup.Zitadel.BaseURL = http_util.BuildHTTP(config.ExternalDomain, config.ExternalPort, config.ExternalSecure)
|
steps.S3DefaultInstance.InstanceSetup.Zitadel.IsDevMode = !config.ExternalSecure
|
||||||
|
steps.S3DefaultInstance.InstanceSetup.Zitadel.BaseURL = http_util.BuildHTTP(config.ExternalDomain, config.ExternalPort, config.ExternalSecure)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
migration.Migrate(ctx, eventstoreClient, steps.S1ProjectionTable)
|
migration.Migrate(ctx, eventstoreClient, steps.s1ProjectionTable)
|
||||||
migration.Migrate(ctx, eventstoreClient, steps.S2DefaultInstance)
|
migration.Migrate(ctx, eventstoreClient, steps.s2AssetsTable)
|
||||||
|
migration.Migrate(ctx, eventstoreClient, steps.S3DefaultInstance)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
S2DefaultInstance:
|
S3DefaultInstance:
|
||||||
InstanceSetup:
|
InstanceSetup:
|
||||||
Org:
|
Org:
|
||||||
Name: ZITADEL
|
Name: ZITADEL
|
||||||
@ -13,6 +13,29 @@ S2DefaultInstance:
|
|||||||
Gender:
|
Gender:
|
||||||
Phone:
|
Phone:
|
||||||
Password: Password1!
|
Password: Password1!
|
||||||
|
Features:
|
||||||
|
TierName: Default Tier
|
||||||
|
TierDescription: ""
|
||||||
|
State: 1 #active
|
||||||
|
StateDescription: ""
|
||||||
|
Retention: 8760h #1year
|
||||||
|
LoginPolicyFactors: true
|
||||||
|
LoginPolicyIDP: true
|
||||||
|
LoginPolicyPasswordless: true
|
||||||
|
LoginPolicyRegistration: true
|
||||||
|
LoginPolicyUsernameLogin: true
|
||||||
|
LoginPolicyPasswordReset: true
|
||||||
|
PasswordComplexityPolicy: true
|
||||||
|
LabelPolicyPrivateLabel: true
|
||||||
|
LabelPolicyWatermark: true
|
||||||
|
CustomDomain: true
|
||||||
|
PrivacyPolicy: true
|
||||||
|
MetadataUser: true
|
||||||
|
CustomTextMessage: true
|
||||||
|
CustomTextLogin: true
|
||||||
|
LockoutPolicy: true
|
||||||
|
ActionsAllowed: 2 #ActionsAllowedUnlimited
|
||||||
|
MaxActions: #not necessary because of ActionsAllowedUnlimited
|
||||||
PasswordComplexityPolicy:
|
PasswordComplexityPolicy:
|
||||||
MinLength: 8
|
MinLength: 8
|
||||||
HasLowercase: true
|
HasLowercase: true
|
||||||
|
@ -94,12 +94,6 @@ func startZitadel(config *Config, masterKey string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var storage static.Storage
|
|
||||||
//TODO: enable when storage is implemented again
|
|
||||||
//if *assetsEnabled {
|
|
||||||
//storage, err = config.AssetStorage.Config.NewStorage()
|
|
||||||
//logging.Log("MAIN-Bfhe2").OnError(err).Fatal("Unable to start asset storage")
|
|
||||||
//}
|
|
||||||
eventstoreClient, err := eventstore.Start(dbClient)
|
eventstoreClient, err := eventstore.Start(dbClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot start eventstore for queries: %w", err)
|
return fmt.Errorf("cannot start eventstore for queries: %w", err)
|
||||||
@ -114,6 +108,11 @@ func startZitadel(config *Config, masterKey string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error starting authz repo: %w", err)
|
return fmt.Errorf("error starting authz repo: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
storage, err := config.AssetStorage.NewStorage(dbClient)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot start asset storage client: %w", err)
|
||||||
|
}
|
||||||
webAuthNConfig := webauthn.Config{
|
webAuthNConfig := webauthn.Config{
|
||||||
ID: config.ExternalDomain,
|
ID: config.ExternalDomain,
|
||||||
Origin: http_util.BuildHTTP(config.ExternalDomain, config.ExternalPort, config.ExternalSecure),
|
Origin: http_util.BuildHTTP(config.ExternalDomain, config.ExternalPort, config.ExternalSecure),
|
||||||
@ -163,13 +162,13 @@ func startAPIs(ctx context.Context, router *mux.Router, commands *command.Comman
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
apis.RegisterHandler(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.InternalAuthZ, id.SonyFlakeGenerator, store, queries))
|
instanceInterceptor := middleware.InstanceInterceptor(queries, config.HTTP1HostHeader)
|
||||||
|
apis.RegisterHandler(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.InternalAuthZ, id.SonyFlakeGenerator, store, queries, instanceInterceptor.Handler))
|
||||||
|
|
||||||
userAgentInterceptor, err := middleware.NewUserAgentHandler(config.UserAgentCookie, keys.UserAgentCookieKey, config.ExternalDomain, id.SonyFlakeGenerator, config.ExternalSecure)
|
userAgentInterceptor, err := middleware.NewUserAgentHandler(config.UserAgentCookie, keys.UserAgentCookieKey, config.ExternalDomain, id.SonyFlakeGenerator, config.ExternalSecure)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
instanceInterceptor := middleware.InstanceInterceptor(queries, config.HTTP1HostHeader)
|
|
||||||
|
|
||||||
issuer := oidc.Issuer(config.ExternalDomain, config.ExternalPort, config.ExternalSecure)
|
issuer := oidc.Issuer(config.ExternalDomain, config.ExternalPort, config.ExternalSecure)
|
||||||
oidcProvider, err := oidc.NewProvider(ctx, config.OIDC, issuer, login.DefaultLoggedOutPath, commands, queries, authRepo, config.SystemDefaults.KeyConfig, keys.OIDC, keys.OIDCKey, eventstore, dbClient, keyChan, userAgentInterceptor, instanceInterceptor.Handler)
|
oidcProvider, err := oidc.NewProvider(ctx, config.OIDC, issuer, login.DefaultLoggedOutPath, commands, queries, authRepo, config.SystemDefaults.KeyConfig, keys.OIDC, keys.OIDCKey, eventstore, dbClient, keyChan, userAgentInterceptor, instanceInterceptor.Handler)
|
||||||
|
@ -163,7 +163,7 @@ func (m *Styling) generateStylingFile(policy *iam_model.LabelPolicyView) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return m.uploadFilesToBucket(policy.AggregateID, "text/css", reader, size)
|
return m.uploadFilesToStorage(policy.InstanceID, policy.AggregateID, "text/css", reader, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Styling) writeFile(policy *iam_model.LabelPolicyView) (io.Reader, int64, error) {
|
func (m *Styling) writeFile(policy *iam_model.LabelPolicyView) (io.Reader, int64, error) {
|
||||||
@ -245,9 +245,10 @@ const fontFaceTemplate = `
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
func (m *Styling) uploadFilesToBucket(aggregateID, contentType string, reader io.Reader, size int64) error {
|
func (m *Styling) uploadFilesToStorage(instanceID, aggregateID, contentType string, reader io.Reader, size int64) error {
|
||||||
fileName := domain.CssPath + "/" + domain.CssVariablesFileName
|
fileName := domain.CssPath + "/" + domain.CssVariablesFileName
|
||||||
_, err := m.static.PutObject(context.Background(), aggregateID, fileName, contentType, reader, size, true)
|
//TODO: handle location as soon as possible
|
||||||
|
_, err := m.static.PutObject(context.Background(), instanceID, "", aggregateID, fileName, contentType, static.ObjectTypeStyling, reader, size)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,24 +1,21 @@
|
|||||||
package assets
|
package assets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
sentryhttp "github.com/getsentry/sentry-go/http"
|
sentryhttp "github.com/getsentry/sentry-go/http"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/superseriousbusiness/exifremove/pkg/exifremove"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/api/authz"
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
|
http_util "github.com/caos/zitadel/internal/api/http"
|
||||||
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
|
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
|
||||||
"github.com/caos/zitadel/internal/command"
|
"github.com/caos/zitadel/internal/command"
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/id"
|
"github.com/caos/zitadel/internal/id"
|
||||||
"github.com/caos/zitadel/internal/query"
|
"github.com/caos/zitadel/internal/query"
|
||||||
"github.com/caos/zitadel/internal/static"
|
"github.com/caos/zitadel/internal/static"
|
||||||
@ -54,26 +51,27 @@ func (h *Handler) Storage() static.Storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Uploader interface {
|
type Uploader interface {
|
||||||
Callback(ctx context.Context, info *domain.AssetInfo, orgID string, commands *command.Commands) error
|
UploadAsset(ctx context.Context, info string, asset *command.AssetUpload, commands *command.Commands) error
|
||||||
ObjectName(data authz.CtxData) (string, error)
|
ObjectName(data authz.CtxData) (string, error)
|
||||||
BucketName(data authz.CtxData) string
|
ResourceOwner(instance authz.Instance, data authz.CtxData) string
|
||||||
ContentTypeAllowed(contentType string) bool
|
ContentTypeAllowed(contentType string) bool
|
||||||
MaxFileSize() int64
|
MaxFileSize() int64
|
||||||
|
ObjectType() static.ObjectType
|
||||||
}
|
}
|
||||||
|
|
||||||
type Downloader interface {
|
type Downloader interface {
|
||||||
ObjectName(ctx context.Context, path string) (string, error)
|
ObjectName(ctx context.Context, path string) (string, error)
|
||||||
BucketName(ctx context.Context, id string) string
|
ResourceOwner(ctx context.Context, ownerPath string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ErrorHandler func(http.ResponseWriter, *http.Request, error, int)
|
type ErrorHandler func(http.ResponseWriter, *http.Request, error, int)
|
||||||
|
|
||||||
func DefaultErrorHandler(w http.ResponseWriter, r *http.Request, err error, code int) {
|
func DefaultErrorHandler(w http.ResponseWriter, r *http.Request, err error, code int) {
|
||||||
logging.Log("ASSET-g5ef1").WithError(err).WithField("uri", r.RequestURI).Error("error occurred on asset api")
|
logging.WithFields("uri", r.RequestURI).WithError(err).Warn("error occurred on asset api")
|
||||||
http.Error(w, err.Error(), code)
|
http.Error(w, err.Error(), code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(commands *command.Commands, verifier *authz.TokenVerifier, authConfig authz.Config, idGenerator id.Generator, storage static.Storage, queries *query.Queries) http.Handler {
|
func NewHandler(commands *command.Commands, verifier *authz.TokenVerifier, authConfig authz.Config, idGenerator id.Generator, storage static.Storage, queries *query.Queries, instanceInterceptor func(handler http.Handler) http.Handler) http.Handler {
|
||||||
h := &Handler{
|
h := &Handler{
|
||||||
commands: commands,
|
commands: commands,
|
||||||
errorHandler: DefaultErrorHandler,
|
errorHandler: DefaultErrorHandler,
|
||||||
@ -85,9 +83,9 @@ func NewHandler(commands *command.Commands, verifier *authz.TokenVerifier, authC
|
|||||||
|
|
||||||
verifier.RegisterServer("Management-API", "assets", AssetsService_AuthMethods) //TODO: separate api?
|
verifier.RegisterServer("Management-API", "assets", AssetsService_AuthMethods) //TODO: separate api?
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
router.Use(sentryhttp.New(sentryhttp.Options{}).Handle)
|
router.Use(sentryhttp.New(sentryhttp.Options{}).Handle, instanceInterceptor)
|
||||||
RegisterRoutes(router, h)
|
RegisterRoutes(router, h)
|
||||||
router.PathPrefix("/{id}").Methods("GET").HandlerFunc(DownloadHandleFunc(h, h.GetFile()))
|
router.PathPrefix("/{owner}").Methods("GET").HandlerFunc(DownloadHandleFunc(h, h.GetFile()))
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,8 +99,8 @@ func (l *publicFileDownloader) ObjectName(_ context.Context, path string) (strin
|
|||||||
return path, nil
|
return path, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *publicFileDownloader) BucketName(_ context.Context, id string) string {
|
func (l *publicFileDownloader) ResourceOwner(_ context.Context, ownerPath string) string {
|
||||||
return id
|
return ownerPath
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxMemory = 2 << 20
|
const maxMemory = 2 << 20
|
||||||
@ -120,7 +118,7 @@ func UploadHandleFunc(s AssetsService, uploader Uploader) func(http.ResponseWrit
|
|||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
err = file.Close()
|
err = file.Close()
|
||||||
logging.Log("UPLOAD-GDg34").OnError(err).Warn("could not close file")
|
logging.OnError(err).Warn("could not close file")
|
||||||
}()
|
}()
|
||||||
contentType := handler.Header.Get("content-type")
|
contentType := handler.Header.Get("content-type")
|
||||||
size := handler.Size
|
size := handler.Size
|
||||||
@ -133,24 +131,21 @@ func UploadHandleFunc(s AssetsService, uploader Uploader) func(http.ResponseWrit
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bucketName := uploader.BucketName(ctxData)
|
resourceOwner := uploader.ResourceOwner(authz.GetInstance(ctx), ctxData)
|
||||||
objectName, err := uploader.ObjectName(ctxData)
|
objectName, err := uploader.ObjectName(ctxData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError)
|
s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cleanedFile, cleanedSize, err := removeExif(file, size, contentType)
|
uploadInfo := &command.AssetUpload{
|
||||||
if err != nil {
|
ResourceOwner: resourceOwner,
|
||||||
s.ErrorHandler()(w, r, fmt.Errorf("remove exif error: %v", err), http.StatusInternalServerError)
|
ObjectName: objectName,
|
||||||
return
|
ContentType: contentType,
|
||||||
|
ObjectType: uploader.ObjectType(),
|
||||||
|
File: file,
|
||||||
|
Size: size,
|
||||||
}
|
}
|
||||||
|
err = uploader.UploadAsset(ctx, ctxData.OrgID, uploadInfo, s.Commands())
|
||||||
info, err := s.Commands().UploadAsset(ctx, bucketName, objectName, contentType, cleanedFile, cleanedSize)
|
|
||||||
if err != nil {
|
|
||||||
s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = uploader.Callback(ctx, info, ctxData.OrgID, s.Commands())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError)
|
s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -164,11 +159,11 @@ func DownloadHandleFunc(s AssetsService, downloader Downloader) func(http.Respon
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
id := mux.Vars(r)["id"]
|
ownerPath := mux.Vars(r)["owner"]
|
||||||
bucketName := downloader.BucketName(ctx, id)
|
resourceOwner := downloader.ResourceOwner(ctx, ownerPath)
|
||||||
path := ""
|
path := ""
|
||||||
if id != "" {
|
if ownerPath != "" {
|
||||||
path = strings.Split(r.RequestURI, id+"/")[1]
|
path = strings.Split(r.RequestURI, ownerPath+"/")[1]
|
||||||
}
|
}
|
||||||
objectName, err := downloader.ObjectName(ctx, path)
|
objectName, err := downloader.ObjectName(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -176,49 +171,33 @@ func DownloadHandleFunc(s AssetsService, downloader Downloader) func(http.Respon
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if objectName == "" {
|
if objectName == "" {
|
||||||
s.ErrorHandler()(w, r, fmt.Errorf("file not found: %v", objectName), http.StatusNotFound)
|
s.ErrorHandler()(w, r, fmt.Errorf("file not found: %v", path), http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
reader, getInfo, err := s.Storage().GetObject(ctx, bucketName, objectName)
|
if err = GetAsset(w, r, resourceOwner, objectName, s.Storage()); err != nil {
|
||||||
if err != nil {
|
s.ErrorHandler()(w, r, err, http.StatusInternalServerError)
|
||||||
s.ErrorHandler()(w, r, fmt.Errorf("download failed: %v", err), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadAll(reader)
|
|
||||||
if err != nil {
|
|
||||||
s.ErrorHandler()(w, r, fmt.Errorf("download failed: %v", err), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
info, err := getInfo()
|
|
||||||
if err != nil {
|
|
||||||
s.ErrorHandler()(w, r, fmt.Errorf("download failed: %v", err), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Header().Set("content-length", strconv.FormatInt(info.Size, 10))
|
|
||||||
w.Header().Set("content-type", info.ContentType)
|
|
||||||
w.Header().Set("ETag", info.ETag)
|
|
||||||
w.Write(data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeExif(file io.Reader, size int64, contentType string) (io.Reader, int64, error) {
|
func GetAsset(w http.ResponseWriter, r *http.Request, resourceOwner, objectName string, storage static.Storage) error {
|
||||||
if !isAllowedContentType(contentType) {
|
data, getInfo, err := storage.GetObject(r.Context(), authz.GetInstance(r.Context()).InstanceID(), resourceOwner, objectName)
|
||||||
return file, size, nil
|
|
||||||
}
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
_, err := buf.ReadFrom(file)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return file, 0, err
|
return fmt.Errorf("download failed: %v", err)
|
||||||
}
|
}
|
||||||
data, err := exifremove.Remove(buf.Bytes())
|
info, err := getInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return fmt.Errorf("download failed: %v", err)
|
||||||
}
|
}
|
||||||
return bytes.NewReader(data), int64(len(data)), nil
|
if info.Hash == r.Header.Get(http_util.IfNoneMatch) {
|
||||||
}
|
w.WriteHeader(304)
|
||||||
|
return nil
|
||||||
func isAllowedContentType(contentType string) bool {
|
}
|
||||||
return strings.HasSuffix(contentType, "png") ||
|
w.Header().Set(http_util.ContentLength, strconv.FormatInt(info.Size, 10))
|
||||||
strings.HasSuffix(contentType, "jpg") ||
|
w.Header().Set(http_util.ContentType, info.ContentType)
|
||||||
strings.HasSuffix(contentType, "jpeg")
|
w.Header().Set(http_util.LastModified, info.LastModified.Format(time.RFC1123))
|
||||||
|
w.Header().Set(http_util.Etag, info.Hash)
|
||||||
|
_, err = w.Write(data)
|
||||||
|
logging.New().OnError(err).Error("error writing response for asset")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
Services:
|
Services:
|
||||||
IAM:
|
IAM:
|
||||||
Prefix: "/iam"
|
Prefix: "/instance"
|
||||||
Methods:
|
Methods:
|
||||||
DefaultLabelPolicyLogo:
|
DefaultLabelPolicyLogo:
|
||||||
Path: "/policy/label/logo"
|
Path: "/policy/label/logo"
|
||||||
@ -116,4 +116,4 @@ Services:
|
|||||||
- Name: Get
|
- Name: Get
|
||||||
Comment:
|
Comment:
|
||||||
Type: download
|
Type: download
|
||||||
Permission: authenticated
|
Permission: authenticated
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
"github.com/caos/zitadel/internal/id"
|
"github.com/caos/zitadel/internal/id"
|
||||||
"github.com/caos/zitadel/internal/query"
|
"github.com/caos/zitadel/internal/query"
|
||||||
|
"github.com/caos/zitadel/internal/static"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handler) UploadDefaultLabelPolicyLogo() Uploader {
|
func (h *Handler) UploadDefaultLabelPolicyLogo() Uploader {
|
||||||
@ -44,6 +45,10 @@ func (l *labelPolicyLogoUploader) ContentTypeAllowed(contentType string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *labelPolicyLogoUploader) ObjectType() static.ObjectType {
|
||||||
|
return static.ObjectTypeStyling
|
||||||
|
}
|
||||||
|
|
||||||
func (l *labelPolicyLogoUploader) MaxFileSize() int64 {
|
func (l *labelPolicyLogoUploader) MaxFileSize() int64 {
|
||||||
return l.maxSize
|
return l.maxSize
|
||||||
}
|
}
|
||||||
@ -60,27 +65,27 @@ func (l *labelPolicyLogoUploader) ObjectName(_ authz.CtxData) (string, error) {
|
|||||||
return prefix + "-" + suffixID, nil
|
return prefix + "-" + suffixID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *labelPolicyLogoUploader) BucketName(ctxData authz.CtxData) string {
|
func (l *labelPolicyLogoUploader) ResourceOwner(instance authz.Instance, ctxData authz.CtxData) string {
|
||||||
if l.defaultPolicy {
|
if l.defaultPolicy {
|
||||||
return domain.IAMID
|
return instance.InstanceID()
|
||||||
}
|
}
|
||||||
return ctxData.OrgID
|
return ctxData.OrgID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *labelPolicyLogoUploader) Callback(ctx context.Context, info *domain.AssetInfo, orgID string, commands *command.Commands) error {
|
func (l *labelPolicyLogoUploader) UploadAsset(ctx context.Context, orgID string, upload *command.AssetUpload, commands *command.Commands) error {
|
||||||
if l.defaultPolicy {
|
if l.defaultPolicy {
|
||||||
if l.darkMode {
|
if l.darkMode {
|
||||||
_, err := commands.AddLogoDarkDefaultLabelPolicy(ctx, info.Key)
|
_, err := commands.AddLogoDarkDefaultLabelPolicy(ctx, upload)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err := commands.AddLogoDefaultLabelPolicy(ctx, info.Key)
|
_, err := commands.AddLogoDefaultLabelPolicy(ctx, upload)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if l.darkMode {
|
if l.darkMode {
|
||||||
_, err := commands.AddLogoDarkLabelPolicy(ctx, orgID, info.Key)
|
_, err := commands.AddLogoDarkLabelPolicy(ctx, orgID, upload)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err := commands.AddLogoLabelPolicy(ctx, orgID, info.Key)
|
_, err := commands.AddLogoLabelPolicy(ctx, orgID, upload)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,8 +139,8 @@ func (l *labelPolicyLogoDownloader) ObjectName(ctx context.Context, path string)
|
|||||||
return policy.Light.LogoURL, nil
|
return policy.Light.LogoURL, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *labelPolicyLogoDownloader) BucketName(ctx context.Context, id string) string {
|
func (l *labelPolicyLogoDownloader) ResourceOwner(ctx context.Context, _ string) string {
|
||||||
return getLabelPolicyBucketName(ctx, l.defaultPolicy, l.preview, l.query)
|
return getLabelPolicyResourceOwner(ctx, l.defaultPolicy, l.preview, l.query)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) UploadDefaultLabelPolicyIcon() Uploader {
|
func (h *Handler) UploadDefaultLabelPolicyIcon() Uploader {
|
||||||
@ -171,6 +176,10 @@ func (l *labelPolicyIconUploader) ContentTypeAllowed(contentType string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *labelPolicyIconUploader) ObjectType() static.ObjectType {
|
||||||
|
return static.ObjectTypeStyling
|
||||||
|
}
|
||||||
|
|
||||||
func (l *labelPolicyIconUploader) MaxFileSize() int64 {
|
func (l *labelPolicyIconUploader) MaxFileSize() int64 {
|
||||||
return l.maxSize
|
return l.maxSize
|
||||||
}
|
}
|
||||||
@ -187,28 +196,28 @@ func (l *labelPolicyIconUploader) ObjectName(_ authz.CtxData) (string, error) {
|
|||||||
return prefix + "-" + suffixID, nil
|
return prefix + "-" + suffixID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *labelPolicyIconUploader) BucketName(ctxData authz.CtxData) string {
|
func (l *labelPolicyIconUploader) ResourceOwner(instance authz.Instance, ctxData authz.CtxData) string {
|
||||||
if l.defaultPolicy {
|
if l.defaultPolicy {
|
||||||
return domain.IAMID
|
return instance.InstanceID()
|
||||||
}
|
}
|
||||||
return ctxData.OrgID
|
return ctxData.OrgID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *labelPolicyIconUploader) Callback(ctx context.Context, info *domain.AssetInfo, orgID string, commands *command.Commands) error {
|
func (l *labelPolicyIconUploader) UploadAsset(ctx context.Context, orgID string, upload *command.AssetUpload, commands *command.Commands) error {
|
||||||
if l.defaultPolicy {
|
if l.defaultPolicy {
|
||||||
if l.darkMode {
|
if l.darkMode {
|
||||||
_, err := commands.AddIconDarkDefaultLabelPolicy(ctx, info.Key)
|
_, err := commands.AddIconDarkDefaultLabelPolicy(ctx, upload)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err := commands.AddIconDefaultLabelPolicy(ctx, info.Key)
|
_, err := commands.AddIconDefaultLabelPolicy(ctx, upload)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.darkMode {
|
if l.darkMode {
|
||||||
_, err := commands.AddIconDarkLabelPolicy(ctx, orgID, info.Key)
|
_, err := commands.AddIconDarkLabelPolicy(ctx, orgID, upload)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err := commands.AddIconLabelPolicy(ctx, orgID, info.Key)
|
_, err := commands.AddIconLabelPolicy(ctx, orgID, upload)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,8 +271,8 @@ func (l *labelPolicyIconDownloader) ObjectName(ctx context.Context, path string)
|
|||||||
return policy.Light.IconURL, nil
|
return policy.Light.IconURL, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *labelPolicyIconDownloader) BucketName(ctx context.Context, id string) string {
|
func (l *labelPolicyIconDownloader) ResourceOwner(ctx context.Context, _ string) string {
|
||||||
return getLabelPolicyBucketName(ctx, l.defaultPolicy, l.preview, l.query)
|
return getLabelPolicyResourceOwner(ctx, l.defaultPolicy, l.preview, l.query)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) UploadDefaultLabelPolicyFont() Uploader {
|
func (h *Handler) UploadDefaultLabelPolicyFont() Uploader {
|
||||||
@ -290,6 +299,10 @@ func (l *labelPolicyFontUploader) ContentTypeAllowed(contentType string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *labelPolicyFontUploader) ObjectType() static.ObjectType {
|
||||||
|
return static.ObjectTypeStyling
|
||||||
|
}
|
||||||
|
|
||||||
func (l *labelPolicyFontUploader) MaxFileSize() int64 {
|
func (l *labelPolicyFontUploader) MaxFileSize() int64 {
|
||||||
return l.maxSize
|
return l.maxSize
|
||||||
}
|
}
|
||||||
@ -303,19 +316,19 @@ func (l *labelPolicyFontUploader) ObjectName(_ authz.CtxData) (string, error) {
|
|||||||
return prefix + "-" + suffixID, nil
|
return prefix + "-" + suffixID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *labelPolicyFontUploader) BucketName(ctxData authz.CtxData) string {
|
func (l *labelPolicyFontUploader) ResourceOwner(instance authz.Instance, ctxData authz.CtxData) string {
|
||||||
if l.defaultPolicy {
|
if l.defaultPolicy {
|
||||||
return domain.IAMID
|
return instance.InstanceID()
|
||||||
}
|
}
|
||||||
return ctxData.OrgID
|
return ctxData.OrgID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *labelPolicyFontUploader) Callback(ctx context.Context, info *domain.AssetInfo, orgID string, commands *command.Commands) error {
|
func (l *labelPolicyFontUploader) UploadAsset(ctx context.Context, orgID string, upload *command.AssetUpload, commands *command.Commands) error {
|
||||||
if l.defaultPolicy {
|
if l.defaultPolicy {
|
||||||
_, err := commands.AddFontDefaultLabelPolicy(ctx, info.Key)
|
_, err := commands.AddFontDefaultLabelPolicy(ctx, upload)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err := commands.AddFontLabelPolicy(ctx, orgID, info.Key)
|
_, err := commands.AddFontLabelPolicy(ctx, orgID, upload)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,8 +362,8 @@ func (l *labelPolicyFontDownloader) ObjectName(ctx context.Context, path string)
|
|||||||
return policy.FontURL, nil
|
return policy.FontURL, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *labelPolicyFontDownloader) BucketName(ctx context.Context, id string) string {
|
func (l *labelPolicyFontDownloader) ResourceOwner(ctx context.Context, _ string) string {
|
||||||
return getLabelPolicyBucketName(ctx, l.defaultPolicy, l.preview, l.query)
|
return getLabelPolicyResourceOwner(ctx, l.defaultPolicy, l.preview, l.query)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLabelPolicy(ctx context.Context, defaultPolicy, preview bool, queries *query.Queries) (*query.LabelPolicy, error) {
|
func getLabelPolicy(ctx context.Context, defaultPolicy, preview bool, queries *query.Queries) (*query.LabelPolicy, error) {
|
||||||
@ -366,16 +379,16 @@ func getLabelPolicy(ctx context.Context, defaultPolicy, preview bool, queries *q
|
|||||||
return queries.ActiveLabelPolicyByOrg(ctx, authz.GetCtxData(ctx).OrgID)
|
return queries.ActiveLabelPolicyByOrg(ctx, authz.GetCtxData(ctx).OrgID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLabelPolicyBucketName(ctx context.Context, defaultPolicy, preview bool, queries *query.Queries) string {
|
func getLabelPolicyResourceOwner(ctx context.Context, defaultPolicy, preview bool, queries *query.Queries) string {
|
||||||
if defaultPolicy {
|
if defaultPolicy {
|
||||||
return domain.IAMID
|
return authz.GetInstance(ctx).InstanceID()
|
||||||
}
|
}
|
||||||
policy, err := getLabelPolicy(ctx, defaultPolicy, preview, queries)
|
policy, err := getLabelPolicy(ctx, defaultPolicy, preview, queries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if policy.IsDefault {
|
if policy.IsDefault {
|
||||||
return domain.IAMID
|
return authz.GetInstance(ctx).InstanceID()
|
||||||
}
|
}
|
||||||
return authz.GetCtxData(ctx).OrgID
|
return authz.GetCtxData(ctx).OrgID
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/api/authz"
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
"github.com/caos/zitadel/internal/command"
|
"github.com/caos/zitadel/internal/command"
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
"github.com/caos/zitadel/internal/static"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handler) UploadMyUserAvatar() Uploader {
|
func (h *Handler) UploadMyUserAvatar() Uploader {
|
||||||
@ -27,6 +28,10 @@ func (l *myHumanAvatarUploader) ContentTypeAllowed(contentType string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *myHumanAvatarUploader) ObjectType() static.ObjectType {
|
||||||
|
return static.ObjectTypeUserAvatar
|
||||||
|
}
|
||||||
|
|
||||||
func (l *myHumanAvatarUploader) MaxFileSize() int64 {
|
func (l *myHumanAvatarUploader) MaxFileSize() int64 {
|
||||||
return l.maxSize
|
return l.maxSize
|
||||||
}
|
}
|
||||||
@ -35,12 +40,12 @@ func (l *myHumanAvatarUploader) ObjectName(ctxData authz.CtxData) (string, error
|
|||||||
return domain.GetHumanAvatarAssetPath(ctxData.UserID), nil
|
return domain.GetHumanAvatarAssetPath(ctxData.UserID), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *myHumanAvatarUploader) BucketName(ctxData authz.CtxData) string {
|
func (l *myHumanAvatarUploader) ResourceOwner(_ authz.Instance, ctxData authz.CtxData) string {
|
||||||
return ctxData.OrgID
|
return ctxData.ResourceOwner
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *myHumanAvatarUploader) Callback(ctx context.Context, info *domain.AssetInfo, orgID string, commands *command.Commands) error {
|
func (l *myHumanAvatarUploader) UploadAsset(ctx context.Context, orgID string, upload *command.AssetUpload, commands *command.Commands) error {
|
||||||
_, err := commands.AddHumanAvatar(ctx, orgID, authz.GetCtxData(ctx).UserID, info.Key)
|
_, err := commands.AddHumanAvatar(ctx, orgID, authz.GetCtxData(ctx).UserID, upload)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +59,6 @@ func (l *myHumanAvatarDownloader) ObjectName(ctx context.Context, path string) (
|
|||||||
return domain.GetHumanAvatarAssetPath(authz.GetCtxData(ctx).UserID), nil
|
return domain.GetHumanAvatarAssetPath(authz.GetCtxData(ctx).UserID), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *myHumanAvatarDownloader) BucketName(ctx context.Context, id string) string {
|
func (l *myHumanAvatarDownloader) ResourceOwner(ctx context.Context, _ string) string {
|
||||||
return authz.GetCtxData(ctx).OrgID
|
return authz.GetCtxData(ctx).ResourceOwner
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,9 @@ const (
|
|||||||
ForwardedFor = "x-forwarded-for"
|
ForwardedFor = "x-forwarded-for"
|
||||||
XUserAgent = "x-user-agent"
|
XUserAgent = "x-user-agent"
|
||||||
XGrpcWeb = "x-grpc-web"
|
XGrpcWeb = "x-grpc-web"
|
||||||
|
IfNoneMatch = "If-None-Match"
|
||||||
|
LastModified = "Last-Modified"
|
||||||
|
Etag = "Etag"
|
||||||
|
|
||||||
ContentSecurityPolicy = "content-security-policy"
|
ContentSecurityPolicy = "content-security-policy"
|
||||||
XXSSProtection = "x-xss-protection"
|
XXSSProtection = "x-xss-protection"
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package login
|
package login
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/caos/logging"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/api/assets"
|
||||||
"github.com/caos/zitadel/internal/api/authz"
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type dynamicResourceData struct {
|
type dynamicResourceData struct {
|
||||||
@ -25,74 +26,11 @@ func (l *Login) handleDynamicResources(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bucketName := authz.GetInstance(r.Context()).InstanceID()
|
resourceOwner := authz.GetInstance(r.Context()).InstanceID()
|
||||||
if data.OrgID != "" && !data.DefaultPolicy {
|
if data.OrgID != "" && !data.DefaultPolicy {
|
||||||
bucketName = data.OrgID
|
resourceOwner = data.OrgID
|
||||||
}
|
}
|
||||||
|
|
||||||
etag := r.Header.Get("If-None-Match")
|
err = assets.GetAsset(w, r, resourceOwner, data.FileName, l.staticStorage)
|
||||||
asset, info, err := l.getStatic(r.Context(), bucketName, data.FileName)
|
logging.WithFields("file", data.FileName, "org", resourceOwner).OnError(err).Warn("asset in login could not be served")
|
||||||
if info != nil && info.ETag == etag {
|
|
||||||
w.WriteHeader(304)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//TODO: enable again when assets are implemented again
|
|
||||||
_ = asset
|
|
||||||
//w.Header().Set("content-length", strconv.FormatInt(info.Size, 10))
|
|
||||||
//w.Header().Set("content-type", info.ContentType)
|
|
||||||
//w.Header().Set("ETag", info.ETag)
|
|
||||||
//w.Write(asset)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Login) getStatic(ctx context.Context, bucketName, fileName string) ([]byte, *domain.AssetInfo, error) {
|
|
||||||
s := new(staticAsset)
|
|
||||||
//TODO: enable again when assets are implemented again
|
|
||||||
//key := bucketName + "-" + fileName
|
|
||||||
//err := l.staticCache.Get(key, s)
|
|
||||||
//if err == nil && s.Info != nil && (s.Info.Expiration.After(time.Now().Add(-1 * time.Minute))) { //TODO: config?
|
|
||||||
// return s.Data, s.Info, nil
|
|
||||||
//}
|
|
||||||
|
|
||||||
//info, err := l.staticStorage.GetObjectInfo(ctx, bucketName, fileName)
|
|
||||||
//if err != nil {
|
|
||||||
// if caos_errs.IsNotFound(err) {
|
|
||||||
// return nil, nil, err
|
|
||||||
// }
|
|
||||||
// return s.Data, s.Info, err
|
|
||||||
//}
|
|
||||||
//if s.Info != nil && s.Info.ETag == info.ETag {
|
|
||||||
// if info.Expiration.After(s.Info.Expiration) {
|
|
||||||
// s.Info = info
|
|
||||||
// //l.cacheStatic(bucketName, fileName, s)
|
|
||||||
// }
|
|
||||||
// return s.Data, s.Info, nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//reader, _, err := l.staticStorage.GetObject(ctx, bucketName, fileName)
|
|
||||||
//if err != nil {
|
|
||||||
// return s.Data, s.Info, err
|
|
||||||
//}
|
|
||||||
//s.Data, err = ioutil.ReadAll(reader)
|
|
||||||
//if err != nil {
|
|
||||||
// return nil, nil, err
|
|
||||||
//}
|
|
||||||
//s.Info = info
|
|
||||||
//l.cacheStatic(bucketName, fileName, s)
|
|
||||||
return s.Data, s.Info, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: enable again when assets are implemented again
|
|
||||||
//
|
|
||||||
//func (l *Login) cacheStatic(bucketName, fileName string, s *staticAsset) {
|
|
||||||
// key := bucketName + "-" + fileName
|
|
||||||
// err := l.staticCache.Set(key, &s)
|
|
||||||
// logging.Log("HANDLER-dfht2").OnError(err).Warnf("caching of asset %s: %s failed", bucketName, fileName)
|
|
||||||
//}
|
|
||||||
|
|
||||||
type staticAsset struct {
|
|
||||||
Data []byte
|
|
||||||
Info *domain.AssetInfo
|
|
||||||
}
|
}
|
||||||
|
@ -124,10 +124,7 @@ func (c *Commands) ActivateDefaultLabelPolicy(ctx context.Context) (*domain.Obje
|
|||||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddLogoDefaultLabelPolicy(ctx context.Context, storageKey string) (*domain.ObjectDetails, error) {
|
func (c *Commands) AddLogoDefaultLabelPolicy(ctx context.Context, upload *AssetUpload) (*domain.ObjectDetails, error) {
|
||||||
if storageKey == "" {
|
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-3m20c", "Errors.Assets.EmptyKey")
|
|
||||||
}
|
|
||||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -136,8 +133,12 @@ func (c *Commands) AddLogoDefaultLabelPolicy(ctx context.Context, storageKey str
|
|||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-Qw0pd", "Errors.IAM.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-Qw0pd", "Errors.IAM.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
|
asset, err := c.uploadAsset(ctx, upload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errs.ThrowInternal(err, "INSTANCE-3m20c", "Errors.Assets.Object.PutFailed")
|
||||||
|
}
|
||||||
instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, instance.NewLabelPolicyLogoAddedEvent(ctx, instanceAgg, storageKey))
|
pushedEvents, err := c.eventstore.Push(ctx, instance.NewLabelPolicyLogoAddedEvent(ctx, instanceAgg, asset.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -158,7 +159,7 @@ func (c *Commands) RemoveLogoDefaultLabelPolicy(ctx context.Context) (*domain.Ob
|
|||||||
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-Xc8Kf", "Errors.IAM.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-Xc8Kf", "Errors.IAM.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.RemoveAsset(ctx, authz.GetInstance(ctx).InstanceID(), existingPolicy.LogoKey)
|
err = c.removeAsset(ctx, authz.GetInstance(ctx).InstanceID(), existingPolicy.LogoKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -174,10 +175,7 @@ func (c *Commands) RemoveLogoDefaultLabelPolicy(ctx context.Context) (*domain.Ob
|
|||||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddIconDefaultLabelPolicy(ctx context.Context, storageKey string) (*domain.ObjectDetails, error) {
|
func (c *Commands) AddIconDefaultLabelPolicy(ctx context.Context, upload *AssetUpload) (*domain.ObjectDetails, error) {
|
||||||
if storageKey == "" {
|
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-yxE4f", "Errors.Assets.EmptyKey")
|
|
||||||
}
|
|
||||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -186,8 +184,12 @@ func (c *Commands) AddIconDefaultLabelPolicy(ctx context.Context, storageKey str
|
|||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-1yMx0", "Errors.IAM.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-1yMx0", "Errors.IAM.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
|
asset, err := c.uploadAsset(ctx, upload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errs.ThrowInternal(err, "INSTANCE-yxE4f", "Errors.Assets.Object.PutFailed")
|
||||||
|
}
|
||||||
instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, instance.NewLabelPolicyIconAddedEvent(ctx, instanceAgg, storageKey))
|
pushedEvents, err := c.eventstore.Push(ctx, instance.NewLabelPolicyIconAddedEvent(ctx, instanceAgg, asset.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -207,7 +209,7 @@ func (c *Commands) RemoveIconDefaultLabelPolicy(ctx context.Context) (*domain.Ob
|
|||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-4M0qw", "Errors.IAM.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-4M0qw", "Errors.IAM.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
err = c.RemoveAsset(ctx, authz.GetInstance(ctx).InstanceID(), existingPolicy.IconKey)
|
err = c.removeAsset(ctx, authz.GetInstance(ctx).InstanceID(), existingPolicy.IconKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -223,20 +225,21 @@ func (c *Commands) RemoveIconDefaultLabelPolicy(ctx context.Context) (*domain.Ob
|
|||||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddLogoDarkDefaultLabelPolicy(ctx context.Context, storageKey string) (*domain.ObjectDetails, error) {
|
func (c *Commands) AddLogoDarkDefaultLabelPolicy(ctx context.Context, upload *AssetUpload) (*domain.ObjectDetails, error) {
|
||||||
if storageKey == "" {
|
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-4fMs9", "Errors.Assets.EmptyKey")
|
|
||||||
}
|
|
||||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-ZR9fs", "Errors.IAM.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-ZR9fs", "Errors.Instance.LabelPolicy.NotFound")
|
||||||
|
}
|
||||||
|
asset, err := c.uploadAsset(ctx, upload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errs.ThrowInternal(err, "INSTANCE-4fMs9", "Errors.Assets.Object.PutFailed")
|
||||||
}
|
}
|
||||||
instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, instance.NewLabelPolicyLogoDarkAddedEvent(ctx, instanceAgg, storageKey))
|
pushedEvents, err := c.eventstore.Push(ctx, instance.NewLabelPolicyLogoDarkAddedEvent(ctx, instanceAgg, asset.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -254,9 +257,9 @@ func (c *Commands) RemoveLogoDarkDefaultLabelPolicy(ctx context.Context) (*domai
|
|||||||
}
|
}
|
||||||
|
|
||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-3FGds", "Errors.IAM.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-3FGds", "Errors.Instance.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
err = c.RemoveAsset(ctx, authz.GetInstance(ctx).InstanceID(), existingPolicy.LogoDarkKey)
|
err = c.removeAsset(ctx, authz.GetInstance(ctx).InstanceID(), existingPolicy.LogoDarkKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -272,20 +275,21 @@ func (c *Commands) RemoveLogoDarkDefaultLabelPolicy(ctx context.Context) (*domai
|
|||||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddIconDarkDefaultLabelPolicy(ctx context.Context, storageKey string) (*domain.ObjectDetails, error) {
|
func (c *Commands) AddIconDarkDefaultLabelPolicy(ctx context.Context, upload *AssetUpload) (*domain.ObjectDetails, error) {
|
||||||
if storageKey == "" {
|
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-1cxM3", "Errors.Assets.EmptyKey")
|
|
||||||
}
|
|
||||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-vMsf9", "Errors.IAM.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-vMsf9", "Errors.Instance.LabelPolicy.NotFound")
|
||||||
|
}
|
||||||
|
asset, err := c.uploadAsset(ctx, upload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errs.ThrowInternal(err, "INSTANCE-1cxM3", "Errors.Assets.Object.PutFailed")
|
||||||
}
|
}
|
||||||
instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, instance.NewLabelPolicyIconDarkAddedEvent(ctx, instanceAgg, storageKey))
|
pushedEvents, err := c.eventstore.Push(ctx, instance.NewLabelPolicyIconDarkAddedEvent(ctx, instanceAgg, asset.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -303,9 +307,9 @@ func (c *Commands) RemoveIconDarkDefaultLabelPolicy(ctx context.Context) (*domai
|
|||||||
}
|
}
|
||||||
|
|
||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-2nc7F", "Errors.IAM.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-2nc7F", "Errors.Instance.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
err = c.RemoveAsset(ctx, authz.GetInstance(ctx).InstanceID(), existingPolicy.IconDarkKey)
|
err = c.removeAsset(ctx, authz.GetInstance(ctx).InstanceID(), existingPolicy.IconDarkKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -321,20 +325,21 @@ func (c *Commands) RemoveIconDarkDefaultLabelPolicy(ctx context.Context) (*domai
|
|||||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddFontDefaultLabelPolicy(ctx context.Context, storageKey string) (*domain.ObjectDetails, error) {
|
func (c *Commands) AddFontDefaultLabelPolicy(ctx context.Context, upload *AssetUpload) (*domain.ObjectDetails, error) {
|
||||||
if storageKey == "" {
|
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-1N8fs", "Errors.Assets.EmptyKey")
|
|
||||||
}
|
|
||||||
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-1N8fE", "Errors.IAM.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-1N8fE", "Errors.Instance.LabelPolicy.NotFound")
|
||||||
|
}
|
||||||
|
asset, err := c.uploadAsset(ctx, upload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errs.ThrowInternal(nil, "INSTANCE-1N8fs", "Errors.Assets.Object.PutFailed")
|
||||||
}
|
}
|
||||||
instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, instance.NewLabelPolicyFontAddedEvent(ctx, instanceAgg, storageKey))
|
pushedEvents, err := c.eventstore.Push(ctx, instance.NewLabelPolicyFontAddedEvent(ctx, instanceAgg, asset.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -352,9 +357,9 @@ func (c *Commands) RemoveFontDefaultLabelPolicy(ctx context.Context) (*domain.Ob
|
|||||||
}
|
}
|
||||||
|
|
||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-Tk0gw", "Errors.IAM.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-Tk0gw", "Errors.Instance.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
err = c.RemoveAsset(ctx, authz.GetInstance(ctx).InstanceID(), existingPolicy.FontKey)
|
err = c.removeAsset(ctx, authz.GetInstance(ctx).InstanceID(), existingPolicy.FontKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/api/authz"
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
@ -452,8 +453,8 @@ func TestCommandSide_AddLogoDefaultLabelPolicy(t *testing.T) {
|
|||||||
storage static.Storage
|
storage static.Storage
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
storageKey string
|
upload *AssetUpload
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -465,20 +466,6 @@ func TestCommandSide_AddLogoDefaultLabelPolicy(t *testing.T) {
|
|||||||
args args
|
args args
|
||||||
res res
|
res res
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
name: "storage key empty, invalid argument error",
|
|
||||||
fields: fields{
|
|
||||||
eventstore: eventstoreExpect(
|
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "label policy not existing, not found error",
|
name: "label policy not existing, not found error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -488,13 +475,61 @@ func TestCommandSide_AddLogoDefaultLabelPolicy(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "logo",
|
||||||
|
ContentType: "text/css",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: nil,
|
||||||
|
Size: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsNotFound,
|
err: caos_errs.IsNotFound,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "upload failed, error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
instance.NewLabelPolicyAddedEvent(context.Background(),
|
||||||
|
&instance.NewAggregate("INSTANCE").Aggregate,
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObjectError(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "logo",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: caos_errs.IsInternal,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "logo added, ok",
|
name: "logo added, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -523,16 +558,24 @@ func TestCommandSide_AddLogoDefaultLabelPolicy(t *testing.T) {
|
|||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewLabelPolicyLogoAddedEvent(context.Background(),
|
instance.NewLabelPolicyLogoAddedEvent(context.Background(),
|
||||||
&instance.NewAggregate("INSTANCE").Aggregate,
|
&instance.NewAggregate("INSTANCE").Aggregate,
|
||||||
"key",
|
"logo",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObject(),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "logo",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.ObjectDetails{
|
want: &domain.ObjectDetails{
|
||||||
@ -545,8 +588,9 @@ func TestCommandSide_AddLogoDefaultLabelPolicy(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
|
static: tt.fields.storage,
|
||||||
}
|
}
|
||||||
got, err := r.AddLogoDefaultLabelPolicy(tt.args.ctx, tt.args.storageKey)
|
got, err := r.AddLogoDefaultLabelPolicy(tt.args.ctx, tt.args.upload)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -593,7 +637,6 @@ func TestCommandSide_RemoveLogoDefaultLabelPolicy(t *testing.T) {
|
|||||||
err: caos_errs.IsNotFound,
|
err: caos_errs.IsNotFound,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "asset remove error, internal error",
|
name: "asset remove error, internal error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -708,10 +751,11 @@ func TestCommandSide_RemoveLogoDefaultLabelPolicy(t *testing.T) {
|
|||||||
func TestCommandSide_AddIconDefaultLabelPolicy(t *testing.T) {
|
func TestCommandSide_AddIconDefaultLabelPolicy(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
|
storage static.Storage
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
storageKey string
|
upload *AssetUpload
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -723,20 +767,6 @@ func TestCommandSide_AddIconDefaultLabelPolicy(t *testing.T) {
|
|||||||
args args
|
args args
|
||||||
res res
|
res res
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
name: "storage key empty, invalid argument error",
|
|
||||||
fields: fields{
|
|
||||||
eventstore: eventstoreExpect(
|
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "label policy not existing, not found error",
|
name: "label policy not existing, not found error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -746,13 +776,61 @@ func TestCommandSide_AddIconDefaultLabelPolicy(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsNotFound,
|
err: caos_errs.IsNotFound,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "upload failed, error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
instance.NewLabelPolicyAddedEvent(context.Background(),
|
||||||
|
&instance.NewAggregate("INSTANCE").Aggregate,
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObjectError(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: caos_errs.IsInternal,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "icon added, ok",
|
name: "icon added, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -781,16 +859,24 @@ func TestCommandSide_AddIconDefaultLabelPolicy(t *testing.T) {
|
|||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewLabelPolicyIconAddedEvent(context.Background(),
|
instance.NewLabelPolicyIconAddedEvent(context.Background(),
|
||||||
&instance.NewAggregate("INSTANCE").Aggregate,
|
&instance.NewAggregate("INSTANCE").Aggregate,
|
||||||
"key",
|
"icon",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObject(),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.ObjectDetails{
|
want: &domain.ObjectDetails{
|
||||||
@ -803,8 +889,9 @@ func TestCommandSide_AddIconDefaultLabelPolicy(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
|
static: tt.fields.storage,
|
||||||
}
|
}
|
||||||
got, err := r.AddIconDefaultLabelPolicy(tt.args.ctx, tt.args.storageKey)
|
got, err := r.AddIconDefaultLabelPolicy(tt.args.ctx, tt.args.upload)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -926,11 +1013,12 @@ func TestCommandSide_RemoveIconDefaultLabelPolicy(t *testing.T) {
|
|||||||
func TestCommandSide_AddLogoDarkDefaultLabelPolicy(t *testing.T) {
|
func TestCommandSide_AddLogoDarkDefaultLabelPolicy(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
|
storage static.Storage
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
instanceID string
|
instanceID string
|
||||||
storageKey string
|
upload *AssetUpload
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -942,21 +1030,6 @@ func TestCommandSide_AddLogoDarkDefaultLabelPolicy(t *testing.T) {
|
|||||||
args args
|
args args
|
||||||
res res
|
res res
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
name: "storage key empty, invalid argument error",
|
|
||||||
fields: fields{
|
|
||||||
eventstore: eventstoreExpect(
|
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
instanceID: "INSTANCE",
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "label policy not existing, not found error",
|
name: "label policy not existing, not found error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -968,12 +1041,61 @@ func TestCommandSide_AddLogoDarkDefaultLabelPolicy(t *testing.T) {
|
|||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
instanceID: "INSTANCE",
|
instanceID: "INSTANCE",
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "logo",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsNotFound,
|
err: caos_errs.IsNotFound,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "upload failed, error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
instance.NewLabelPolicyAddedEvent(context.Background(),
|
||||||
|
&instance.NewAggregate("INSTANCE").Aggregate,
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObjectError(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
instanceID: "INSTANCE",
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "logo",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: caos_errs.IsInternal,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "logo dark added, ok",
|
name: "logo dark added, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -1002,16 +1124,24 @@ func TestCommandSide_AddLogoDarkDefaultLabelPolicy(t *testing.T) {
|
|||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewLabelPolicyLogoDarkAddedEvent(context.Background(),
|
instance.NewLabelPolicyLogoDarkAddedEvent(context.Background(),
|
||||||
&instance.NewAggregate("INSTANCE").Aggregate,
|
&instance.NewAggregate("INSTANCE").Aggregate,
|
||||||
"key",
|
"logo",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObject(),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "logo",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.ObjectDetails{
|
want: &domain.ObjectDetails{
|
||||||
@ -1024,8 +1154,9 @@ func TestCommandSide_AddLogoDarkDefaultLabelPolicy(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
|
static: tt.fields.storage,
|
||||||
}
|
}
|
||||||
got, err := r.AddLogoDarkDefaultLabelPolicy(tt.args.ctx, tt.args.storageKey)
|
got, err := r.AddLogoDarkDefaultLabelPolicy(tt.args.ctx, tt.args.upload)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -1186,10 +1317,11 @@ func TestCommandSide_RemoveLogoDarkDefaultLabelPolicy(t *testing.T) {
|
|||||||
func TestCommandSide_AddIconDarkDefaultLabelPolicy(t *testing.T) {
|
func TestCommandSide_AddIconDarkDefaultLabelPolicy(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
|
storage static.Storage
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
storageKey string
|
upload *AssetUpload
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -1201,20 +1333,6 @@ func TestCommandSide_AddIconDarkDefaultLabelPolicy(t *testing.T) {
|
|||||||
args args
|
args args
|
||||||
res res
|
res res
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
name: "storage key empty, invalid argument error",
|
|
||||||
fields: fields{
|
|
||||||
eventstore: eventstoreExpect(
|
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "label policy not existing, not found error",
|
name: "label policy not existing, not found error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -1224,13 +1342,61 @@ func TestCommandSide_AddIconDarkDefaultLabelPolicy(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsNotFound,
|
err: caos_errs.IsNotFound,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "upload failed, error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
instance.NewLabelPolicyAddedEvent(context.Background(),
|
||||||
|
&instance.NewAggregate("INSTANCE").Aggregate,
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObjectError(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: caos_errs.IsInternal,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "icon dark added, ok",
|
name: "icon dark added, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -1259,16 +1425,24 @@ func TestCommandSide_AddIconDarkDefaultLabelPolicy(t *testing.T) {
|
|||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewLabelPolicyIconDarkAddedEvent(context.Background(),
|
instance.NewLabelPolicyIconDarkAddedEvent(context.Background(),
|
||||||
&instance.NewAggregate("INSTANCE").Aggregate,
|
&instance.NewAggregate("INSTANCE").Aggregate,
|
||||||
"key",
|
"icon",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObject(),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.ObjectDetails{
|
want: &domain.ObjectDetails{
|
||||||
@ -1281,8 +1455,9 @@ func TestCommandSide_AddIconDarkDefaultLabelPolicy(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
|
static: tt.fields.storage,
|
||||||
}
|
}
|
||||||
got, err := r.AddIconDarkDefaultLabelPolicy(tt.args.ctx, tt.args.storageKey)
|
got, err := r.AddIconDarkDefaultLabelPolicy(tt.args.ctx, tt.args.upload)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -1443,10 +1618,11 @@ func TestCommandSide_RemoveIconDarkDefaultLabelPolicy(t *testing.T) {
|
|||||||
func TestCommandSide_AddFontDefaultLabelPolicy(t *testing.T) {
|
func TestCommandSide_AddFontDefaultLabelPolicy(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
|
storage static.Storage
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
storageKey string
|
upload *AssetUpload
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -1458,20 +1634,6 @@ func TestCommandSide_AddFontDefaultLabelPolicy(t *testing.T) {
|
|||||||
args args
|
args args
|
||||||
res res
|
res res
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
name: "storage key empty, invalid argument error",
|
|
||||||
fields: fields{
|
|
||||||
eventstore: eventstoreExpect(
|
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "label policy not existing, not found error",
|
name: "label policy not existing, not found error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -1481,13 +1643,61 @@ func TestCommandSide_AddFontDefaultLabelPolicy(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "font",
|
||||||
|
ContentType: "ttf",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsNotFound,
|
err: caos_errs.IsNotFound,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "upload failed, error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
instance.NewLabelPolicyAddedEvent(context.Background(),
|
||||||
|
&instance.NewAggregate("INSTANCE").Aggregate,
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObjectError(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "font",
|
||||||
|
ContentType: "ttf",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: caos_errs.IsInternal,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "font added, ok",
|
name: "font added, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -1516,16 +1726,24 @@ func TestCommandSide_AddFontDefaultLabelPolicy(t *testing.T) {
|
|||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
instance.NewLabelPolicyFontAddedEvent(context.Background(),
|
instance.NewLabelPolicyFontAddedEvent(context.Background(),
|
||||||
&instance.NewAggregate("INSTANCE").Aggregate,
|
&instance.NewAggregate("INSTANCE").Aggregate,
|
||||||
"key",
|
"font",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObject(),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "IAM",
|
||||||
|
ObjectName: "font",
|
||||||
|
ContentType: "ttf",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.ObjectDetails{
|
want: &domain.ObjectDetails{
|
||||||
@ -1538,8 +1756,9 @@ func TestCommandSide_AddFontDefaultLabelPolicy(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
|
static: tt.fields.storage,
|
||||||
}
|
}
|
||||||
got, err := r.AddFontDefaultLabelPolicy(tt.args.ctx, tt.args.storageKey)
|
got, err := r.AddFontDefaultLabelPolicy(tt.args.ctx, tt.args.upload)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/repository/org"
|
"github.com/caos/zitadel/internal/repository/org"
|
||||||
|
"github.com/caos/zitadel/internal/static"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Commands) AddLabelPolicy(ctx context.Context, resourceOwner string, policy *domain.LabelPolicy) (*domain.LabelPolicy, error) {
|
func (c *Commands) AddLabelPolicy(ctx context.Context, resourceOwner string, policy *domain.LabelPolicy) (*domain.LabelPolicy, error) {
|
||||||
@ -150,13 +151,10 @@ func (c *Commands) ActivateLabelPolicy(ctx context.Context, orgID string) (*doma
|
|||||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddLogoLabelPolicy(ctx context.Context, orgID, storageKey string) (*domain.ObjectDetails, error) {
|
func (c *Commands) AddLogoLabelPolicy(ctx context.Context, orgID string, upload *AssetUpload) (*domain.ObjectDetails, error) {
|
||||||
if orgID == "" {
|
if orgID == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-KKd4X", "Errors.ResourceOwnerMissing")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-KKd4X", "Errors.ResourceOwnerMissing")
|
||||||
}
|
}
|
||||||
if storageKey == "" {
|
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-4N3nf", "Errors.Assets.EmptyKey")
|
|
||||||
}
|
|
||||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -165,8 +163,12 @@ func (c *Commands) AddLogoLabelPolicy(ctx context.Context, orgID, storageKey str
|
|||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-23BMs", "Errors.Org.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "ORG-23BMs", "Errors.Org.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
|
asset, err := c.uploadAsset(ctx, upload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errs.ThrowInternal(err, "IAM-4N3nf", "Errors.Assets.Object.PutFailed")
|
||||||
|
}
|
||||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, org.NewLabelPolicyLogoAddedEvent(ctx, orgAgg, storageKey))
|
pushedEvents, err := c.eventstore.Push(ctx, org.NewLabelPolicyLogoAddedEvent(ctx, orgAgg, asset.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -189,7 +191,7 @@ func (c *Commands) RemoveLogoLabelPolicy(ctx context.Context, orgID string) (*do
|
|||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-4MVsf", "Errors.Org.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "ORG-4MVsf", "Errors.Org.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
err = c.RemoveAsset(ctx, orgID, existingPolicy.LogoKey)
|
err = c.removeAsset(ctx, orgID, existingPolicy.LogoKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -205,13 +207,10 @@ func (c *Commands) RemoveLogoLabelPolicy(ctx context.Context, orgID string) (*do
|
|||||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddIconLabelPolicy(ctx context.Context, orgID, storageKey string) (*domain.ObjectDetails, error) {
|
func (c *Commands) AddIconLabelPolicy(ctx context.Context, orgID string, upload *AssetUpload) (*domain.ObjectDetails, error) {
|
||||||
if orgID == "" {
|
if orgID == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-hMDs3", "Errors.ResourceOwnerMissing")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-hMDs3", "Errors.ResourceOwnerMissing")
|
||||||
}
|
}
|
||||||
if storageKey == "" {
|
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-4BS7f", "Errors.Assets.EmptyKey")
|
|
||||||
}
|
|
||||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -220,8 +219,12 @@ func (c *Commands) AddIconLabelPolicy(ctx context.Context, orgID, storageKey str
|
|||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-4nq2f", "Errors.Org.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "ORG-4nq2f", "Errors.Org.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
|
asset, err := c.uploadAsset(ctx, upload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errs.ThrowInternal(err, "IAM-4BS7f", "Errors.Assets.Object.PutFailed")
|
||||||
|
}
|
||||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, org.NewLabelPolicyIconAddedEvent(ctx, orgAgg, storageKey))
|
pushedEvents, err := c.eventstore.Push(ctx, org.NewLabelPolicyIconAddedEvent(ctx, orgAgg, asset.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -245,7 +248,7 @@ func (c *Commands) RemoveIconLabelPolicy(ctx context.Context, orgID string) (*do
|
|||||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-1nd9f", "Errors.Org.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "ORG-1nd9f", "Errors.Org.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.RemoveAsset(ctx, orgID, existingPolicy.IconKey)
|
err = c.removeAsset(ctx, orgID, existingPolicy.IconKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -261,13 +264,10 @@ func (c *Commands) RemoveIconLabelPolicy(ctx context.Context, orgID string) (*do
|
|||||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddLogoDarkLabelPolicy(ctx context.Context, orgID, storageKey string) (*domain.ObjectDetails, error) {
|
func (c *Commands) AddLogoDarkLabelPolicy(ctx context.Context, orgID string, upload *AssetUpload) (*domain.ObjectDetails, error) {
|
||||||
if orgID == "" {
|
if orgID == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-67Ms2", "Errors.ResourceOwnerMissing")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-67Ms2", "Errors.ResourceOwnerMissing")
|
||||||
}
|
}
|
||||||
if storageKey == "" {
|
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-3S7fN", "Errors.Assets.EmptyKey")
|
|
||||||
}
|
|
||||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -276,8 +276,12 @@ func (c *Commands) AddLogoDarkLabelPolicy(ctx context.Context, orgID, storageKey
|
|||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-QSqcd", "Errors.Org.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "ORG-QSqcd", "Errors.Org.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
|
asset, err := c.uploadAsset(ctx, upload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errs.ThrowInternal(err, "IAM-3S7fN", "Errors.Assets.Object.PutFailed")
|
||||||
|
}
|
||||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, org.NewLabelPolicyLogoDarkAddedEvent(ctx, orgAgg, storageKey))
|
pushedEvents, err := c.eventstore.Push(ctx, org.NewLabelPolicyLogoDarkAddedEvent(ctx, orgAgg, asset.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -300,7 +304,7 @@ func (c *Commands) RemoveLogoDarkLabelPolicy(ctx context.Context, orgID string)
|
|||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-0peQw", "Errors.Org.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "ORG-0peQw", "Errors.Org.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
err = c.RemoveAsset(ctx, orgID, existingPolicy.LogoDarkKey)
|
err = c.removeAsset(ctx, orgID, existingPolicy.LogoDarkKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -316,13 +320,10 @@ func (c *Commands) RemoveLogoDarkLabelPolicy(ctx context.Context, orgID string)
|
|||||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddIconDarkLabelPolicy(ctx context.Context, orgID, storageKey string) (*domain.ObjectDetails, error) {
|
func (c *Commands) AddIconDarkLabelPolicy(ctx context.Context, orgID string, upload *AssetUpload) (*domain.ObjectDetails, error) {
|
||||||
if orgID == "" {
|
if orgID == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-tzBfs", "Errors.ResourceOwnerMissing")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-tzBfs", "Errors.ResourceOwnerMissing")
|
||||||
}
|
}
|
||||||
if storageKey == "" {
|
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-4B7cs", "Errors.Assets.EmptyKey")
|
|
||||||
}
|
|
||||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -331,8 +332,12 @@ func (c *Commands) AddIconDarkLabelPolicy(ctx context.Context, orgID, storageKey
|
|||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-4Nf8s", "Errors.Org.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "ORG-4Nf8s", "Errors.Org.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
|
asset, err := c.uploadAsset(ctx, upload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errs.ThrowInternal(err, "IAM-4B7cs", "Errors.Assets.Object.PutFailed")
|
||||||
|
}
|
||||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, org.NewLabelPolicyIconDarkAddedEvent(ctx, orgAgg, storageKey))
|
pushedEvents, err := c.eventstore.Push(ctx, org.NewLabelPolicyIconDarkAddedEvent(ctx, orgAgg, asset.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -367,13 +372,10 @@ func (c *Commands) RemoveIconDarkLabelPolicy(ctx context.Context, orgID string)
|
|||||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddFontLabelPolicy(ctx context.Context, orgID, storageKey string) (*domain.ObjectDetails, error) {
|
func (c *Commands) AddFontLabelPolicy(ctx context.Context, orgID string, upload *AssetUpload) (*domain.ObjectDetails, error) {
|
||||||
if orgID == "" {
|
if orgID == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-1Nf9s", "Errors.ResourceOwnerMissing")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-1Nf9s", "Errors.ResourceOwnerMissing")
|
||||||
}
|
}
|
||||||
if storageKey == "" {
|
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-2f9fw", "Errors.Assets.EmptyKey")
|
|
||||||
}
|
|
||||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -382,8 +384,12 @@ func (c *Commands) AddFontLabelPolicy(ctx context.Context, orgID, storageKey str
|
|||||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-2M9fs", "Errors.Org.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "ORG-2M9fs", "Errors.Org.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
|
asset, err := c.uploadAsset(ctx, upload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errs.ThrowInternal(err, "ORG-2f9fw", "Errors.Assets.Object.PutFailed")
|
||||||
|
}
|
||||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, org.NewLabelPolicyFontAddedEvent(ctx, orgAgg, storageKey))
|
pushedEvents, err := c.eventstore.Push(ctx, org.NewLabelPolicyFontAddedEvent(ctx, orgAgg, asset.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -447,7 +453,7 @@ func (c *Commands) removeLabelPolicy(ctx context.Context, existingPolicy *OrgLab
|
|||||||
return nil, caos_errs.ThrowNotFound(nil, "Org-3M9df", "Errors.Org.LabelPolicy.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "Org-3M9df", "Errors.Org.LabelPolicy.NotFound")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.RemoveAssetsFolder(ctx, existingPolicy.AggregateID, domain.LabelPolicyPrefix+"/", true)
|
err = c.removeAssetsFolder(ctx, existingPolicy.AggregateID, static.ObjectTypeStyling)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -463,7 +469,7 @@ func (c *Commands) removeLabelPolicyIfExists(ctx context.Context, orgID string)
|
|||||||
if existingPolicy.State != domain.PolicyStateActive {
|
if existingPolicy.State != domain.PolicyStateActive {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
err = c.RemoveAssetsFolder(ctx, orgID, domain.LabelPolicyPrefix+"/", true)
|
err = c.removeAssetsFolder(ctx, orgID, static.ObjectTypeStyling)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -472,7 +478,7 @@ func (c *Commands) removeLabelPolicyIfExists(ctx context.Context, orgID string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) removeLabelPolicyAssets(ctx context.Context, existingPolicy *OrgLabelPolicyWriteModel) (*org.LabelPolicyAssetsRemovedEvent, error) {
|
func (c *Commands) removeLabelPolicyAssets(ctx context.Context, existingPolicy *OrgLabelPolicyWriteModel) (*org.LabelPolicyAssetsRemovedEvent, error) {
|
||||||
err := c.RemoveAssetsFolder(ctx, existingPolicy.AggregateID, domain.LabelPolicyPrefix+"/", true)
|
err := c.removeAssetsFolder(ctx, existingPolicy.AggregateID, static.ObjectTypeStyling)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -782,9 +783,9 @@ func TestCommandSide_AddLogoLabelPolicy(t *testing.T) {
|
|||||||
storage static.Storage
|
storage static.Storage
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
orgID string
|
orgID string
|
||||||
storageKey string
|
upload *AssetUpload
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -803,24 +804,17 @@ func TestCommandSide_AddLogoLabelPolicy(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
storageKey: "key",
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "storage key empty, invalid argument error",
|
|
||||||
fields: fields{
|
|
||||||
eventstore: eventstoreExpect(
|
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "",
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "logo",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
err: caos_errs.IsErrorInvalidArgument,
|
||||||
@ -835,14 +829,63 @@ func TestCommandSide_AddLogoLabelPolicy(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "org1",
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "logo",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsNotFound,
|
err: caos_errs.IsNotFound,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "upload failed, error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewLabelPolicyAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObjectError(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
orgID: "org1",
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "logo",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: caos_errs.IsInternal,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "logo added, ok",
|
name: "logo added, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -871,17 +914,25 @@ func TestCommandSide_AddLogoLabelPolicy(t *testing.T) {
|
|||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewLabelPolicyLogoAddedEvent(context.Background(),
|
org.NewLabelPolicyLogoAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
"key",
|
"logo",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObject(),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "org1",
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "logo",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.ObjectDetails{
|
want: &domain.ObjectDetails{
|
||||||
@ -896,7 +947,7 @@ func TestCommandSide_AddLogoLabelPolicy(t *testing.T) {
|
|||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
static: tt.fields.storage,
|
static: tt.fields.storage,
|
||||||
}
|
}
|
||||||
got, err := r.AddLogoLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.storageKey)
|
got, err := r.AddLogoLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.upload)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -1039,11 +1090,12 @@ func TestCommandSide_RemoveLogoLabelPolicy(t *testing.T) {
|
|||||||
func TestCommandSide_AddIconLabelPolicy(t *testing.T) {
|
func TestCommandSide_AddIconLabelPolicy(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
|
storage static.Storage
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
orgID string
|
orgID string
|
||||||
storageKey string
|
upload *AssetUpload
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -1062,24 +1114,17 @@ func TestCommandSide_AddIconLabelPolicy(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
storageKey: "key",
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "storage key empty, invalid argument error",
|
|
||||||
fields: fields{
|
|
||||||
eventstore: eventstoreExpect(
|
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "",
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
err: caos_errs.IsErrorInvalidArgument,
|
||||||
@ -1094,14 +1139,63 @@ func TestCommandSide_AddIconLabelPolicy(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "org1",
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsNotFound,
|
err: caos_errs.IsNotFound,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "upload failed, error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewLabelPolicyAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObjectError(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
orgID: "org1",
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: caos_errs.IsInternal,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "icon added, ok",
|
name: "icon added, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -1130,17 +1224,25 @@ func TestCommandSide_AddIconLabelPolicy(t *testing.T) {
|
|||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewLabelPolicyIconAddedEvent(context.Background(),
|
org.NewLabelPolicyIconAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
"key",
|
"icon",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObject(),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "org1",
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.ObjectDetails{
|
want: &domain.ObjectDetails{
|
||||||
@ -1153,8 +1255,9 @@ func TestCommandSide_AddIconLabelPolicy(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
|
static: tt.fields.storage,
|
||||||
}
|
}
|
||||||
got, err := r.AddIconLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.storageKey)
|
got, err := r.AddIconLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.upload)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -1294,11 +1397,12 @@ func TestCommandSide_RemoveIconLabelPolicy(t *testing.T) {
|
|||||||
func TestCommandSide_AddLogoDarkLabelPolicy(t *testing.T) {
|
func TestCommandSide_AddLogoDarkLabelPolicy(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
|
storage static.Storage
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
orgID string
|
orgID string
|
||||||
storageKey string
|
upload *AssetUpload
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -1319,22 +1423,15 @@ func TestCommandSide_AddLogoDarkLabelPolicy(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "",
|
||||||
},
|
upload: &AssetUpload{
|
||||||
res: res{
|
ResourceOwner: "org1",
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
ObjectName: "logo",
|
||||||
},
|
ContentType: "image",
|
||||||
},
|
ObjectType: static.ObjectTypeStyling,
|
||||||
{
|
File: bytes.NewReader([]byte("test")),
|
||||||
name: "storage key empty, invalid argument error",
|
Size: 4,
|
||||||
fields: fields{
|
},
|
||||||
eventstore: eventstoreExpect(
|
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
orgID: "org1",
|
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
err: caos_errs.IsErrorInvalidArgument,
|
||||||
@ -1349,14 +1446,63 @@ func TestCommandSide_AddLogoDarkLabelPolicy(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "org1",
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "logo",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsNotFound,
|
err: caos_errs.IsNotFound,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "upload failed, error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewLabelPolicyAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObjectError(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
orgID: "org1",
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "logo",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: caos_errs.IsInternal,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "logo dark added, ok",
|
name: "logo dark added, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -1385,17 +1531,25 @@ func TestCommandSide_AddLogoDarkLabelPolicy(t *testing.T) {
|
|||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewLabelPolicyLogoDarkAddedEvent(context.Background(),
|
org.NewLabelPolicyLogoDarkAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
"key",
|
"logo",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObject(),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "org1",
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "logo",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.ObjectDetails{
|
want: &domain.ObjectDetails{
|
||||||
@ -1408,8 +1562,9 @@ func TestCommandSide_AddLogoDarkLabelPolicy(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
|
static: tt.fields.storage,
|
||||||
}
|
}
|
||||||
got, err := r.AddLogoDarkLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.storageKey)
|
got, err := r.AddLogoDarkLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.upload)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -1555,9 +1710,9 @@ func TestCommandSide_AddIconDarkLabelPolicy(t *testing.T) {
|
|||||||
storage static.Storage
|
storage static.Storage
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
orgID string
|
orgID string
|
||||||
storageKey string
|
upload *AssetUpload
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -1576,24 +1731,17 @@ func TestCommandSide_AddIconDarkLabelPolicy(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
storageKey: "key",
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "storage key empty, invalid argument error",
|
|
||||||
fields: fields{
|
|
||||||
eventstore: eventstoreExpect(
|
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "",
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
err: caos_errs.IsErrorInvalidArgument,
|
||||||
@ -1608,14 +1756,63 @@ func TestCommandSide_AddIconDarkLabelPolicy(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "org1",
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsNotFound,
|
err: caos_errs.IsNotFound,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "upload failed, error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewLabelPolicyAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObjectError(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
orgID: "org1",
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: caos_errs.IsInternal,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "icon dark added, ok",
|
name: "icon dark added, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -1644,17 +1841,25 @@ func TestCommandSide_AddIconDarkLabelPolicy(t *testing.T) {
|
|||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewLabelPolicyIconDarkAddedEvent(context.Background(),
|
org.NewLabelPolicyIconDarkAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
"key",
|
"icon",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObject(),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "org1",
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "icon",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.ObjectDetails{
|
want: &domain.ObjectDetails{
|
||||||
@ -1667,8 +1872,9 @@ func TestCommandSide_AddIconDarkLabelPolicy(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
|
static: tt.fields.storage,
|
||||||
}
|
}
|
||||||
got, err := r.AddIconDarkLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.storageKey)
|
got, err := r.AddIconDarkLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.upload)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -1806,11 +2012,12 @@ func TestCommandSide_RemoveIconDarkLabelPolicy(t *testing.T) {
|
|||||||
func TestCommandSide_AddFontLabelPolicy(t *testing.T) {
|
func TestCommandSide_AddFontLabelPolicy(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
|
storage static.Storage
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
orgID string
|
orgID string
|
||||||
storageKey string
|
upload *AssetUpload
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -1829,24 +2036,17 @@ func TestCommandSide_AddFontLabelPolicy(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
storageKey: "key",
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "storage key empty, invalid argument error",
|
|
||||||
fields: fields{
|
|
||||||
eventstore: eventstoreExpect(
|
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "",
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "font",
|
||||||
|
ContentType: "ttf",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
err: caos_errs.IsErrorInvalidArgument,
|
||||||
@ -1861,14 +2061,55 @@ func TestCommandSide_AddFontLabelPolicy(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "org1",
|
||||||
storageKey: "key",
|
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsNotFound,
|
err: caos_errs.IsNotFound,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "upload failed, error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewLabelPolicyAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
"#ffffff",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObjectError(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
orgID: "org1",
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "font",
|
||||||
|
ContentType: "ttf",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: caos_errs.IsInternal,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "font added, ok",
|
name: "font added, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@ -1897,17 +2138,25 @@ func TestCommandSide_AddFontLabelPolicy(t *testing.T) {
|
|||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
org.NewLabelPolicyFontAddedEvent(context.Background(),
|
org.NewLabelPolicyFontAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
"key",
|
"font",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObject(),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "org1",
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "font",
|
||||||
|
ContentType: "ttf",
|
||||||
|
ObjectType: static.ObjectTypeStyling,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.ObjectDetails{
|
want: &domain.ObjectDetails{
|
||||||
@ -1920,8 +2169,9 @@ func TestCommandSide_AddFontLabelPolicy(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
|
static: tt.fields.storage,
|
||||||
}
|
}
|
||||||
got, err := r.AddFontLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.storageKey)
|
got, err := r.AddFontLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.upload)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,70 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/superseriousbusiness/exifremove/pkg/exifremove"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
|
"github.com/caos/zitadel/internal/static"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Commands) UploadAsset(ctx context.Context, bucketName, objectName, contentType string, file io.Reader, size int64) (*domain.AssetInfo, error) {
|
type AssetUpload struct {
|
||||||
|
ResourceOwner string
|
||||||
|
ObjectName string
|
||||||
|
ContentType string
|
||||||
|
ObjectType static.ObjectType
|
||||||
|
File io.Reader
|
||||||
|
Size int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Commands) uploadAsset(ctx context.Context, upload *AssetUpload) (*static.Asset, error) {
|
||||||
|
//TODO: handle location as soon as possible
|
||||||
|
file, size, err := removeExif(upload.File, upload.Size, upload.ContentType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return c.static.PutObject(ctx,
|
return c.static.PutObject(ctx,
|
||||||
bucketName,
|
authz.GetInstance(ctx).InstanceID(),
|
||||||
objectName,
|
"",
|
||||||
contentType,
|
upload.ResourceOwner,
|
||||||
|
upload.ObjectName,
|
||||||
|
upload.ContentType,
|
||||||
|
upload.ObjectType,
|
||||||
file,
|
file,
|
||||||
size,
|
size,
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) RemoveAsset(ctx context.Context, bucketName, storeKey string) error {
|
func (c *Commands) removeAsset(ctx context.Context, resourceOwner, storeKey string) error {
|
||||||
return c.static.RemoveObject(ctx, bucketName, storeKey)
|
return c.static.RemoveObject(ctx, authz.GetInstance(ctx).InstanceID(), resourceOwner, storeKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) RemoveAssetsFolder(ctx context.Context, bucketName, path string, recursive bool) error {
|
func (c *Commands) removeAssetsFolder(ctx context.Context, resourceOwner string, objectType static.ObjectType) error {
|
||||||
return c.static.RemoveObjects(ctx, bucketName, path, recursive)
|
return c.static.RemoveObjects(ctx, authz.GetInstance(ctx).InstanceID(), resourceOwner, objectType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeExif(file io.Reader, size int64, contentType string) (io.Reader, int64, error) {
|
||||||
|
if !isAllowedContentType(contentType) {
|
||||||
|
return file, size, nil
|
||||||
|
}
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
_, err := buf.ReadFrom(file)
|
||||||
|
if err != nil {
|
||||||
|
return file, 0, err
|
||||||
|
}
|
||||||
|
data, err := exifremove.Remove(buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return bytes.NewReader(data), int64(len(data)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAllowedContentType(contentType string) bool {
|
||||||
|
return strings.HasSuffix(contentType, "png") ||
|
||||||
|
strings.HasSuffix(contentType, "jpg") ||
|
||||||
|
strings.HasSuffix(contentType, "jpeg")
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,10 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/repository/user"
|
"github.com/caos/zitadel/internal/repository/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Commands) AddHumanAvatar(ctx context.Context, orgID, userID, storageKey string) (*domain.ObjectDetails, error) {
|
func (c *Commands) AddHumanAvatar(ctx context.Context, orgID, userID string, upload *AssetUpload) (*domain.ObjectDetails, error) {
|
||||||
if userID == "" {
|
if userID == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "USER-Ba5Ds", "Errors.IDMissing")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "USER-Ba5Ds", "Errors.IDMissing")
|
||||||
}
|
}
|
||||||
if storageKey == "" {
|
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "USER-1Xyud", "Errors.Assets.EmptyKey")
|
|
||||||
}
|
|
||||||
existingUser, err := c.userWriteModelByID(ctx, userID, orgID)
|
existingUser, err := c.userWriteModelByID(ctx, userID, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -23,8 +20,12 @@ func (c *Commands) AddHumanAvatar(ctx context.Context, orgID, userID, storageKey
|
|||||||
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
|
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "USER-vJ3fS", "Errors.Users.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "USER-vJ3fS", "Errors.Users.NotFound")
|
||||||
}
|
}
|
||||||
|
asset, err := c.uploadAsset(ctx, upload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errs.ThrowInternal(err, "USER-1Xyud", "Errors.Assets.Object.PutFailed")
|
||||||
|
}
|
||||||
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
|
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, user.NewHumanAvatarAddedEvent(ctx, userAgg, storageKey))
|
pushedEvents, err := c.eventstore.Push(ctx, user.NewHumanAvatarAddedEvent(ctx, userAgg, asset.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -46,7 +47,7 @@ func (c *Commands) RemoveHumanAvatar(ctx context.Context, orgID, userID string)
|
|||||||
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
|
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "USER-35N8f", "Errors.Users.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "USER-35N8f", "Errors.Users.NotFound")
|
||||||
}
|
}
|
||||||
err = c.RemoveAsset(ctx, orgID, existingUser.Avatar)
|
err = c.removeAsset(ctx, orgID, existingUser.Avatar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -20,12 +21,13 @@ import (
|
|||||||
func TestCommandSide_AddHumanAvatar(t *testing.T) {
|
func TestCommandSide_AddHumanAvatar(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
|
storage static.Storage
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
orgID string
|
orgID string
|
||||||
userID string
|
userID string
|
||||||
storageKey string
|
upload *AssetUpload
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -44,25 +46,18 @@ func TestCommandSide_AddHumanAvatar(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
storageKey: "key",
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "storage key empty, invalid argument error",
|
|
||||||
fields: fields{
|
|
||||||
eventstore: eventstoreExpect(
|
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "",
|
||||||
userID: "user1",
|
userID: "",
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "avatar",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeUserAvatar,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsErrorInvalidArgument,
|
err: caos_errs.IsErrorInvalidArgument,
|
||||||
@ -77,17 +72,65 @@ func TestCommandSide_AddHumanAvatar(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "org1",
|
||||||
userID: "user1",
|
userID: "user1",
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "avatar",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeUserAvatar,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
err: caos_errs.IsNotFound,
|
err: caos_errs.IsNotFound,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "logo added, ok",
|
name: "upload failed, error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
user.NewHumanAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
"username",
|
||||||
|
"firstname",
|
||||||
|
"lastname",
|
||||||
|
"nickname",
|
||||||
|
"displayname",
|
||||||
|
language.Und,
|
||||||
|
domain.GenderUnspecified,
|
||||||
|
"email@test.ch",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObjectError(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
orgID: "org1",
|
||||||
|
userID: "user1",
|
||||||
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "avatar",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeUserAvatar,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: caos_errs.IsInternal,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "avatar added, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: eventstoreExpect(
|
||||||
t,
|
t,
|
||||||
@ -112,18 +155,26 @@ func TestCommandSide_AddHumanAvatar(t *testing.T) {
|
|||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanAvatarAddedEvent(context.Background(),
|
user.NewHumanAvatarAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
"key",
|
"avatar",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
storage: mock.NewStorage(t).ExpectPutObject(),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
orgID: "org1",
|
orgID: "org1",
|
||||||
userID: "user1",
|
userID: "user1",
|
||||||
storageKey: "key",
|
upload: &AssetUpload{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
ObjectName: "avatar",
|
||||||
|
ContentType: "image",
|
||||||
|
ObjectType: static.ObjectTypeUserAvatar,
|
||||||
|
File: bytes.NewReader([]byte("test")),
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.ObjectDetails{
|
want: &domain.ObjectDetails{
|
||||||
@ -136,8 +187,9 @@ func TestCommandSide_AddHumanAvatar(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
|
static: tt.fields.storage,
|
||||||
}
|
}
|
||||||
got, err := r.AddHumanAvatar(tt.args.ctx, tt.args.orgID, tt.args.userID, tt.args.storageKey)
|
got, err := r.AddHumanAvatar(tt.args.ctx, tt.args.orgID, tt.args.userID, tt.args.upload)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,32 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type InstanceSetup struct {
|
type InstanceSetup struct {
|
||||||
Org OrgSetup
|
Org OrgSetup
|
||||||
Zitadel ZitadelConfig
|
Zitadel ZitadelConfig
|
||||||
|
Features struct {
|
||||||
|
TierName string
|
||||||
|
TierDescription string
|
||||||
|
Retention time.Duration
|
||||||
|
State domain.FeaturesState
|
||||||
|
StateDescription string
|
||||||
|
LoginPolicyFactors bool
|
||||||
|
LoginPolicyIDP bool
|
||||||
|
LoginPolicyPasswordless bool
|
||||||
|
LoginPolicyRegistration bool
|
||||||
|
LoginPolicyUsernameLogin bool
|
||||||
|
LoginPolicyPasswordReset bool
|
||||||
|
PasswordComplexityPolicy bool
|
||||||
|
LabelPolicyPrivateLabel bool
|
||||||
|
LabelPolicyWatermark bool
|
||||||
|
CustomDomain bool
|
||||||
|
PrivacyPolicy bool
|
||||||
|
MetadataUser bool
|
||||||
|
CustomTextMessage bool
|
||||||
|
CustomTextLogin bool
|
||||||
|
LockoutPolicy bool
|
||||||
|
ActionsAllowed domain.ActionsAllowed
|
||||||
|
MaxActions int
|
||||||
|
}
|
||||||
PasswordComplexityPolicy struct {
|
PasswordComplexityPolicy struct {
|
||||||
MinLength uint64
|
MinLength uint64
|
||||||
HasLowercase bool
|
HasLowercase bool
|
||||||
@ -170,6 +194,31 @@ func (command *Command) SetUpInstance(ctx context.Context, setup *InstanceSetup)
|
|||||||
projectAgg := project.NewAggregate(setup.Zitadel.projectID, orgID)
|
projectAgg := project.NewAggregate(setup.Zitadel.projectID, orgID)
|
||||||
|
|
||||||
validations := []preparation.Validation{
|
validations := []preparation.Validation{
|
||||||
|
SetDefaultFeatures(
|
||||||
|
instanceAgg,
|
||||||
|
setup.Features.TierName,
|
||||||
|
setup.Features.TierDescription,
|
||||||
|
setup.Features.State,
|
||||||
|
setup.Features.StateDescription,
|
||||||
|
setup.Features.Retention,
|
||||||
|
setup.Features.LoginPolicyFactors,
|
||||||
|
setup.Features.LoginPolicyIDP,
|
||||||
|
setup.Features.LoginPolicyPasswordless,
|
||||||
|
setup.Features.LoginPolicyRegistration,
|
||||||
|
setup.Features.LoginPolicyUsernameLogin,
|
||||||
|
setup.Features.LoginPolicyPasswordReset,
|
||||||
|
setup.Features.PasswordComplexityPolicy,
|
||||||
|
setup.Features.LabelPolicyPrivateLabel,
|
||||||
|
setup.Features.LabelPolicyWatermark,
|
||||||
|
setup.Features.CustomDomain,
|
||||||
|
setup.Features.PrivacyPolicy,
|
||||||
|
setup.Features.MetadataUser,
|
||||||
|
setup.Features.CustomTextMessage,
|
||||||
|
setup.Features.CustomTextLogin,
|
||||||
|
setup.Features.LockoutPolicy,
|
||||||
|
setup.Features.ActionsAllowed,
|
||||||
|
setup.Features.MaxActions,
|
||||||
|
),
|
||||||
AddPasswordComplexityPolicy(
|
AddPasswordComplexityPolicy(
|
||||||
instanceAgg,
|
instanceAgg,
|
||||||
setup.PasswordComplexityPolicy.MinLength,
|
setup.PasswordComplexityPolicy.MinLength,
|
||||||
|
95
internal/command/v2/instance_features.go
Normal file
95
internal/command/v2/instance_features.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/command"
|
||||||
|
"github.com/caos/zitadel/internal/command/v2/preparation"
|
||||||
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/instance"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetDefaultFeatures(
|
||||||
|
a *instance.Aggregate,
|
||||||
|
tierName,
|
||||||
|
tierDescription string,
|
||||||
|
state domain.FeaturesState,
|
||||||
|
stateDescription string,
|
||||||
|
retention time.Duration,
|
||||||
|
loginPolicyFactors,
|
||||||
|
loginPolicyIDP,
|
||||||
|
loginPolicyPasswordless,
|
||||||
|
loginPolicyRegistration,
|
||||||
|
loginPolicyUsernameLogin,
|
||||||
|
loginPolicyPasswordReset,
|
||||||
|
passwordComplexityPolicy,
|
||||||
|
labelPolicyPrivateLabel,
|
||||||
|
labelPolicyWatermark,
|
||||||
|
customDomain,
|
||||||
|
privacyPolicy,
|
||||||
|
metadataUser,
|
||||||
|
customTextMessage,
|
||||||
|
customTextLogin,
|
||||||
|
lockoutPolicy bool,
|
||||||
|
actionsAllowed domain.ActionsAllowed,
|
||||||
|
maxActions int,
|
||||||
|
) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
if !state.Valid() || state == domain.FeaturesStateUnspecified || state == domain.FeaturesStateRemoved {
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "INSTA-d3r1s", "Errors.Invalid.Argument")
|
||||||
|
}
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
writeModel, err := defaultFeatures(ctx, filter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
event, hasChanged := writeModel.NewSetEvent(ctx, &a.Aggregate,
|
||||||
|
tierName,
|
||||||
|
tierDescription,
|
||||||
|
state,
|
||||||
|
stateDescription,
|
||||||
|
retention,
|
||||||
|
loginPolicyFactors,
|
||||||
|
loginPolicyIDP,
|
||||||
|
loginPolicyPasswordless,
|
||||||
|
loginPolicyRegistration,
|
||||||
|
loginPolicyUsernameLogin,
|
||||||
|
loginPolicyPasswordReset,
|
||||||
|
passwordComplexityPolicy,
|
||||||
|
labelPolicyPrivateLabel,
|
||||||
|
labelPolicyWatermark,
|
||||||
|
customDomain,
|
||||||
|
privacyPolicy,
|
||||||
|
metadataUser,
|
||||||
|
customTextMessage,
|
||||||
|
customTextLogin,
|
||||||
|
lockoutPolicy,
|
||||||
|
actionsAllowed,
|
||||||
|
maxActions,
|
||||||
|
)
|
||||||
|
if !hasChanged {
|
||||||
|
return nil, errors.ThrowPreconditionFailed(nil, "INSTA-GE4h2", "Errors.Features.NotChanged")
|
||||||
|
}
|
||||||
|
return []eventstore.Command{
|
||||||
|
event,
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultFeatures(ctx context.Context, filter preparation.FilterToQueryReducer) (*command.InstanceFeaturesWriteModel, error) {
|
||||||
|
features := command.NewInstanceFeaturesWriteModel(ctx)
|
||||||
|
events, err := filter(ctx, features.Query())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(events) == 0 {
|
||||||
|
return features, nil
|
||||||
|
}
|
||||||
|
features.AppendEvents(events...)
|
||||||
|
err = features.Reduce()
|
||||||
|
return features, err
|
||||||
|
}
|
152
internal/command/v2/instance_features_test.go
Normal file
152
internal/command/v2/instance_features_test.go
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/repository/features"
|
||||||
|
"github.com/caos/zitadel/internal/repository/instance"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSetDefaultFeatures(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
a *instance.Aggregate
|
||||||
|
tierName string
|
||||||
|
tierDescription string
|
||||||
|
state domain.FeaturesState
|
||||||
|
stateDescription string
|
||||||
|
retention time.Duration
|
||||||
|
loginPolicyFactors bool
|
||||||
|
loginPolicyIDP bool
|
||||||
|
loginPolicyPasswordless bool
|
||||||
|
loginPolicyRegistration bool
|
||||||
|
loginPolicyUsernameLogin bool
|
||||||
|
loginPolicyPasswordReset bool
|
||||||
|
passwordComplexityPolicy bool
|
||||||
|
labelPolicyPrivateLabel bool
|
||||||
|
labelPolicyWatermark bool
|
||||||
|
customDomain bool
|
||||||
|
privacyPolicy bool
|
||||||
|
metadataUser bool
|
||||||
|
customTextMessage bool
|
||||||
|
customTextLogin bool
|
||||||
|
lockoutPolicy bool
|
||||||
|
actionsAllowed domain.ActionsAllowed
|
||||||
|
maxActions int
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want Want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "invalid state",
|
||||||
|
args: args{
|
||||||
|
a: instance.NewAggregate("INSTANCE"),
|
||||||
|
tierName: "",
|
||||||
|
tierDescription: "",
|
||||||
|
state: 0,
|
||||||
|
stateDescription: "",
|
||||||
|
retention: 0,
|
||||||
|
loginPolicyFactors: false,
|
||||||
|
loginPolicyIDP: false,
|
||||||
|
loginPolicyPasswordless: false,
|
||||||
|
loginPolicyRegistration: false,
|
||||||
|
loginPolicyUsernameLogin: false,
|
||||||
|
loginPolicyPasswordReset: false,
|
||||||
|
passwordComplexityPolicy: false,
|
||||||
|
labelPolicyPrivateLabel: false,
|
||||||
|
labelPolicyWatermark: false,
|
||||||
|
customDomain: false,
|
||||||
|
privacyPolicy: false,
|
||||||
|
metadataUser: false,
|
||||||
|
customTextMessage: false,
|
||||||
|
customTextLogin: false,
|
||||||
|
lockoutPolicy: false,
|
||||||
|
actionsAllowed: 0,
|
||||||
|
maxActions: 0,
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
ValidationErr: errors.ThrowInvalidArgument(nil, "INSTA-d3r1s", "Errors.Invalid.Argument"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "correct",
|
||||||
|
args: args{
|
||||||
|
a: instance.NewAggregate("INSTANCE"),
|
||||||
|
tierName: "",
|
||||||
|
tierDescription: "",
|
||||||
|
state: domain.FeaturesStateActive,
|
||||||
|
stateDescription: "",
|
||||||
|
retention: 0,
|
||||||
|
loginPolicyFactors: false,
|
||||||
|
loginPolicyIDP: false,
|
||||||
|
loginPolicyPasswordless: false,
|
||||||
|
loginPolicyRegistration: false,
|
||||||
|
loginPolicyUsernameLogin: false,
|
||||||
|
loginPolicyPasswordReset: false,
|
||||||
|
passwordComplexityPolicy: false,
|
||||||
|
labelPolicyPrivateLabel: false,
|
||||||
|
labelPolicyWatermark: false,
|
||||||
|
customDomain: false,
|
||||||
|
privacyPolicy: false,
|
||||||
|
metadataUser: false,
|
||||||
|
customTextMessage: false,
|
||||||
|
customTextLogin: false,
|
||||||
|
lockoutPolicy: false,
|
||||||
|
actionsAllowed: 0,
|
||||||
|
maxActions: 0,
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
Commands: []eventstore.Command{
|
||||||
|
func() *instance.FeaturesSetEvent {
|
||||||
|
event, _ := instance.NewFeaturesSetEvent(context.Background(), &instance.NewAggregate("INSTANCE").Aggregate,
|
||||||
|
[]features.FeaturesChanges{
|
||||||
|
features.ChangeState(domain.FeaturesStateActive),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return event
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
AssertValidation(t, SetDefaultFeatures(
|
||||||
|
tt.args.a,
|
||||||
|
tt.args.tierName,
|
||||||
|
tt.args.tierDescription,
|
||||||
|
tt.args.state,
|
||||||
|
tt.args.stateDescription,
|
||||||
|
tt.args.retention,
|
||||||
|
tt.args.loginPolicyFactors,
|
||||||
|
tt.args.loginPolicyIDP,
|
||||||
|
tt.args.loginPolicyPasswordless,
|
||||||
|
tt.args.loginPolicyRegistration,
|
||||||
|
tt.args.loginPolicyUsernameLogin,
|
||||||
|
tt.args.loginPolicyPasswordReset,
|
||||||
|
tt.args.passwordComplexityPolicy,
|
||||||
|
tt.args.labelPolicyPrivateLabel,
|
||||||
|
tt.args.labelPolicyWatermark,
|
||||||
|
tt.args.customDomain,
|
||||||
|
tt.args.privacyPolicy,
|
||||||
|
tt.args.metadataUser,
|
||||||
|
tt.args.customTextMessage,
|
||||||
|
tt.args.customTextLogin,
|
||||||
|
tt.args.lockoutPolicy,
|
||||||
|
tt.args.actionsAllowed,
|
||||||
|
tt.args.maxActions,
|
||||||
|
), NewMultiFilter().
|
||||||
|
Append(func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return nil, nil
|
||||||
|
}).
|
||||||
|
Filter(),
|
||||||
|
tt.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -62,9 +62,9 @@ func NewFeatureProjection(ctx context.Context, config crdb.StatementHandlerConfi
|
|||||||
crdb.NewColumn(FeatureSequenceCol, crdb.ColumnTypeInt64),
|
crdb.NewColumn(FeatureSequenceCol, crdb.ColumnTypeInt64),
|
||||||
crdb.NewColumn(FeatureIsDefaultCol, crdb.ColumnTypeBool, crdb.Default(false)),
|
crdb.NewColumn(FeatureIsDefaultCol, crdb.ColumnTypeBool, crdb.Default(false)),
|
||||||
crdb.NewColumn(FeatureTierNameCol, crdb.ColumnTypeText),
|
crdb.NewColumn(FeatureTierNameCol, crdb.ColumnTypeText),
|
||||||
crdb.NewColumn(FeatureTierDescriptionCol, crdb.ColumnTypeText),
|
crdb.NewColumn(FeatureTierDescriptionCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||||
crdb.NewColumn(FeatureStateCol, crdb.ColumnTypeEnum, crdb.Default(0)),
|
crdb.NewColumn(FeatureStateCol, crdb.ColumnTypeEnum, crdb.Default(0)),
|
||||||
crdb.NewColumn(FeatureStateDescriptionCol, crdb.ColumnTypeText),
|
crdb.NewColumn(FeatureStateDescriptionCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||||
crdb.NewColumn(FeatureAuditLogRetentionCol, crdb.ColumnTypeInt64, crdb.Default(0)),
|
crdb.NewColumn(FeatureAuditLogRetentionCol, crdb.ColumnTypeInt64, crdb.Default(0)),
|
||||||
crdb.NewColumn(FeatureLoginPolicyFactorsCol, crdb.ColumnTypeBool, crdb.Default(false)),
|
crdb.NewColumn(FeatureLoginPolicyFactorsCol, crdb.ColumnTypeBool, crdb.Default(false)),
|
||||||
crdb.NewColumn(FeatureLoginPolicyIDPCol, crdb.ColumnTypeBool, crdb.Default(false)),
|
crdb.NewColumn(FeatureLoginPolicyIDPCol, crdb.ColumnTypeBool, crdb.Default(false)),
|
||||||
|
@ -1,114 +1,30 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"database/sql"
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"net/url"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/static"
|
"github.com/caos/zitadel/internal/static"
|
||||||
|
"github.com/caos/zitadel/internal/static/database"
|
||||||
"github.com/caos/zitadel/internal/static/s3"
|
"github.com/caos/zitadel/internal/static/s3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AssetStorageConfig struct {
|
type AssetStorageConfig struct {
|
||||||
Type string
|
Type string
|
||||||
Config static.Config
|
Config map[string]interface{} `mapstructure:",remain"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var storage = map[string]func() static.Config{
|
func (a *AssetStorageConfig) NewStorage(client *sql.DB) (static.Storage, error) {
|
||||||
"s3": func() static.Config { return &s3.Config{} },
|
t, ok := storage[a.Type]
|
||||||
"none": func() static.Config { return &NoStorage{} },
|
|
||||||
"": func() static.Config { return &NoStorage{} },
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *AssetStorageConfig) UnmarshalJSON(data []byte) error {
|
|
||||||
var rc struct {
|
|
||||||
Type string
|
|
||||||
Config json.RawMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(data, &rc); err != nil {
|
|
||||||
return errors.ThrowInternal(err, "STATIC-Bfn5r", "error parsing config")
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Type = rc.Type
|
|
||||||
|
|
||||||
var err error
|
|
||||||
c.Config, err = newStorageConfig(c.Type, rc.Config)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newStorageConfig(storageType string, configData []byte) (static.Config, error) {
|
|
||||||
t, ok := storage[storageType]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.ThrowInternalf(nil, "STATIC-dsbjh", "config type %s not supported", storageType)
|
return nil, errors.ThrowInternalf(nil, "STATIC-dsbjh", "config type %s not supported", a.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
staticConfig := t()
|
return t(client, a.Config)
|
||||||
if len(configData) == 0 {
|
|
||||||
return staticConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(configData, staticConfig); err != nil {
|
|
||||||
return nil, errors.ThrowInternal(err, "STATIC-GB4nw", "Could not read config: %v")
|
|
||||||
}
|
|
||||||
|
|
||||||
return staticConfig, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var storage = map[string]static.CreateStorage{
|
||||||
errNoStorage = errors.ThrowInternal(nil, "STATIC-ashg4", "Errors.Assets.Store.NotConfigured")
|
"db": database.NewStorage,
|
||||||
)
|
"": database.NewStorage,
|
||||||
|
"s3": s3.NewStorage,
|
||||||
type NoStorage struct{}
|
|
||||||
|
|
||||||
func (_ *NoStorage) NewStorage() (static.Storage, error) {
|
|
||||||
return &NoStorage{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *NoStorage) CreateBucket(ctx context.Context, name, location string) error {
|
|
||||||
return errNoStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *NoStorage) RemoveBucket(ctx context.Context, name string) error {
|
|
||||||
return errNoStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *NoStorage) ListBuckets(ctx context.Context) ([]*domain.BucketInfo, error) {
|
|
||||||
return nil, errNoStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *NoStorage) PutObject(ctx context.Context, bucketName, objectName, contentType string, object io.Reader, objectSize int64, createBucketIfNotExisting bool) (*domain.AssetInfo, error) {
|
|
||||||
return nil, errNoStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *NoStorage) GetObjectInfo(ctx context.Context, bucketName, objectName string) (*domain.AssetInfo, error) {
|
|
||||||
return nil, errNoStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *NoStorage) GetObject(ctx context.Context, bucketName, objectName string) (io.Reader, func() (*domain.AssetInfo, error), error) {
|
|
||||||
return nil, nil, errNoStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *NoStorage) ListObjectInfos(ctx context.Context, bucketName, prefix string, recursive bool) ([]*domain.AssetInfo, error) {
|
|
||||||
return nil, errNoStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *NoStorage) GetObjectPresignedURL(ctx context.Context, bucketName, objectName string, expiration time.Duration) (*url.URL, error) {
|
|
||||||
return nil, errNoStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *NoStorage) RemoveObject(ctx context.Context, bucketName, objectName string) error {
|
|
||||||
return errNoStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *NoStorage) RemoveObjects(ctx context.Context, bucketName, path string, recursive bool) error {
|
|
||||||
return errNoStorage
|
|
||||||
}
|
}
|
||||||
|
182
internal/static/database/crdb.go
Normal file
182
internal/static/database/crdb.go
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
errs "errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Masterminds/squirrel"
|
||||||
|
|
||||||
|
caos_errors "github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/static"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ static.Storage = (*crdbStorage)(nil)
|
||||||
|
|
||||||
|
const (
|
||||||
|
assetsTable = "system.assets"
|
||||||
|
AssetColInstanceID = "instance_id"
|
||||||
|
AssetColType = "asset_type"
|
||||||
|
AssetColLocation = "location"
|
||||||
|
AssetColResourceOwner = "resource_owner"
|
||||||
|
AssetColName = "name"
|
||||||
|
AssetColData = "data"
|
||||||
|
AssetColContentType = "content_type"
|
||||||
|
AssetColHash = "hash"
|
||||||
|
AssetColUpdatedAt = "updated_at"
|
||||||
|
)
|
||||||
|
|
||||||
|
type crdbStorage struct {
|
||||||
|
client *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStorage(client *sql.DB, _ map[string]interface{}) (static.Storage, error) {
|
||||||
|
return &crdbStorage{client: client}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *crdbStorage) PutObject(ctx context.Context, instanceID, location, resourceOwner, name, contentType string, objectType static.ObjectType, object io.Reader, objectSize int64) (*static.Asset, error) {
|
||||||
|
data, err := io.ReadAll(object)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errors.ThrowInternal(err, "DATAB-Dfwvq", "Errors.Internal")
|
||||||
|
}
|
||||||
|
stmt, args, err := squirrel.Insert(assetsTable).
|
||||||
|
Columns(AssetColInstanceID, AssetColResourceOwner, AssetColName, AssetColType, AssetColContentType, AssetColData, AssetColUpdatedAt).
|
||||||
|
Values(instanceID, resourceOwner, name, objectType, contentType, data, "now()").
|
||||||
|
Suffix(fmt.Sprintf(
|
||||||
|
"ON CONFLICT (%s, %s, %s) DO UPDATE"+
|
||||||
|
" SET %s = $5, %s = $6"+
|
||||||
|
" RETURNING %s, %s", AssetColInstanceID, AssetColResourceOwner, AssetColName, AssetColContentType, AssetColData, AssetColHash, AssetColUpdatedAt)).
|
||||||
|
PlaceholderFormat(squirrel.Dollar).
|
||||||
|
ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errors.ThrowInternal(err, "DATAB-32DG1", "Errors.Internal")
|
||||||
|
}
|
||||||
|
var hash string
|
||||||
|
var updatedAt time.Time
|
||||||
|
err = c.client.QueryRowContext(ctx, stmt, args...).Scan(&hash, &updatedAt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errors.ThrowInternal(err, "DATAB-D2g2q", "Errors.Internal")
|
||||||
|
}
|
||||||
|
return &static.Asset{
|
||||||
|
InstanceID: instanceID,
|
||||||
|
Name: name,
|
||||||
|
Hash: hash,
|
||||||
|
Size: objectSize,
|
||||||
|
LastModified: updatedAt,
|
||||||
|
Location: location,
|
||||||
|
ContentType: contentType,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *crdbStorage) GetObject(ctx context.Context, instanceID, resourceOwner, name string) ([]byte, func() (*static.Asset, error), error) {
|
||||||
|
query, args, err := squirrel.Select(AssetColData, AssetColContentType, AssetColHash, AssetColUpdatedAt).
|
||||||
|
From(assetsTable).
|
||||||
|
Where(squirrel.Eq{
|
||||||
|
AssetColInstanceID: instanceID,
|
||||||
|
AssetColResourceOwner: resourceOwner,
|
||||||
|
AssetColName: name,
|
||||||
|
}).
|
||||||
|
PlaceholderFormat(squirrel.Dollar).
|
||||||
|
ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, caos_errors.ThrowInternal(err, "DATAB-GE3hz", "Errors.Internal")
|
||||||
|
}
|
||||||
|
var data []byte
|
||||||
|
asset := &static.Asset{
|
||||||
|
InstanceID: instanceID,
|
||||||
|
ResourceOwner: resourceOwner,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
err = c.client.QueryRowContext(ctx, query, args...).
|
||||||
|
Scan(
|
||||||
|
&data,
|
||||||
|
&asset.ContentType,
|
||||||
|
&asset.Hash,
|
||||||
|
&asset.LastModified,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errs.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, nil, caos_errors.ThrowNotFound(err, "DATAB-pCP8P", "Errors.Assets.Object.NotFound")
|
||||||
|
}
|
||||||
|
return nil, nil, caos_errors.ThrowInternal(err, "DATAB-Sfgb3", "Errors.Assets.Object.GetFailed")
|
||||||
|
}
|
||||||
|
asset.Size = int64(len(data))
|
||||||
|
return data,
|
||||||
|
func() (*static.Asset, error) {
|
||||||
|
return asset, nil
|
||||||
|
},
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *crdbStorage) GetObjectInfo(ctx context.Context, instanceID, resourceOwner, name string) (*static.Asset, error) {
|
||||||
|
query, args, err := squirrel.Select(AssetColContentType, AssetColLocation, "length("+AssetColData+")", AssetColHash, AssetColUpdatedAt).
|
||||||
|
From(assetsTable).
|
||||||
|
Where(squirrel.Eq{
|
||||||
|
AssetColInstanceID: instanceID,
|
||||||
|
AssetColResourceOwner: resourceOwner,
|
||||||
|
AssetColName: name,
|
||||||
|
}).
|
||||||
|
PlaceholderFormat(squirrel.Dollar).
|
||||||
|
ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errors.ThrowInternal(err, "DATAB-rggt2", "Errors.Internal")
|
||||||
|
}
|
||||||
|
asset := &static.Asset{
|
||||||
|
InstanceID: instanceID,
|
||||||
|
ResourceOwner: resourceOwner,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
err = c.client.QueryRowContext(ctx, query, args...).
|
||||||
|
Scan(
|
||||||
|
&asset.ContentType,
|
||||||
|
&asset.Location,
|
||||||
|
&asset.Size,
|
||||||
|
&asset.Hash,
|
||||||
|
&asset.LastModified,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errors.ThrowInternal(err, "DATAB-Dbh2s", "Errors.Internal")
|
||||||
|
}
|
||||||
|
return asset, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *crdbStorage) RemoveObject(ctx context.Context, instanceID, resourceOwner, name string) error {
|
||||||
|
stmt, args, err := squirrel.Delete(assetsTable).
|
||||||
|
Where(squirrel.Eq{
|
||||||
|
AssetColInstanceID: instanceID,
|
||||||
|
AssetColResourceOwner: resourceOwner,
|
||||||
|
AssetColName: name,
|
||||||
|
}).
|
||||||
|
PlaceholderFormat(squirrel.Dollar).
|
||||||
|
ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return caos_errors.ThrowInternal(err, "DATAB-Sgvwq", "Errors.Internal")
|
||||||
|
}
|
||||||
|
_, err = c.client.ExecContext(ctx, stmt, args...)
|
||||||
|
if err != nil {
|
||||||
|
return caos_errors.ThrowInternal(err, "DATAB-RHNgf", "Errors.Assets.Object.RemoveFailed")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *crdbStorage) RemoveObjects(ctx context.Context, instanceID, resourceOwner string, objectType static.ObjectType) error {
|
||||||
|
stmt, args, err := squirrel.Delete(assetsTable).
|
||||||
|
Where(squirrel.Eq{
|
||||||
|
AssetColInstanceID: instanceID,
|
||||||
|
AssetColResourceOwner: resourceOwner,
|
||||||
|
AssetColType: objectType,
|
||||||
|
}).
|
||||||
|
PlaceholderFormat(squirrel.Dollar).
|
||||||
|
ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return caos_errors.ThrowInternal(err, "DATAB-Sfgeq", "Errors.Internal")
|
||||||
|
}
|
||||||
|
_, err = c.client.ExecContext(ctx, stmt, args...)
|
||||||
|
if err != nil {
|
||||||
|
return caos_errors.ThrowInternal(err, "DATAB-Efgt2", "Errors.Assets.Object.RemoveFailed")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
203
internal/static/database/crdb_test.go
Normal file
203
internal/static/database/crdb_test.go
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"database/sql/driver"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/static"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
testNow = time.Now()
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
objectStmt = "INSERT INTO system.assets" +
|
||||||
|
" (instance_id,resource_owner,name,asset_type,content_type,data,updated_at)" +
|
||||||
|
" VALUES ($1,$2,$3,$4,$5,$6,$7)" +
|
||||||
|
" ON CONFLICT (instance_id, resource_owner, name) DO UPDATE SET" +
|
||||||
|
" content_type = $5, data = $6" +
|
||||||
|
" RETURNING hash"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_crdbStorage_CreateObject(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
client db
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
instanceID string
|
||||||
|
location string
|
||||||
|
resourceOwner string
|
||||||
|
name string
|
||||||
|
contentType string
|
||||||
|
objectType static.ObjectType
|
||||||
|
data io.Reader
|
||||||
|
objectSize int64
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want *static.Asset
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"create ok",
|
||||||
|
fields{
|
||||||
|
client: prepareDB(t,
|
||||||
|
expectQuery(
|
||||||
|
objectStmt,
|
||||||
|
[]string{
|
||||||
|
"hash",
|
||||||
|
"updated_at",
|
||||||
|
},
|
||||||
|
[][]driver.Value{
|
||||||
|
{
|
||||||
|
"md5Hash",
|
||||||
|
testNow,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"instanceID",
|
||||||
|
"resourceOwner",
|
||||||
|
"name",
|
||||||
|
static.ObjectTypeUserAvatar,
|
||||||
|
"contentType",
|
||||||
|
[]byte("test"),
|
||||||
|
"now()",
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
instanceID: "instanceID",
|
||||||
|
location: "location",
|
||||||
|
resourceOwner: "resourceOwner",
|
||||||
|
name: "name",
|
||||||
|
contentType: "contentType",
|
||||||
|
data: bytes.NewReader([]byte("test")),
|
||||||
|
objectSize: 4,
|
||||||
|
},
|
||||||
|
&static.Asset{
|
||||||
|
InstanceID: "instanceID",
|
||||||
|
Name: "name",
|
||||||
|
Hash: "md5Hash",
|
||||||
|
Size: 4,
|
||||||
|
LastModified: testNow,
|
||||||
|
Location: "location",
|
||||||
|
ContentType: "contentType",
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
c := &crdbStorage{
|
||||||
|
client: tt.fields.client.db,
|
||||||
|
}
|
||||||
|
got, err := c.PutObject(tt.args.ctx, tt.args.instanceID, tt.args.location, tt.args.resourceOwner, tt.args.name, tt.args.contentType, tt.args.objectType, tt.args.data, tt.args.objectSize)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("CreateObject() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("CreateObject() got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type db struct {
|
||||||
|
mock sqlmock.Sqlmock
|
||||||
|
db *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareDB(t *testing.T, expectations ...expectation) db {
|
||||||
|
t.Helper()
|
||||||
|
client, mock, err := sqlmock.New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create sql mock: %v", err)
|
||||||
|
}
|
||||||
|
for _, expectation := range expectations {
|
||||||
|
expectation(mock)
|
||||||
|
}
|
||||||
|
return db{
|
||||||
|
mock: mock,
|
||||||
|
db: client,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type expectation func(m sqlmock.Sqlmock)
|
||||||
|
|
||||||
|
func expectExists(query string, value bool, args ...driver.Value) expectation {
|
||||||
|
return func(m sqlmock.Sqlmock) {
|
||||||
|
m.ExpectQuery(regexp.QuoteMeta(query)).WithArgs(args...).WillReturnRows(sqlmock.NewRows([]string{"exists"}).AddRow(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectQueryErr(query string, err error, args ...driver.Value) expectation {
|
||||||
|
return func(m sqlmock.Sqlmock) {
|
||||||
|
m.ExpectQuery(regexp.QuoteMeta(query)).WithArgs(args...).WillReturnError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func expectQuery(stmt string, cols []string, rows [][]driver.Value, args ...driver.Value) func(m sqlmock.Sqlmock) {
|
||||||
|
return func(m sqlmock.Sqlmock) {
|
||||||
|
q := m.ExpectQuery(regexp.QuoteMeta(stmt)).WithArgs(args...)
|
||||||
|
result := sqlmock.NewRows(cols)
|
||||||
|
count := uint64(len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
if cols[len(cols)-1] == "count" {
|
||||||
|
row = append(row, count)
|
||||||
|
}
|
||||||
|
result.AddRow(row...)
|
||||||
|
}
|
||||||
|
q.WillReturnRows(result)
|
||||||
|
q.RowsWillBeClosed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectExec(stmt string, err error, args ...driver.Value) expectation {
|
||||||
|
return func(m sqlmock.Sqlmock) {
|
||||||
|
query := m.ExpectExec(regexp.QuoteMeta(stmt)).WithArgs(args...)
|
||||||
|
if err != nil {
|
||||||
|
query.WillReturnError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
query.WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectBegin(err error) expectation {
|
||||||
|
return func(m sqlmock.Sqlmock) {
|
||||||
|
query := m.ExpectBegin()
|
||||||
|
if err != nil {
|
||||||
|
query.WillReturnError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectCommit(err error) expectation {
|
||||||
|
return func(m sqlmock.Sqlmock) {
|
||||||
|
query := m.ExpectCommit()
|
||||||
|
if err != nil {
|
||||||
|
query.WillReturnError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectRollback(err error) expectation {
|
||||||
|
return func(m sqlmock.Sqlmock) {
|
||||||
|
query := m.ExpectRollback()
|
||||||
|
if err != nil {
|
||||||
|
query.WillReturnError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ Errors:
|
|||||||
Object:
|
Object:
|
||||||
PutFailed: Objekt konnte nicht erstellt werden
|
PutFailed: Objekt konnte nicht erstellt werden
|
||||||
GetFailed: Objekt konnte nicht gelesen werden
|
GetFailed: Objekt konnte nicht gelesen werden
|
||||||
|
NotFound: Objekt konnte nicht gefunden werden
|
||||||
PresignedTokenFailed: Signiertes Token konnte nicht erstellt werden
|
PresignedTokenFailed: Signiertes Token konnte nicht erstellt werden
|
||||||
ListFailed: Objektliste konnte nicht gelesen werden
|
ListFailed: Objektliste konnte nicht gelesen werden
|
||||||
RemoveFailed: Objekt konnte nicht gelöscht werden
|
RemoveFailed: Objekt konnte nicht gelöscht werden
|
||||||
|
@ -22,6 +22,7 @@ Errors:
|
|||||||
Object:
|
Object:
|
||||||
PutFailed: Object not created
|
PutFailed: Object not created
|
||||||
GetFailed: Object could not be read
|
GetFailed: Object could not be read
|
||||||
|
NotFound: Object could not be found
|
||||||
PresignedTokenFailed: Signed token could not be created
|
PresignedTokenFailed: Signed token could not be created
|
||||||
ListFailed: Objectlist could not be read
|
ListFailed: Objectlist could not be read
|
||||||
RemoveFailed: Object could not be removed
|
RemoveFailed: Object could not be removed
|
||||||
|
@ -22,6 +22,7 @@ Errors:
|
|||||||
Object:
|
Object:
|
||||||
PutFailed: Oggetto non creato
|
PutFailed: Oggetto non creato
|
||||||
GetFailed: Oggetto non può essere letto
|
GetFailed: Oggetto non può essere letto
|
||||||
|
NotFound: Oggetto non trovato
|
||||||
PresignedTokenFailed: Il token non può essere creato
|
PresignedTokenFailed: Il token non può essere creato
|
||||||
ListFailed: La lista degli oggetti non può essere letta
|
ListFailed: La lista degli oggetti non può essere letta
|
||||||
RemoveFailed: L'oggetto non può essere rimosso
|
RemoveFailed: L'oggetto non può essere rimosso
|
||||||
|
@ -7,11 +7,8 @@ package mock
|
|||||||
import (
|
import (
|
||||||
context "context"
|
context "context"
|
||||||
io "io"
|
io "io"
|
||||||
url "net/url"
|
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
time "time"
|
|
||||||
|
|
||||||
domain "github.com/caos/zitadel/internal/domain"
|
|
||||||
static "github.com/caos/zitadel/internal/static"
|
static "github.com/caos/zitadel/internal/static"
|
||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
)
|
)
|
||||||
@ -39,187 +36,76 @@ func (m *MockStorage) EXPECT() *MockStorageMockRecorder {
|
|||||||
return m.recorder
|
return m.recorder
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateBucket mocks base method.
|
|
||||||
func (m *MockStorage) CreateBucket(ctx context.Context, name, location string) error {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "CreateBucket", ctx, name, location)
|
|
||||||
ret0, _ := ret[0].(error)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateBucket indicates an expected call of CreateBucket.
|
|
||||||
func (mr *MockStorageMockRecorder) CreateBucket(ctx, name, location interface{}) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBucket", reflect.TypeOf((*MockStorage)(nil).CreateBucket), ctx, name, location)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetObject mocks base method.
|
// GetObject mocks base method.
|
||||||
func (m *MockStorage) GetObject(ctx context.Context, bucketName, objectName string) (io.Reader, func() (*domain.AssetInfo, error), error) {
|
func (m *MockStorage) GetObject(ctx context.Context, instanceID, resourceOwner, name string) ([]byte, func() (*static.Asset, error), error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "GetObject", ctx, bucketName, objectName)
|
ret := m.ctrl.Call(m, "GetObject", ctx, instanceID, resourceOwner, name)
|
||||||
ret0, _ := ret[0].(io.Reader)
|
ret0, _ := ret[0].([]byte)
|
||||||
ret1, _ := ret[1].(func() (*domain.AssetInfo, error))
|
ret1, _ := ret[1].(func() (*static.Asset, error))
|
||||||
ret2, _ := ret[2].(error)
|
ret2, _ := ret[2].(error)
|
||||||
return ret0, ret1, ret2
|
return ret0, ret1, ret2
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetObject indicates an expected call of GetObject.
|
// GetObject indicates an expected call of GetObject.
|
||||||
func (mr *MockStorageMockRecorder) GetObject(ctx, bucketName, objectName interface{}) *gomock.Call {
|
func (mr *MockStorageMockRecorder) GetObject(ctx, instanceID, resourceOwner, name interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObject", reflect.TypeOf((*MockStorage)(nil).GetObject), ctx, bucketName, objectName)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObject", reflect.TypeOf((*MockStorage)(nil).GetObject), ctx, instanceID, resourceOwner, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetObjectInfo mocks base method.
|
// GetObjectInfo mocks base method.
|
||||||
func (m *MockStorage) GetObjectInfo(ctx context.Context, bucketName, objectName string) (*domain.AssetInfo, error) {
|
func (m *MockStorage) GetObjectInfo(ctx context.Context, instanceID, resourceOwner, name string) (*static.Asset, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "GetObjectInfo", ctx, bucketName, objectName)
|
ret := m.ctrl.Call(m, "GetObjectInfo", ctx, instanceID, resourceOwner, name)
|
||||||
ret0, _ := ret[0].(*domain.AssetInfo)
|
ret0, _ := ret[0].(*static.Asset)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetObjectInfo indicates an expected call of GetObjectInfo.
|
// GetObjectInfo indicates an expected call of GetObjectInfo.
|
||||||
func (mr *MockStorageMockRecorder) GetObjectInfo(ctx, bucketName, objectName interface{}) *gomock.Call {
|
func (mr *MockStorageMockRecorder) GetObjectInfo(ctx, instanceID, resourceOwner, name interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObjectInfo", reflect.TypeOf((*MockStorage)(nil).GetObjectInfo), ctx, bucketName, objectName)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObjectInfo", reflect.TypeOf((*MockStorage)(nil).GetObjectInfo), ctx, instanceID, resourceOwner, name)
|
||||||
}
|
|
||||||
|
|
||||||
// GetObjectPresignedURL mocks base method.
|
|
||||||
func (m *MockStorage) GetObjectPresignedURL(ctx context.Context, bucketName, objectName string, expiration time.Duration) (*url.URL, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "GetObjectPresignedURL", ctx, bucketName, objectName, expiration)
|
|
||||||
ret0, _ := ret[0].(*url.URL)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetObjectPresignedURL indicates an expected call of GetObjectPresignedURL.
|
|
||||||
func (mr *MockStorageMockRecorder) GetObjectPresignedURL(ctx, bucketName, objectName, expiration interface{}) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObjectPresignedURL", reflect.TypeOf((*MockStorage)(nil).GetObjectPresignedURL), ctx, bucketName, objectName, expiration)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListBuckets mocks base method.
|
|
||||||
func (m *MockStorage) ListBuckets(ctx context.Context) ([]*domain.BucketInfo, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "ListBuckets", ctx)
|
|
||||||
ret0, _ := ret[0].([]*domain.BucketInfo)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListBuckets indicates an expected call of ListBuckets.
|
|
||||||
func (mr *MockStorageMockRecorder) ListBuckets(ctx interface{}) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListBuckets", reflect.TypeOf((*MockStorage)(nil).ListBuckets), ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListObjectInfos mocks base method.
|
|
||||||
func (m *MockStorage) ListObjectInfos(ctx context.Context, bucketName, prefix string, recursive bool) ([]*domain.AssetInfo, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "ListObjectInfos", ctx, bucketName, prefix, recursive)
|
|
||||||
ret0, _ := ret[0].([]*domain.AssetInfo)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListObjectInfos indicates an expected call of ListObjectInfos.
|
|
||||||
func (mr *MockStorageMockRecorder) ListObjectInfos(ctx, bucketName, prefix, recursive interface{}) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListObjectInfos", reflect.TypeOf((*MockStorage)(nil).ListObjectInfos), ctx, bucketName, prefix, recursive)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutObject mocks base method.
|
// PutObject mocks base method.
|
||||||
func (m *MockStorage) PutObject(ctx context.Context, bucketName, objectName, contentType string, object io.Reader, objectSize int64, createBucketIfNotExisting bool) (*domain.AssetInfo, error) {
|
func (m *MockStorage) PutObject(ctx context.Context, instanceID, location, resourceOwner, name, contentType string, objectType static.ObjectType, object io.Reader, objectSize int64) (*static.Asset, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "PutObject", ctx, bucketName, objectName, contentType, object, objectSize, createBucketIfNotExisting)
|
ret := m.ctrl.Call(m, "PutObject", ctx, instanceID, location, resourceOwner, name, contentType, objectType, object, objectSize)
|
||||||
ret0, _ := ret[0].(*domain.AssetInfo)
|
ret0, _ := ret[0].(*static.Asset)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutObject indicates an expected call of PutObject.
|
// PutObject indicates an expected call of PutObject.
|
||||||
func (mr *MockStorageMockRecorder) PutObject(ctx, bucketName, objectName, contentType, object, objectSize, createBucketIfNotExisting interface{}) *gomock.Call {
|
func (mr *MockStorageMockRecorder) PutObject(ctx, instanceID, location, resourceOwner, name, contentType, objectType, object, objectSize interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutObject", reflect.TypeOf((*MockStorage)(nil).PutObject), ctx, bucketName, objectName, contentType, object, objectSize, createBucketIfNotExisting)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutObject", reflect.TypeOf((*MockStorage)(nil).PutObject), ctx, instanceID, location, resourceOwner, name, contentType, objectType, object, objectSize)
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveBucket mocks base method.
|
|
||||||
func (m *MockStorage) RemoveBucket(ctx context.Context, name string) error {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "RemoveBucket", ctx, name)
|
|
||||||
ret0, _ := ret[0].(error)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveBucket indicates an expected call of RemoveBucket.
|
|
||||||
func (mr *MockStorageMockRecorder) RemoveBucket(ctx, name interface{}) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveBucket", reflect.TypeOf((*MockStorage)(nil).RemoveBucket), ctx, name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveObject mocks base method.
|
// RemoveObject mocks base method.
|
||||||
func (m *MockStorage) RemoveObject(ctx context.Context, bucketName, objectName string) error {
|
func (m *MockStorage) RemoveObject(ctx context.Context, instanceID, resourceOwner, name string) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "RemoveObject", ctx, bucketName, objectName)
|
ret := m.ctrl.Call(m, "RemoveObject", ctx, instanceID, resourceOwner, name)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
return ret0
|
return ret0
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveObject indicates an expected call of RemoveObject.
|
// RemoveObject indicates an expected call of RemoveObject.
|
||||||
func (mr *MockStorageMockRecorder) RemoveObject(ctx, bucketName, objectName interface{}) *gomock.Call {
|
func (mr *MockStorageMockRecorder) RemoveObject(ctx, instanceID, resourceOwner, name interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveObject", reflect.TypeOf((*MockStorage)(nil).RemoveObject), ctx, bucketName, objectName)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveObject", reflect.TypeOf((*MockStorage)(nil).RemoveObject), ctx, instanceID, resourceOwner, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveObjects mocks base method.
|
// RemoveObjects mocks base method.
|
||||||
func (m *MockStorage) RemoveObjects(ctx context.Context, bucketName, path string, recursive bool) error {
|
func (m *MockStorage) RemoveObjects(ctx context.Context, instanceID, resourceOwner string, objectType static.ObjectType) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "RemoveObjects", ctx, bucketName, path, recursive)
|
ret := m.ctrl.Call(m, "RemoveObjects", ctx, instanceID, resourceOwner, objectType)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
return ret0
|
return ret0
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveObjects indicates an expected call of RemoveObjects.
|
// RemoveObjects indicates an expected call of RemoveObjects.
|
||||||
func (mr *MockStorageMockRecorder) RemoveObjects(ctx, bucketName, path, recursive interface{}) *gomock.Call {
|
func (mr *MockStorageMockRecorder) RemoveObjects(ctx, instanceID, resourceOwner, objectType interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveObjects", reflect.TypeOf((*MockStorage)(nil).RemoveObjects), ctx, bucketName, path, recursive)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveObjects", reflect.TypeOf((*MockStorage)(nil).RemoveObjects), ctx, instanceID, resourceOwner, objectType)
|
||||||
}
|
|
||||||
|
|
||||||
// MockConfig is a mock of Config interface.
|
|
||||||
type MockConfig struct {
|
|
||||||
ctrl *gomock.Controller
|
|
||||||
recorder *MockConfigMockRecorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockConfigMockRecorder is the mock recorder for MockConfig.
|
|
||||||
type MockConfigMockRecorder struct {
|
|
||||||
mock *MockConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMockConfig creates a new mock instance.
|
|
||||||
func NewMockConfig(ctrl *gomock.Controller) *MockConfig {
|
|
||||||
mock := &MockConfig{ctrl: ctrl}
|
|
||||||
mock.recorder = &MockConfigMockRecorder{mock}
|
|
||||||
return mock
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
|
||||||
func (m *MockConfig) EXPECT() *MockConfigMockRecorder {
|
|
||||||
return m.recorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStorage mocks base method.
|
|
||||||
func (m *MockConfig) NewStorage() (static.Storage, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "NewStorage")
|
|
||||||
ret0, _ := ret[0].(static.Storage)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStorage indicates an expected call of NewStorage.
|
|
||||||
func (mr *MockConfigMockRecorder) NewStorage() *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewStorage", reflect.TypeOf((*MockConfig)(nil).NewStorage))
|
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,49 @@
|
|||||||
package mock
|
package mock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
|
|
||||||
caos_errors "github.com/caos/zitadel/internal/errors"
|
caos_errors "github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/static"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewStorage(t *testing.T) *MockStorage {
|
func NewStorage(t *testing.T) *MockStorage {
|
||||||
return NewMockStorage(gomock.NewController(t))
|
return NewMockStorage(gomock.NewController(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockStorage) ExpectAddObjectNoError() *MockStorage {
|
func (m *MockStorage) ExpectPutObject() *MockStorage {
|
||||||
m.EXPECT().
|
m.EXPECT().
|
||||||
PutObject(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
|
PutObject(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
|
||||||
Return(nil, nil)
|
DoAndReturn(func(ctx context.Context, instanceID, location, resourceOwner, name, contentType string, objectType static.ObjectType, object io.Reader, objectSize int64) (*static.Asset, error) {
|
||||||
|
hash, _ := io.ReadAll(object)
|
||||||
|
return &static.Asset{
|
||||||
|
InstanceID: instanceID,
|
||||||
|
Name: name,
|
||||||
|
Hash: string(hash),
|
||||||
|
Size: objectSize,
|
||||||
|
LastModified: time.Now(),
|
||||||
|
Location: location,
|
||||||
|
ContentType: contentType,
|
||||||
|
}, nil
|
||||||
|
})
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockStorage) ExpectAddObjectError() *MockStorage {
|
func (m *MockStorage) ExpectPutObjectError() *MockStorage {
|
||||||
m.EXPECT().
|
m.EXPECT().
|
||||||
PutObject(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
|
PutObject(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
|
||||||
Return(nil, caos_errors.ThrowInternal(nil, "", ""))
|
Return(nil, caos_errors.ThrowInternal(nil, "", ""))
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockStorage) ExpectRemoveObjectNoError() *MockStorage {
|
func (m *MockStorage) ExpectRemoveObjectNoError() *MockStorage {
|
||||||
m.EXPECT().
|
m.EXPECT().
|
||||||
RemoveObject(gomock.Any(), gomock.Any(), gomock.Any()).
|
RemoveObject(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
|
||||||
Return(nil)
|
Return(nil)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
@ -42,7 +57,7 @@ func (m *MockStorage) ExpectRemoveObjectsNoError() *MockStorage {
|
|||||||
|
|
||||||
func (m *MockStorage) ExpectRemoveObjectError() *MockStorage {
|
func (m *MockStorage) ExpectRemoveObjectError() *MockStorage {
|
||||||
m.EXPECT().
|
m.EXPECT().
|
||||||
RemoveObject(gomock.Any(), gomock.Any(), gomock.Any()).
|
RemoveObject(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
|
||||||
Return(caos_errors.ThrowInternal(nil, "", ""))
|
Return(caos_errors.ThrowInternal(nil, "", ""))
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package s3
|
package s3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/minio/minio-go/v7"
|
"github.com/minio/minio-go/v7"
|
||||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/static"
|
"github.com/caos/zitadel/internal/static"
|
||||||
)
|
)
|
||||||
@ -34,3 +38,15 @@ func (c *Config) NewStorage() (static.Storage, error) {
|
|||||||
MultiDelete: c.MultiDelete,
|
MultiDelete: c.MultiDelete,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewStorage(_ *sql.DB, rawConfig map[string]interface{}) (static.Storage, error) {
|
||||||
|
configData, err := json.Marshal(rawConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ThrowInternal(err, "MINIO-Ef2f2", "could not map config")
|
||||||
|
}
|
||||||
|
c := new(Config)
|
||||||
|
if err := json.Unmarshal(configData, c); err != nil {
|
||||||
|
return nil, errors.ThrowInternal(err, "MINIO-GB4nw", "could not map config")
|
||||||
|
}
|
||||||
|
return c.NewStorage()
|
||||||
|
}
|
||||||
|
@ -2,11 +2,10 @@ package s3
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
"github.com/minio/minio-go/v7"
|
"github.com/minio/minio-go/v7"
|
||||||
@ -14,8 +13,11 @@ import (
|
|||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/static"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ static.Storage = (*Minio)(nil)
|
||||||
|
|
||||||
type Minio struct {
|
type Minio struct {
|
||||||
Client *minio.Client
|
Client *minio.Client
|
||||||
Location string
|
Location string
|
||||||
@ -23,129 +25,66 @@ type Minio struct {
|
|||||||
MultiDelete bool
|
MultiDelete bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Minio) CreateBucket(ctx context.Context, name, location string) error {
|
func (m *Minio) PutObject(ctx context.Context, instanceID, location, resourceOwner, name, contentType string, objectType static.ObjectType, object io.Reader, objectSize int64) (*static.Asset, error) {
|
||||||
if location == "" {
|
err := m.createBucket(ctx, instanceID, location)
|
||||||
location = m.Location
|
if err != nil && !caos_errs.IsErrorAlreadyExists(err) {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
name = m.prefixBucketName(name)
|
bucketName := m.prefixBucketName(instanceID)
|
||||||
exists, err := m.Client.BucketExists(ctx, name)
|
objectName := fmt.Sprintf("%s/%s", resourceOwner, name)
|
||||||
if err != nil {
|
|
||||||
logging.LogWithFields("MINIO-ADvf3", "bucketname", name).WithError(err).Error("cannot check if bucket exists")
|
|
||||||
return caos_errs.ThrowInternal(err, "MINIO-1b8fs", "Errors.Assets.Bucket.Internal")
|
|
||||||
}
|
|
||||||
if exists {
|
|
||||||
return caos_errs.ThrowAlreadyExists(nil, "MINIO-9n3MK", "Errors.Assets.Bucket.AlreadyExists")
|
|
||||||
}
|
|
||||||
err = m.Client.MakeBucket(ctx, name, minio.MakeBucketOptions{Region: location})
|
|
||||||
if err != nil {
|
|
||||||
return caos_errs.ThrowInternal(err, "MINIO-4m90d", "Errors.Assets.Bucket.CreateFailed")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Minio) ListBuckets(ctx context.Context) ([]*domain.BucketInfo, error) {
|
|
||||||
infos, err := m.Client.ListBuckets(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, caos_errs.ThrowInternal(err, "MINIO-390OP", "Errors.Assets.Bucket.ListFailed")
|
|
||||||
}
|
|
||||||
buckets := make([]*domain.BucketInfo, len(infos))
|
|
||||||
for i, info := range infos {
|
|
||||||
buckets[i] = &domain.BucketInfo{
|
|
||||||
Name: info.Name,
|
|
||||||
CreationDate: info.CreationDate,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buckets, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Minio) RemoveBucket(ctx context.Context, name string) error {
|
|
||||||
name = m.prefixBucketName(name)
|
|
||||||
err := m.Client.RemoveBucket(ctx, name)
|
|
||||||
if err != nil {
|
|
||||||
return caos_errs.ThrowInternal(err, "MINIO-338Hs", "Errors.Assets.Bucket.RemoveFailed")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Minio) PutObject(ctx context.Context, bucketName, objectName, contentType string, object io.Reader, objectSize int64, createBucketIfNotExisting bool) (*domain.AssetInfo, error) {
|
|
||||||
if createBucketIfNotExisting {
|
|
||||||
err := m.CreateBucket(ctx, bucketName, "")
|
|
||||||
if err != nil && !caos_errs.IsErrorAlreadyExists(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bucketName = m.prefixBucketName(bucketName)
|
|
||||||
info, err := m.Client.PutObject(ctx, bucketName, objectName, object, objectSize, minio.PutObjectOptions{ContentType: contentType})
|
info, err := m.Client.PutObject(ctx, bucketName, objectName, object, objectSize, minio.PutObjectOptions{ContentType: contentType})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, caos_errs.ThrowInternal(err, "MINIO-590sw", "Errors.Assets.Object.PutFailed")
|
return nil, caos_errs.ThrowInternal(err, "MINIO-590sw", "Errors.Assets.Object.PutFailed")
|
||||||
}
|
}
|
||||||
return &domain.AssetInfo{
|
return &static.Asset{
|
||||||
Bucket: info.Bucket,
|
InstanceID: info.Bucket,
|
||||||
Key: info.Key,
|
ResourceOwner: resourceOwner,
|
||||||
ETag: info.ETag,
|
Name: info.Key,
|
||||||
Size: info.Size,
|
Hash: info.ETag,
|
||||||
LastModified: info.LastModified,
|
Size: info.Size,
|
||||||
Location: info.Location,
|
LastModified: info.LastModified,
|
||||||
VersionID: info.VersionID,
|
Location: info.Location,
|
||||||
|
ContentType: contentType,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Minio) GetObjectInfo(ctx context.Context, bucketName, objectName string) (*domain.AssetInfo, error) {
|
func (m *Minio) GetObject(ctx context.Context, instanceID, resourceOwner, name string) ([]byte, func() (*static.Asset, error), error) {
|
||||||
bucketName = m.prefixBucketName(bucketName)
|
bucketName := m.prefixBucketName(instanceID)
|
||||||
objectinfo, err := m.Client.StatObject(ctx, bucketName, objectName, minio.StatObjectOptions{})
|
objectName := fmt.Sprintf("%s/%s", resourceOwner, name)
|
||||||
|
object, err := m.Client.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, caos_errs.ThrowInternal(err, "MINIO-VGDgv", "Errors.Assets.Object.GetFailed")
|
||||||
|
}
|
||||||
|
info := func() (*static.Asset, error) {
|
||||||
|
info, err := object.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errs.ThrowInternal(err, "MINIO-F96xF", "Errors.Assets.Object.GetFailed")
|
||||||
|
}
|
||||||
|
return m.objectToAssetInfo(instanceID, resourceOwner, info), nil
|
||||||
|
}
|
||||||
|
asset, err := io.ReadAll(object)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, caos_errs.ThrowInternal(err, "MINIO-SFef1", "Errors.Assets.Object.GetFailed")
|
||||||
|
}
|
||||||
|
return asset, info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Minio) GetObjectInfo(ctx context.Context, instanceID, resourceOwner, name string) (*static.Asset, error) {
|
||||||
|
bucketName := m.prefixBucketName(instanceID)
|
||||||
|
objectName := fmt.Sprintf("%s/%s", resourceOwner, name)
|
||||||
|
objectInfo, err := m.Client.StatObject(ctx, bucketName, objectName, minio.StatObjectOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errResp := minio.ToErrorResponse(err); errResp.StatusCode == http.StatusNotFound {
|
if errResp := minio.ToErrorResponse(err); errResp.StatusCode == http.StatusNotFound {
|
||||||
return nil, caos_errs.ThrowNotFound(err, "MINIO-Gdfh4", "Errors.Assets.Object.GetFailed")
|
return nil, caos_errs.ThrowNotFound(err, "MINIO-Gdfh4", "Errors.Assets.Object.GetFailed")
|
||||||
}
|
}
|
||||||
return nil, caos_errs.ThrowInternal(err, "MINIO-1vySX", "Errors.Assets.Object.GetFailed")
|
return nil, caos_errs.ThrowInternal(err, "MINIO-1vySX", "Errors.Assets.Object.GetFailed")
|
||||||
}
|
}
|
||||||
return m.objectToAssetInfo(bucketName, objectinfo), nil
|
return m.objectToAssetInfo(instanceID, resourceOwner, objectInfo), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Minio) GetObject(ctx context.Context, bucketName, objectName string) (io.Reader, func() (*domain.AssetInfo, error), error) {
|
func (m *Minio) RemoveObject(ctx context.Context, instanceID, resourceOwner, name string) error {
|
||||||
bucketName = m.prefixBucketName(bucketName)
|
bucketName := m.prefixBucketName(instanceID)
|
||||||
object, err := m.Client.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{})
|
objectName := fmt.Sprintf("%s/%s", resourceOwner, name)
|
||||||
if err != nil {
|
|
||||||
return nil, nil, caos_errs.ThrowInternal(err, "MINIO-VGDgv", "Errors.Assets.Object.GetFailed")
|
|
||||||
}
|
|
||||||
info := func() (*domain.AssetInfo, error) {
|
|
||||||
info, err := object.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return nil, caos_errs.ThrowInternal(err, "MINIO-F96xF", "Errors.Assets.Object.GetFailed")
|
|
||||||
}
|
|
||||||
return m.objectToAssetInfo(bucketName, info), nil
|
|
||||||
}
|
|
||||||
return object, info, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Minio) GetObjectPresignedURL(ctx context.Context, bucketName, objectName string, expiration time.Duration) (*url.URL, error) {
|
|
||||||
bucketName = m.prefixBucketName(bucketName)
|
|
||||||
reqParams := make(url.Values)
|
|
||||||
presignedURL, err := m.Client.PresignedGetObject(ctx, bucketName, objectName, expiration, reqParams)
|
|
||||||
if err != nil {
|
|
||||||
return nil, caos_errs.ThrowInternal(err, "MINIO-19Mp0", "Errors.Assets.Object.PresignedTokenFailed")
|
|
||||||
}
|
|
||||||
return presignedURL, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Minio) ListObjectInfos(ctx context.Context, bucketName, prefix string, recursive bool) ([]*domain.AssetInfo, error) {
|
|
||||||
bucketName = m.prefixBucketName(bucketName)
|
|
||||||
assetInfos := make([]*domain.AssetInfo, 0)
|
|
||||||
|
|
||||||
objects, cancel := m.listObjects(ctx, bucketName, prefix, recursive)
|
|
||||||
defer cancel()
|
|
||||||
for object := range objects {
|
|
||||||
if object.Err != nil {
|
|
||||||
logging.LogWithFields("MINIO-wC8sd", "bucket-name", bucketName, "prefix", prefix).WithError(object.Err).Debug("unable to get object")
|
|
||||||
return nil, caos_errs.ThrowInternal(object.Err, "MINIO-1m09S", "Errors.Assets.Object.ListFailed")
|
|
||||||
}
|
|
||||||
assetInfos = append(assetInfos, m.objectToAssetInfo(bucketName, object))
|
|
||||||
}
|
|
||||||
return assetInfos, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Minio) RemoveObject(ctx context.Context, bucketName, objectName string) error {
|
|
||||||
bucketName = m.prefixBucketName(bucketName)
|
|
||||||
err := m.Client.RemoveObject(ctx, bucketName, objectName, minio.RemoveObjectOptions{})
|
err := m.Client.RemoveObject(ctx, bucketName, objectName, minio.RemoveObjectOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return caos_errs.ThrowInternal(err, "MINIO-x85RT", "Errors.Assets.Object.RemoveFailed")
|
return caos_errs.ThrowInternal(err, "MINIO-x85RT", "Errors.Assets.Object.RemoveFailed")
|
||||||
@ -153,19 +92,27 @@ func (m *Minio) RemoveObject(ctx context.Context, bucketName, objectName string)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Minio) RemoveObjects(ctx context.Context, bucketName, path string, recursive bool) error {
|
func (m *Minio) RemoveObjects(ctx context.Context, instanceID, resourceOwner string, objectType static.ObjectType) error {
|
||||||
bucketName = m.prefixBucketName(bucketName)
|
bucketName := m.prefixBucketName(instanceID)
|
||||||
objectsCh := make(chan minio.ObjectInfo)
|
objectsCh := make(chan minio.ObjectInfo)
|
||||||
g := new(errgroup.Group)
|
g := new(errgroup.Group)
|
||||||
|
|
||||||
|
var path string
|
||||||
|
switch objectType {
|
||||||
|
case static.ObjectTypeStyling:
|
||||||
|
path = domain.LabelPolicyPrefix + "/"
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
defer close(objectsCh)
|
defer close(objectsCh)
|
||||||
objects, cancel := m.listObjects(ctx, bucketName, path, recursive)
|
objects, cancel := m.listObjects(ctx, bucketName, resourceOwner, true)
|
||||||
for object := range objects {
|
for object := range objects {
|
||||||
if err := object.Err; err != nil {
|
if err := object.Err; err != nil {
|
||||||
cancel()
|
cancel()
|
||||||
if errResp := minio.ToErrorResponse(err); errResp.StatusCode == http.StatusNotFound {
|
if errResp := minio.ToErrorResponse(err); errResp.StatusCode == http.StatusNotFound {
|
||||||
logging.LogWithFields("MINIO-ss8va", "bucketName", bucketName, "path", path).Warn("list objects for remove failed with not found")
|
logging.WithFields("bucketName", bucketName, "path", path).Warn("list objects for remove failed with not found")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return caos_errs.ThrowInternal(object.Err, "MINIO-WQF32", "Errors.Assets.Object.ListFailed")
|
return caos_errs.ThrowInternal(object.Err, "MINIO-WQF32", "Errors.Assets.Object.ListFailed")
|
||||||
@ -189,6 +136,26 @@ func (m *Minio) RemoveObjects(ctx context.Context, bucketName, path string, recu
|
|||||||
return g.Wait()
|
return g.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Minio) createBucket(ctx context.Context, name, location string) error {
|
||||||
|
if location == "" {
|
||||||
|
location = m.Location
|
||||||
|
}
|
||||||
|
name = m.prefixBucketName(name)
|
||||||
|
exists, err := m.Client.BucketExists(ctx, name)
|
||||||
|
if err != nil {
|
||||||
|
logging.WithFields("bucketname", name).WithError(err).Error("cannot check if bucket exists")
|
||||||
|
return caos_errs.ThrowInternal(err, "MINIO-1b8fs", "Errors.Assets.Bucket.Internal")
|
||||||
|
}
|
||||||
|
if exists {
|
||||||
|
return caos_errs.ThrowAlreadyExists(nil, "MINIO-9n3MK", "Errors.Assets.Bucket.AlreadyExists")
|
||||||
|
}
|
||||||
|
err = m.Client.MakeBucket(ctx, name, minio.MakeBucketOptions{Region: location})
|
||||||
|
if err != nil {
|
||||||
|
return caos_errs.ThrowInternal(err, "MINIO-4m90d", "Errors.Assets.Bucket.CreateFailed")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Minio) listObjects(ctx context.Context, bucketName, prefix string, recursive bool) (<-chan minio.ObjectInfo, context.CancelFunc) {
|
func (m *Minio) listObjects(ctx context.Context, bucketName, prefix string, recursive bool) (<-chan minio.ObjectInfo, context.CancelFunc) {
|
||||||
ctxCancel, cancel := context.WithCancel(ctx)
|
ctxCancel, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
@ -198,17 +165,15 @@ func (m *Minio) listObjects(ctx context.Context, bucketName, prefix string, recu
|
|||||||
}), cancel
|
}), cancel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Minio) objectToAssetInfo(bucketName string, object minio.ObjectInfo) *domain.AssetInfo {
|
func (m *Minio) objectToAssetInfo(bucketName string, resourceOwner string, object minio.ObjectInfo) *static.Asset {
|
||||||
return &domain.AssetInfo{
|
return &static.Asset{
|
||||||
Bucket: bucketName,
|
InstanceID: bucketName,
|
||||||
Key: object.Key,
|
ResourceOwner: resourceOwner,
|
||||||
ETag: object.ETag,
|
Name: object.Key,
|
||||||
Size: object.Size,
|
Hash: object.ETag,
|
||||||
LastModified: object.LastModified,
|
Size: object.Size,
|
||||||
VersionID: object.VersionID,
|
LastModified: object.LastModified,
|
||||||
Expiration: object.Expires,
|
ContentType: object.ContentType,
|
||||||
ContentType: object.ContentType,
|
|
||||||
AutheticatedURL: m.Client.EndpointURL().String() + "/" + bucketName + "/" + object.Key,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,25 +2,36 @@ package static
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type CreateStorage func(client *sql.DB, rawConfig map[string]interface{}) (Storage, error)
|
||||||
|
|
||||||
type Storage interface {
|
type Storage interface {
|
||||||
CreateBucket(ctx context.Context, name, location string) error
|
PutObject(ctx context.Context, instanceID, location, resourceOwner, name, contentType string, objectType ObjectType, object io.Reader, objectSize int64) (*Asset, error)
|
||||||
RemoveBucket(ctx context.Context, name string) error
|
GetObject(ctx context.Context, instanceID, resourceOwner, name string) ([]byte, func() (*Asset, error), error)
|
||||||
ListBuckets(ctx context.Context) ([]*domain.BucketInfo, error)
|
GetObjectInfo(ctx context.Context, instanceID, resourceOwner, name string) (*Asset, error)
|
||||||
PutObject(ctx context.Context, bucketName, objectName, contentType string, object io.Reader, objectSize int64, createBucketIfNotExisting bool) (*domain.AssetInfo, error)
|
RemoveObject(ctx context.Context, instanceID, resourceOwner, name string) error
|
||||||
GetObjectInfo(ctx context.Context, bucketName, objectName string) (*domain.AssetInfo, error)
|
RemoveObjects(ctx context.Context, instanceID, resourceOwner string, objectType ObjectType) error
|
||||||
GetObject(ctx context.Context, bucketName, objectName string) (io.Reader, func() (*domain.AssetInfo, error), error)
|
//TODO: add functionality to move asset location
|
||||||
ListObjectInfos(ctx context.Context, bucketName, prefix string, recursive bool) ([]*domain.AssetInfo, error)
|
|
||||||
GetObjectPresignedURL(ctx context.Context, bucketName, objectName string, expiration time.Duration) (*url.URL, error)
|
|
||||||
RemoveObject(ctx context.Context, bucketName, objectName string) error
|
|
||||||
RemoveObjects(ctx context.Context, bucketName, path string, recursive bool) error
|
|
||||||
}
|
}
|
||||||
type Config interface {
|
|
||||||
NewStorage() (Storage, error)
|
type ObjectType int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
ObjectTypeUserAvatar = iota
|
||||||
|
ObjectTypeStyling
|
||||||
|
)
|
||||||
|
|
||||||
|
type Asset struct {
|
||||||
|
InstanceID string
|
||||||
|
ResourceOwner string
|
||||||
|
Name string
|
||||||
|
Hash string
|
||||||
|
Size int64
|
||||||
|
LastModified time.Time
|
||||||
|
Location string
|
||||||
|
ContentType string
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"net/url"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
@ -11,7 +9,6 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||||
"github.com/caos/zitadel/internal/static"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserView struct {
|
type UserView struct {
|
||||||
@ -41,7 +38,6 @@ type HumanView struct {
|
|||||||
DisplayName string
|
DisplayName string
|
||||||
AvatarKey string
|
AvatarKey string
|
||||||
AvatarURL string
|
AvatarURL string
|
||||||
PreSignedAvatar *url.URL
|
|
||||||
PreferredLanguage string
|
PreferredLanguage string
|
||||||
Gender Gender
|
Gender Gender
|
||||||
Email string
|
Email string
|
||||||
@ -257,23 +253,6 @@ func (u *UserView) GetProfile() (*Profile, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserView) FillUserAvatar(ctx context.Context, static static.Storage, expiration time.Duration) error {
|
|
||||||
if u.HumanView == nil {
|
|
||||||
return errors.ThrowPreconditionFailed(nil, "MODEL-2k8da", "Errors.User.NotHuman")
|
|
||||||
}
|
|
||||||
if static != nil {
|
|
||||||
if ctx == nil {
|
|
||||||
ctx = context.Background()
|
|
||||||
}
|
|
||||||
presignesAvatarURL, err := static.GetObjectPresignedURL(ctx, u.ResourceOwner, u.AvatarKey, expiration)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
u.PreSignedAvatar = presignesAvatarURL
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UserView) GetPhone() (*Phone, error) {
|
func (u *UserView) GetPhone() (*Phone, error) {
|
||||||
if u.HumanView == nil {
|
if u.HumanView == nil {
|
||||||
return nil, errors.ThrowPreconditionFailed(nil, "MODEL-him4a", "Errors.User.NotHuman")
|
return nil, errors.ThrowPreconditionFailed(nil, "MODEL-him4a", "Errors.User.NotHuman")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user