From b9d8aa65253d739757d882561fc1056842a41d7a Mon Sep 17 00:00:00 2001 From: optclblast Date: Sat, 23 Nov 2024 03:52:06 -0500 Subject: [PATCH] tmp --- .mockery.yaml | 12 + .vscode/launch.json | 16 + cmd/main.go | 13 +- go.mod | 4 + go.sum | 1 + internal/app/app.go | 133 ++---- internal/app/auth.go | 63 +++ internal/app/login.go | 156 ++++++++ internal/app/middleware.go | 28 ++ internal/app/register.go | 93 +++++ internal/app/upload_file.go | 52 +++ .../cron/cleanup_sessions/cleanup_session.go | 46 +++ internal/cron/cron.go | 7 + internal/domain/files.go | 1 + internal/domain/requests.go | 10 + internal/files_engine/engine.go | 39 ++ internal/logger/logger.go | 8 +- internal/reqcontext/auth.go | 37 ++ internal/storage/audit/storage.go | 19 + internal/storage/filestorage/fs/storage.go | 86 ++++ internal/storage/interface.go | 22 +- internal/storage/models/audit/audit_log.go | 49 +++ internal/storage/models/auth.go | 6 +- internal/storage/postgres/database.go | 63 ++- .../storage/mock_AuthAuditLogStorage.go | 85 ++++ .../internal/storage/mock_AuthStorage.go | 377 ++++++++++++++++++ .../internal/storage/mock_BlobStorage.go | 191 +++++++++ .../internal/storage/mock_Database.go | 377 ++++++++++++++++++ .../internal/storage/mock_FileStorage.go | 32 ++ .../internal/storage/mock_MetaStorage.go | 95 +++++ 30 files changed, 2004 insertions(+), 117 deletions(-) create mode 100644 .mockery.yaml create mode 100644 .vscode/launch.json create mode 100644 internal/app/auth.go create mode 100644 internal/app/login.go create mode 100644 internal/app/middleware.go create mode 100644 internal/app/register.go create mode 100644 internal/app/upload_file.go create mode 100644 internal/cron/cleanup_sessions/cleanup_session.go create mode 100644 internal/cron/cron.go create mode 100644 internal/domain/files.go create mode 100644 internal/files_engine/engine.go create mode 100644 internal/reqcontext/auth.go create mode 100644 internal/storage/audit/storage.go create mode 100644 internal/storage/filestorage/fs/storage.go create mode 100644 internal/storage/models/audit/audit_log.go create mode 100644 mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_AuthAuditLogStorage.go create mode 100644 mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_AuthStorage.go create mode 100644 mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_BlobStorage.go create mode 100644 mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_Database.go create mode 100644 mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_FileStorage.go create mode 100644 mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_MetaStorage.go diff --git a/.mockery.yaml b/.mockery.yaml new file mode 100644 index 0000000..3b40e8f --- /dev/null +++ b/.mockery.yaml @@ -0,0 +1,12 @@ +filename: "mock_{{.InterfaceName}}.go" +dir: "mocks/{{.PackagePath}}" +outpkg: "{{.PackageName}}" +with-expecter: true +packages: + git.optclblast.xyz/draincloud/draincloud-core/internal/storage: + interfaces: + Database: + AuthAuditLogStorage: + AuthStorage: + BlobStorage: + MetaStorage: \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..636cf6b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/main.go" + + } + ] +} \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go index 1b21ba4..25f1f84 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -2,20 +2,29 @@ package main import ( "context" + "os" + "os/signal" "git.optclblast.xyz/draincloud/draincloud-core/internal/app" + cleanupsessions "git.optclblast.xyz/draincloud/draincloud-core/internal/cron/cleanup_sessions" "git.optclblast.xyz/draincloud/draincloud-core/internal/plugin" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/postgres" ) func main() { - ctx := context.Background() + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill) + defer cancel() plugin.MustNewPluginLoader(ctx, 8081, plugin.NewPluginStore()). Run(ctx) pg := postgres.New(ctx, "postgres://draincloud:draincloud@localhost:5432/draincloud?sslmode=disable") - app.New(pg). + cleanupSessionsCron := cleanupsessions.New(pg) + cleanupSessionsCron.Run(ctx) + + go app.New(pg). Run(ctx) + + <-ctx.Done() } diff --git a/go.mod b/go.mod index 69a8cd7..ecfe2a4 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,14 @@ module git.optclblast.xyz/draincloud/draincloud-core go 1.23.0 require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/fatih/color v1.17.0 github.com/fsnotify/fsnotify v1.7.0 github.com/gin-gonic/gin v1.10.0 github.com/jackc/pgx/v5 v5.7.1 github.com/jmoiron/sqlx v1.4.0 github.com/spf13/viper v1.19.0 + github.com/stretchr/testify v1.9.0 golang.org/x/crypto v0.28.0 ) @@ -36,6 +38,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -43,6 +46,7 @@ require ( github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect diff --git a/go.sum b/go.sum index 61aa5a6..121cb37 100644 --- a/go.sum +++ b/go.sum @@ -105,6 +105,7 @@ github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= diff --git a/internal/app/app.go b/internal/app/app.go index 5245350..c664ab6 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -2,31 +2,31 @@ package app import ( "context" - "crypto/rand" - "encoding/base64" - "fmt" + "errors" "net/http" - "time" "git.optclblast.xyz/draincloud/draincloud-core/internal/domain" + filesengine "git.optclblast.xyz/draincloud/draincloud-core/internal/files_engine" "git.optclblast.xyz/draincloud/draincloud-core/internal/logger" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage" "github.com/gin-gonic/gin" - "golang.org/x/crypto/bcrypt" ) type DrainCloud struct { - mux *gin.Engine - datadase storage.Database + mux *gin.Engine + database storage.Database + filesEngine *filesengine.FilesEngine } func New( - datadase storage.Database, + database storage.Database, + filesEngine *filesengine.FilesEngine, ) *DrainCloud { mux := gin.Default() d := &DrainCloud{ - datadase: datadase, + database: database, + filesEngine: filesEngine, } // Built-in auth component of DrainCloud-Core @@ -34,7 +34,17 @@ func New( { authGroup.POST("/register", d.Register) authGroup.POST("/login", d.Login) - authGroup.POST("/logout", d.Logout) + } + + filesGroup := mux.Group("/files") + { + filesGroup.POST("/upload", func(ctx *gin.Context) { + err := d.uploadFile(ctx) + if err != nil { + logger.Error(ctx.Request.Context(), "", logger.Err(err)) + ctx.String(400, err.Error()) + } + }) } d.mux = mux @@ -46,95 +56,22 @@ func (d *DrainCloud) Run(ctx context.Context) error { return d.mux.Run() } -func (d *DrainCloud) Register(ctx *gin.Context) { - logger.Debug(ctx, "[register] new request") - - req := new(domain.RegisterRequest) - err := ctx.BindJSON(req) - if err != nil { - logger.Error(ctx, "[register] failed to bind request", logger.Err(err)) - ctx.JSON(http.StatusBadRequest, map[string]string{ - "error": "bad request", +func writeError(ctx *gin.Context, err error) { + switch { + case errors.Is(err, ErrorAccessDenied): + ctx.JSON(http.StatusInternalServerError, domain.ErrorJson{ + Code: http.StatusForbidden, + Message: err.Error(), }) - return - } - - _, err = d.register(ctx, req) - if err != nil { - logger.Error(ctx, "[register] failed to register user", logger.Err(err)) - ctx.JSON(http.StatusBadRequest, map[string]string{ - "error": err.Error(), + case errors.Is(err, ErrorSessionExpired): + ctx.JSON(http.StatusInternalServerError, domain.ErrorJson{ + Code: http.StatusForbidden, + Message: err.Error(), + }) + default: + ctx.JSON(http.StatusInternalServerError, domain.ErrorJson{ + Code: http.StatusInternalServerError, + Message: "Internal Error", }) - return } - - ctx.JSON(http.StatusOK, map[string]bool{ - "ok": true, - }) -} - -type registerResult struct { - // cookies []http.Cookie -} - -func (d *DrainCloud) register(ctx *gin.Context, req *domain.RegisterRequest) (*registerResult, error) { - if err := validateLoginAndPassword(req.Login, req.Password); err != nil { - return nil, fmt.Errorf("invalid creds: %w", err) - } - - passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), 10) - if err != nil { - logger.Error(ctx, "[register] failed to generate password", logger.Err(err)) - return nil, fmt.Errorf("failed to generate password: %w", err) - } - - _, err = d.datadase.AddUser(ctx, req.Login, req.Login, passwordHash) - if err != nil { - return nil, fmt.Errorf("failed to add new user: %w", err) - } - - sessionToken, err := generateSessionToken(100) - if err != nil { - return nil, fmt.Errorf("failed to generate a session token: %w", err) - } - - ctx.SetCookie("__Session_token", sessionToken, int((time.Hour * 24).Seconds()), "_path", "_domain", true, true) - - csrfToken, err := generateSessionToken(100) - if err != nil { - return nil, fmt.Errorf("failed to generate a csrf token: %w", err) - } - - ctx.SetCookie("__Csrf_token", csrfToken, int((time.Hour * 24).Seconds()), "_path", "_domain", true, false) - - // TODO save session into database - - return ®isterResult{}, nil -} - -func validateLoginAndPassword(login, password string) error { - if len(login) < 4 { - return fmt.Errorf("login must be longer than 8 chars") - } - - if len(password) < 6 { - return fmt.Errorf("password must be longer than 8 chars") - } - - return nil -} - -func generateSessionToken(length int) (string, error) { - bytes := make([]byte, length) - if _, err := rand.Read(bytes); err != nil { - return "", fmt.Errorf("failed to generate token: %w", err) - } - return base64.URLEncoding.EncodeToString(bytes), nil -} - -func (d *DrainCloud) Login(ctx *gin.Context) { - -} -func (d *DrainCloud) Logout(ctx *gin.Context) { - } diff --git a/internal/app/auth.go b/internal/app/auth.go new file mode 100644 index 0000000..371c0e7 --- /dev/null +++ b/internal/app/auth.go @@ -0,0 +1,63 @@ +package app + +import ( + "crypto/rand" + "encoding/base64" + "errors" + "fmt" + "log/slog" + "net/http" + + "git.optclblast.xyz/draincloud/draincloud-core/internal/logger" + "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" + "github.com/gin-gonic/gin" +) + +const ( + csrfTokenCookie = "__Csrf_token" + sessionTokenCookie = "__Session_token" +) + +var ( + ErrorUnauthorized = errors.New("unauthorized") +) + +func (d *DrainCloud) authorize(ctx *gin.Context) (*models.Session, error) { + session, err := d.getSession(ctx) + if err != nil && !errors.Is(err, http.ErrNoCookie) { + return nil, ErrorUnauthorized + } + + if session == nil { + return nil, ErrorUnauthorized + } + + if err := validateSession(ctx, session); err != nil { + // TODO add audit log entry + return nil, ErrorUnauthorized + } + + logger.Debug(ctx, "[authorize] user authorized", slog.Int64("session_id", session.ID)) + + return session, nil +} + +func validateLoginAndPassword(login, password string) error { + if len(login) < 4 { + return fmt.Errorf("login must be longer than 8 chars") + } + + if len(password) < 6 { + return fmt.Errorf("password must be longer than 8 chars") + } + + return nil +} + +func generateSessionToken(length int) (string, error) { + bytes := make([]byte, length) + if _, err := rand.Read(bytes); err != nil { + return "", fmt.Errorf("failed to generate token: %w", err) + } + return base64.URLEncoding.EncodeToString(bytes), nil +} diff --git a/internal/app/login.go b/internal/app/login.go new file mode 100644 index 0000000..59bddf2 --- /dev/null +++ b/internal/app/login.go @@ -0,0 +1,156 @@ +package app + +import ( + "bytes" + "errors" + "fmt" + "log/slog" + "net/http" + "time" + + "git.optclblast.xyz/draincloud/draincloud-core/internal/domain" + "git.optclblast.xyz/draincloud/draincloud-core/internal/logger" + "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" + "github.com/gin-gonic/gin" + "golang.org/x/crypto/bcrypt" +) + +var ( + ErrorAccessDenied = errors.New("access denied") + ErrorSessionExpired = errors.New("session expired") +) + +func (d *DrainCloud) Login(ctx *gin.Context) { + logger.Debug(ctx, "[Login] new request") + + req := new(domain.LoginRequest) + err := ctx.BindJSON(req) + if err != nil { + logger.Error(ctx, "[Login] failed to bind request", logger.Err(err)) + ctx.JSON(http.StatusBadRequest, map[string]string{ + "error": "bad request", + }) + return + } + + resp, err := d.login(ctx, req) + if err != nil { + logger.Error(ctx, "[Login] failed to login user", logger.Err(err)) + ctx.JSON(http.StatusInternalServerError, map[string]string{ + "error": err.Error(), + }) + return + } + + ctx.JSON(http.StatusOK, resp) +} + +func (d *DrainCloud) login(ctx *gin.Context, req *domain.LoginRequest) (*domain.LoginResponse, error) { + session, err := d.getSession(ctx) + if err != nil && !errors.Is(err, http.ErrNoCookie) { + return nil, err + } + + if session != nil { + if err := validateSession(ctx, session); err != nil { + // TODO add audit log entry + return nil, err + } + + logger.Debug(ctx, "[login] user is already logged in", slog.Int64("session_id", session.ID)) + return &domain.LoginResponse{ + Ok: true, + }, nil + } + logger.Debug(ctx, "[login] session not found. trying to authorize") + + passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), 10) + if err != nil { + logger.Error(ctx, "[login] failed to generate password hash", logger.Err(err)) + return nil, fmt.Errorf("failed to generate password hash: %w", err) + } + + user, err := d.database.GetUserByLogin(ctx, req.Login) + if err != nil { + return nil, fmt.Errorf("failed to fetch user by login: %w", err) + } + + if bytes.Equal(passwordHash, user.PasswordHash) { + logger.Warn(ctx, "[login] failed to login user. passwords hashes not equal") + return nil, ErrorAccessDenied + } + + sessionCreatedAt := time.Now() + sessionExpiredAt := sessionCreatedAt.Add(time.Hour * 24 * 7) + + sessionToken, err := generateSessionToken(100) + if err != nil { + return nil, fmt.Errorf("failed to generate a session token: %w", err) + } + ctx.SetCookie(sessionTokenCookie, sessionToken, int(sessionExpiredAt.Sub(sessionCreatedAt).Seconds()), "_path", "_domain", true, true) + + csrfToken, err := generateSessionToken(100) + if err != nil { + return nil, fmt.Errorf("failed to generate a csrf token: %w", err) + } + ctx.SetCookie(csrfTokenCookie, csrfToken, int(sessionExpiredAt.Sub(sessionCreatedAt).Seconds()), "_path", "_domain", true, false) + + if _, err = d.database.AddSession(ctx, &models.Session{ + SessionToken: sessionToken, + CsrfToken: csrfToken, + UserID: user.ID, + CreatedAt: sessionCreatedAt, + ExpiredAt: sessionExpiredAt, + }); err != nil { + return nil, fmt.Errorf("failed to save session: %w", err) + } + + // TODO add audit log entry + + return &domain.LoginResponse{ + Ok: true, + }, nil +} + +func (d *DrainCloud) getSession(ctx *gin.Context) (*models.Session, error) { + token, err := ctx.Cookie(sessionTokenCookie) + if err != nil { + return nil, fmt.Errorf("failed to fetch session cookie from request: %w", err) + } + csrfToken, err := ctx.Cookie(csrfTokenCookie) + if err != nil { + return nil, fmt.Errorf("failed to fetch csrf cookie from request: %w", err) + } + + if len(csrfToken) == 0 || len(token) == 0 { + return nil, fmt.Errorf("session token or csrf token is empty") + } + + session, err := d.database.GetSession(ctx, token) + if err != nil { + return nil, fmt.Errorf("failed to fetch session from repo: %w", err) + } + + return session, nil +} + +func validateSession(ctx *gin.Context, session *models.Session) error { + if session == nil { + return ErrorAccessDenied + } + + csrfToken, err := ctx.Cookie(csrfTokenCookie) + if err != nil { + return fmt.Errorf("failed to fetch csrf cookie from request: %w", err) + } + + if session.CsrfToken != csrfToken { + return ErrorAccessDenied + } + + if session.ExpiredAt.Before(time.Now()) { + return ErrorSessionExpired + } + + return nil +} diff --git a/internal/app/middleware.go b/internal/app/middleware.go new file mode 100644 index 0000000..40bd7f3 --- /dev/null +++ b/internal/app/middleware.go @@ -0,0 +1,28 @@ +package app + +import ( + "git.optclblast.xyz/draincloud/draincloud-core/internal/reqcontext" + "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" + "github.com/gin-gonic/gin" +) + +type authorizer interface { + authorize(ctx *gin.Context) (*models.Session, error) +} + +func WithAuth(handler gin.HandlerFunc, auth authorizer) gin.HandlerFunc { + return func(ctx *gin.Context) { + sess, err := auth.authorize(ctx) + if err != nil { + writeError(ctx, err) + ctx.Abort() + return + } + + authCtx := reqcontext.WithSession(ctx.Request.Context(), sess) + authCtx = reqcontext.WithUserID(authCtx, sess.UserID) + ctx.Request = ctx.Request.WithContext(authCtx) + + handler(ctx) + } +} diff --git a/internal/app/register.go b/internal/app/register.go new file mode 100644 index 0000000..b0303c3 --- /dev/null +++ b/internal/app/register.go @@ -0,0 +1,93 @@ +package app + +import ( + "fmt" + "net/http" + "time" + + "git.optclblast.xyz/draincloud/draincloud-core/internal/domain" + "git.optclblast.xyz/draincloud/draincloud-core/internal/logger" + "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" + "github.com/gin-gonic/gin" + "golang.org/x/crypto/bcrypt" +) + +func (d *DrainCloud) Register(ctx *gin.Context) { + logger.Debug(ctx, "[register] new request") + + // TODO check if registration is enabled + + req := new(domain.RegisterRequest) + err := ctx.BindJSON(req) + if err != nil { + logger.Error(ctx, "[register] failed to bind request", logger.Err(err)) + ctx.JSON(http.StatusBadRequest, map[string]string{ + "error": "bad request", + }) + return + } + + resp, err := d.register(ctx, req) + if err != nil { + logger.Error(ctx, "[register] failed to register user", logger.Err(err)) + ctx.JSON(http.StatusInternalServerError, map[string]string{ + "error": err.Error(), + }) + return + } + + ctx.JSON(http.StatusOK, resp) +} + +func (d *DrainCloud) register(ctx *gin.Context, req *domain.RegisterRequest) (*domain.RegisterResponse, error) { + if err := validateLoginAndPassword(req.Login, req.Password); err != nil { + return nil, fmt.Errorf("invalid creds: %w", err) + } + + passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), 10) + if err != nil { + logger.Error(ctx, "[register] failed to generate password hash", logger.Err(err)) + return nil, fmt.Errorf("failed to generate password hash: %w", err) + } + + user := &models.User{ + Username: req.Login, + Login: req.Login, + PasswordHash: passwordHash, + } + + userID, err := d.database.AddUser(ctx, user.Login, user.Username, user.PasswordHash) + if err != nil { + return nil, fmt.Errorf("failed to add new user: %w", err) + } + user.ID = userID + + sessionCreatedAt := time.Now() + sessionExpiredAt := sessionCreatedAt.Add(time.Hour * 24 * 7) + + sessionToken, err := generateSessionToken(100) + if err != nil { + return nil, fmt.Errorf("failed to generate a session token: %w", err) + } + ctx.SetCookie(sessionTokenCookie, sessionToken, int(sessionExpiredAt.Sub(sessionCreatedAt).Seconds()), "_path", "_domain", true, true) + + csrfToken, err := generateSessionToken(100) + if err != nil { + return nil, fmt.Errorf("failed to generate a csrf token: %w", err) + } + ctx.SetCookie(csrfTokenCookie, csrfToken, int(sessionExpiredAt.Sub(sessionCreatedAt).Seconds()), "_path", "_domain", true, false) + + if _, err = d.database.AddSession(ctx, &models.Session{ + SessionToken: sessionToken, + CsrfToken: csrfToken, + UserID: user.ID, + CreatedAt: sessionCreatedAt, + ExpiredAt: sessionExpiredAt, + }); err != nil { + return nil, fmt.Errorf("failed to save session: %w", err) + } + + return &domain.RegisterResponse{ + Ok: true, + }, nil +} diff --git a/internal/app/upload_file.go b/internal/app/upload_file.go new file mode 100644 index 0000000..0e382dd --- /dev/null +++ b/internal/app/upload_file.go @@ -0,0 +1,52 @@ +package app + +import ( + "io" + "log/slog" + + filesengine "git.optclblast.xyz/draincloud/draincloud-core/internal/files_engine" + "git.optclblast.xyz/draincloud/draincloud-core/internal/logger" + "github.com/davecgh/go-spew/spew" + "github.com/gin-gonic/gin" +) + +const ( + maxFileSize = 10 << 30 +) + +func (d *DrainCloud) UploadFile(ctx *gin.Context) { + if err := ctx.Request.ParseMultipartForm(maxFileSize); err != nil { + logger.Error(ctx, "uploadFile handler error", logger.Err(err)) + writeError(ctx, err) + return + } + + if err := d.uploadFile(ctx); err != nil { + logger.Error(ctx, "uploadFile handle", logger.Err(err)) + writeError(ctx, err) + return + } +} + +func (d *DrainCloud) uploadFile(ctx *gin.Context) error { + title := ctx.PostForm("file") + logger.Info(ctx, "uploadFile", slog.Any("postForm data", spew.Sdump(title))) + + file, header, err := ctx.Request.FormFile("file") + if err != nil { + return err + } + logger.Info(ctx, "uploadFile", slog.Any("header", spew.Sdump(header))) + + data, err := io.ReadAll(file) + if err != nil { + return err + } + + d.filesEngine.SaveFile(ctx, filesengine.File{ + Name: header.Filename, + // UserID: , + }) + + return nil +} diff --git a/internal/cron/cleanup_sessions/cleanup_session.go b/internal/cron/cleanup_sessions/cleanup_session.go new file mode 100644 index 0000000..1866fbe --- /dev/null +++ b/internal/cron/cleanup_sessions/cleanup_session.go @@ -0,0 +1,46 @@ +package cleanupsessions + +import ( + "context" + "time" + + "git.optclblast.xyz/draincloud/draincloud-core/internal/logger" +) + +// TODO set with config +const cronInterval = time.Minute * 10 + +type ExpiredSessionsRemover interface { + RemoveExpiredSessions(ctx context.Context) error +} + +type CleanupSessionCron struct { + db ExpiredSessionsRemover +} + +func New(db ExpiredSessionsRemover) *CleanupSessionCron { + return &CleanupSessionCron{ + db: db, + } +} + +func (c *CleanupSessionCron) Run(ctx context.Context) { + logger.Info(ctx, "[CleanupSessionCron] running cron") + go func() { + t := time.NewTicker(cronInterval) + defer t.Stop() + for { + select { + case <-ctx.Done(): + logger.Warn(ctx, "[CleanupSessionCron] context cancelled") + return + case <-t.C: + logger.Notice(ctx, "[CleanupSessionCron] cleanup started") + t.Reset(cronInterval) + if err := c.db.RemoveExpiredSessions(ctx); err != nil { + logger.Error(ctx, "[CleanupSessionCron] failed to remove expired sessions", logger.Err(err)) + } + } + } + }() +} diff --git a/internal/cron/cron.go b/internal/cron/cron.go new file mode 100644 index 0000000..08fba93 --- /dev/null +++ b/internal/cron/cron.go @@ -0,0 +1,7 @@ +package cron + +import "context" + +type Cron interface { + Run(ctx context.Context) +} diff --git a/internal/domain/files.go b/internal/domain/files.go new file mode 100644 index 0000000..4188b5a --- /dev/null +++ b/internal/domain/files.go @@ -0,0 +1 @@ +package domain diff --git a/internal/domain/requests.go b/internal/domain/requests.go index 97d3241..65113e5 100644 --- a/internal/domain/requests.go +++ b/internal/domain/requests.go @@ -15,5 +15,15 @@ type LoginRequest struct { Password string `json:"password"` } +type LoginResponse struct { + Ok bool `json:"ok"` + Message string `json:"message"` +} + type LogoutRequest struct { } + +type ErrorJson struct { + Code int `json:"code"` + Message string `json:"message"` +} diff --git a/internal/files_engine/engine.go b/internal/files_engine/engine.go new file mode 100644 index 0000000..122798a --- /dev/null +++ b/internal/files_engine/engine.go @@ -0,0 +1,39 @@ +package filesengine + +import ( + "context" + + "git.optclblast.xyz/draincloud/draincloud-core/internal/storage" +) + +type FilesEngine struct { + blobStorage storage.BlobStorage + metaStorage storage.MetaStorage +} + +func NewFilesEngine( + blobStorage storage.BlobStorage, + metaStorage storage.MetaStorage, +) *FilesEngine { + return &FilesEngine{ + blobStorage: blobStorage, + metaStorage: metaStorage, + } +} + +type File struct { + Name string + UserID int64 + Ext string + Type string + Size int64 + Data []byte +} + +func (e *FilesEngine) SaveFile( + ctx context.Context, + file File, +) (int64, error) { + + return -1, nil +} diff --git a/internal/logger/logger.go b/internal/logger/logger.go index e561d0c..3239fbe 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -7,7 +7,11 @@ import ( ) //nolint:gochecknoglobals // ... -var globalLogger *slog.Logger = newLogger(LevelInfo, os.Stdout) +var globalLogger *slog.Logger = newLogger(LevelDebug, os.Stdout) + +func SetLevel(l slog.Level) { + globalLogger = newLogger(l, os.Stdout) +} const ( LevelEmergency = slog.Level(10000) @@ -73,5 +77,5 @@ func Info(ctx context.Context, message string, attrs ...any) { func Debug(ctx context.Context, message string, attrs ...any) { l := loggerFromCtx(ctx) - l.Log(ctx, LevelCritial, message, attrs...) + l.DebugContext(ctx, message, attrs...) } diff --git a/internal/reqcontext/auth.go b/internal/reqcontext/auth.go new file mode 100644 index 0000000..59c6060 --- /dev/null +++ b/internal/reqcontext/auth.go @@ -0,0 +1,37 @@ +package reqcontext + +import ( + "context" + "fmt" + + "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" +) + +type CtxKey string + +const ( + UserIDCtxKey CtxKey = "_ctx_user_id" + SessionCtxKey CtxKey = "_ctx_session" +) + +func WithUserID(parent context.Context, userID int64) context.Context { + return context.WithValue(parent, UserIDCtxKey, userID) +} + +func GetUserID(ctx context.Context) (int64, error) { + if id, ok := ctx.Value(UserIDCtxKey).(int64); ok { + return id, nil + } + return -1, fmt.Errorf("userID not passed with context") +} + +func WithSession(parent context.Context, session *models.Session) context.Context { + return context.WithValue(parent, SessionCtxKey, session) +} + +func GetSession(ctx context.Context) (*models.Session, error) { + if ses, ok := ctx.Value(UserIDCtxKey).(*models.Session); ok { + return ses, nil + } + return nil, fmt.Errorf("session not passed with context") +} \ No newline at end of file diff --git a/internal/storage/audit/storage.go b/internal/storage/audit/storage.go new file mode 100644 index 0000000..25382c4 --- /dev/null +++ b/internal/storage/audit/storage.go @@ -0,0 +1,19 @@ +package audit + +import ( + "context" + + "github.com/jackc/pgx/v5" + + "git.optclblast.xyz/draincloud/draincloud-core/internal/logger" + "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/audit" +) + +type Repository struct { + db *pgx.Conn +} + +func (r *Repository) AddEntry(ctx context.Context, entry audit.AuditLogEntry) error { + logger.Warn(ctx, "[Repository][AddEntry] not implemented yet!") + return nil +} diff --git a/internal/storage/filestorage/fs/storage.go b/internal/storage/filestorage/fs/storage.go new file mode 100644 index 0000000..a22aa03 --- /dev/null +++ b/internal/storage/filestorage/fs/storage.go @@ -0,0 +1,86 @@ +package fs + +import ( + "context" + "fmt" + "os" + "sync" + + "git.optclblast.xyz/draincloud/draincloud-core/internal/logger" +) + +type Storage struct { + lm *sync.Map + dir string +} + +func NewFSStorage(dir string) *Storage { + return &Storage{ + lm: &sync.Map{}, + dir: dir, + } +} + +func (s *Storage) GetFile(ctx context.Context, id int64) (*os.File, error) { + tx := lockFile(s.lm, id) + defer unlockFile(s.lm, id, tx) + + file, err := os.Open(getFilePath(s.dir, id)) + if err != nil { + return nil, fmt.Errorf("failed to open file: %w", err) + } + defer func() { + if err = file.Close(); err != nil { + logger.Error(ctx, "[getFile] close error", logger.Err(err)) + } + }() + + return file, nil +} + +func (s *Storage) SaveBlob(ctx context.Context, id int64, data []byte) error { + tx := lockFile(s.lm, id) + defer unlockFile(s.lm, id, tx) + + file, err := os.Open(getFilePath(s.dir, id)) + if err != nil { + return fmt.Errorf("failed to open file: %w", err) + } + defer func() { + if err = file.Close(); err != nil { + logger.Error(ctx, "[saveFile] close error", logger.Err(err)) + } + }() + + if _, err = file.Write(data); err != nil { + return fmt.Errorf("failed to write data to file: %w", err) + } + + return nil +} + +func (s *Storage) DeleteFile(ctx context.Context, id int64) error { + tx := lockFile(s.lm, id) + defer unlockFile(s.lm, id, tx) + + + + return nil +} + +func getFilePath(dir string, id int64) string { + return fmt.Sprintf("%s/%v", dir, id) +} + +func lockFile(lm *sync.Map, id int64) sync.Locker { + _m := &sync.Mutex{} + many, _ := lm.LoadOrStore(id, _m) + _m, _ = many.(*sync.Mutex) + _m.Lock() + return _m +} + +func unlockFile(lm *sync.Map, id int64, tx sync.Locker) { + tx.Unlock() + lm.Delete(id) +} diff --git a/internal/storage/interface.go b/internal/storage/interface.go index c098194..3392dc0 100644 --- a/internal/storage/interface.go +++ b/internal/storage/interface.go @@ -2,8 +2,10 @@ package storage import ( "context" + "os" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" + auditmodels "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/audit" ) type Database interface { @@ -11,7 +13,25 @@ type Database interface { } type AuthStorage interface { - AddUser(ctx context.Context, login string, username string, passwordHash []byte) (uint64, error) + AddUser(ctx context.Context, login string, username string, passwordHash []byte) (int64, error) GetUserByLogin(ctx context.Context, login string) (*models.User, error) GetUserByID(ctx context.Context, id uint64) (*models.User, error) + + AddSession(ctx context.Context, ses *models.Session) (int64, error) + GetSession(ctx context.Context, sessionToken string) (*models.Session, error) + RemoveSession(ctx context.Context, id int64) error +} + +type AuthAuditLogStorage interface { + AddEntry(ctx context.Context, entry auditmodels.AuditLogEntry) error +} + +type MetaStorage interface { + SaveMetadata(ctx context.Context, fileType string, size int64, ext string) (int64, error) +} + +type BlobStorage interface { + GetFile(ctx context.Context, id int64) (*os.File, error) + SaveBlob(ctx context.Context, id int64, data []byte) error + DeleteFile(ctx context.Context, id int64) error } diff --git a/internal/storage/models/audit/audit_log.go b/internal/storage/models/audit/audit_log.go new file mode 100644 index 0000000..8aaeeba --- /dev/null +++ b/internal/storage/models/audit/audit_log.go @@ -0,0 +1,49 @@ +package audit + +import "time" + +type EventType int + +const ( + EventUnspecified EventType = iota + EventSuccessfullLogin + EventFailedLogin + EventSuccessfullRegister + EventFailedRegister + EventSuccessfullAuth + EventFailedAuth + EventUserUpdated +) + +type Severity int + +const ( + SeverityAlert = 0 + SeverityWarning = 10 + SeverityInfo = 100 + SeverityNotice = 200 +) + +type Actor struct { + ActorSysName string + RemoteIP string + ID int64 +} + +const ( + ActorDrainCloudCore = "_actor_draincloud_core" + ActorUser = "user" +) + +type AuditLogEntry struct { + EventType EventType + // Who caused changes + Actor Actor + Severity Severity + SessionID int64 + CreatedAt time.Time + // What changed + Object string + // How it was changed + Action string +} diff --git a/internal/storage/models/auth.go b/internal/storage/models/auth.go index 5d0ae4f..503e291 100644 --- a/internal/storage/models/auth.go +++ b/internal/storage/models/auth.go @@ -3,16 +3,16 @@ package models import "time" type Session struct { - ID string + ID int64 SessionToken string CsrfToken string - User *User + UserID int64 CreatedAt time.Time ExpiredAt time.Time } type User struct { - ID uint64 + ID int64 Username string Login string PasswordHash []byte diff --git a/internal/storage/postgres/database.go b/internal/storage/postgres/database.go index 10f5698..b9feb00 100644 --- a/internal/storage/postgres/database.go +++ b/internal/storage/postgres/database.go @@ -2,7 +2,9 @@ package postgres import ( "context" + "database/sql" "fmt" + "log/slog" "time" "git.optclblast.xyz/draincloud/draincloud-core/internal/closer" @@ -37,7 +39,7 @@ type dbtx interface { Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error) } -func (d *Database) AddUser(ctx context.Context, login string, username string, passwordHash []byte) (uint64, error) { +func (d *Database) AddUser(ctx context.Context, login string, username string, passwordHash []byte) (int64, error) { return addUser(ctx, d.db, login, username, passwordHash) } @@ -49,18 +51,59 @@ func (d *Database) GetUserByLogin(ctx context.Context, login string) (*models.Us return getUserByLogin(ctx, d.db, login) } -func (d *Database) AddSession(ctx context.Context, ses *models.Session) (uint64, error) { +func (d *Database) AddSession(ctx context.Context, ses *models.Session) (int64, error) { return addSession(ctx, d.db, ses) } -func addUser(ctx context.Context, conn dbtx, login string, username string, passwordHash []byte) (uint64, error) { +func (d *Database) GetSession(ctx context.Context, sessionToken string) (*models.Session, error) { + const stmt = `SELECT + s.id, s.session_token, s.csrf_token, s.user_id, s.created_at, s.expired_at + FROM sessions as s + WHERE s.session_token = $1;` + + row := d.db.QueryRow(ctx, stmt, sessionToken) + + var ( + id int64 + sesToken, csrfToken string + userID int64 + createdAt sql.NullTime + expiredAt sql.NullTime + ) + + if err := row.Scan(&id, &sesToken, &csrfToken, &userID, &createdAt, &expiredAt); err != nil { + return nil, err + } + + return &models.Session{ + ID: id, + SessionToken: sesToken, + CsrfToken: csrfToken, + UserID: userID, + CreatedAt: createdAt.Time, + ExpiredAt: expiredAt.Time, + }, nil +} + +func (d *Database) RemoveSession(ctx context.Context, id int64) error { + const stmt = `DELETE FROM sessions WHERE id = $1;` + _, err := d.db.Exec(ctx, stmt, id) + return err +} + +func (d *Database) RemoveExpiredSessions(ctx context.Context) error { + const stmt = `DELETE FROM sessions WHERE expired_at < $1;` + res, err := d.db.Exec(ctx, stmt, time.Now()) + logger.Notice(ctx, "[Database][RemoveExpiredSessions] sessions cleanup", slog.Int64("removed", res.RowsAffected())) + return err +} + +func addUser(ctx context.Context, conn dbtx, login string, username string, passwordHash []byte) (int64, error) { const stmt = `INSERT INTO users (login,username,password) VALUES ($1,$2,$3) RETURNING id` row := conn.QueryRow(ctx, stmt, login, username, passwordHash) - - var id uint64 - + var id int64 if err := row.Scan(&id); err != nil { return 0, fmt.Errorf("failed to insert user data into users table: %w", err) } @@ -71,7 +114,6 @@ func addUser(ctx context.Context, conn dbtx, login string, username string, pass func getUserByID(ctx context.Context, conn dbtx, id uint64) (*models.User, error) { const stmt = `SELECT * FROM users WHERE id = $1 LIMIT 1` u := new(models.User) - row := conn.QueryRow(ctx, stmt, id) if err := row.Scan(&u.ID, &u.Login, &u.Username, &u.PasswordHash, &u.CreatedAt, &u.UpdatedAt); err != nil { return nil, fmt.Errorf("failed to fetch user by id: %w", err) @@ -83,7 +125,6 @@ func getUserByID(ctx context.Context, conn dbtx, id uint64) (*models.User, error func getUserByLogin(ctx context.Context, conn dbtx, login string) (*models.User, error) { const stmt = `SELECT * FROM users WHERE login = $1 LIMIT 1` u := new(models.User) - row := conn.QueryRow(ctx, stmt, login) if err := row.Scan(&u.ID, &u.Login, &u.Username, &u.PasswordHash, &u.CreatedAt, &u.UpdatedAt); err != nil { return nil, fmt.Errorf("failed to fetch user by login: %w", err) @@ -92,11 +133,11 @@ func getUserByLogin(ctx context.Context, conn dbtx, login string) (*models.User, return u, nil } -func addSession(ctx context.Context, conn dbtx, session *models.Session) (uint64, error) { +func addSession(ctx context.Context, conn dbtx, session *models.Session) (int64, error) { const stmt = `INSERT INTO sessions (session_token, csrf_token, user_id, created_at, expired_at) VALUES ($1, $2, $3, $4, $5) RETURNING id;` - var id uint64 - row := conn.QueryRow(ctx, stmt, session.SessionToken, session.CsrfToken, session.User.ID, session.CreatedAt, session.ExpiredAt) + var id int64 + row := conn.QueryRow(ctx, stmt, session.SessionToken, session.CsrfToken, session.UserID, session.CreatedAt, session.ExpiredAt) if err := row.Scan(&id); err != nil { return 0, fmt.Errorf("failed to insert new session: %w", err) } diff --git a/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_AuthAuditLogStorage.go b/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_AuthAuditLogStorage.go new file mode 100644 index 0000000..840d37a --- /dev/null +++ b/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_AuthAuditLogStorage.go @@ -0,0 +1,85 @@ +// Code generated by mockery v2.48.0. DO NOT EDIT. + +package storage + +import ( + context "context" + + audit "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/audit" + + mock "github.com/stretchr/testify/mock" +) + +// MockAuthAuditLogStorage is an autogenerated mock type for the AuthAuditLogStorage type +type MockAuthAuditLogStorage struct { + mock.Mock +} + +type MockAuthAuditLogStorage_Expecter struct { + mock *mock.Mock +} + +func (_m *MockAuthAuditLogStorage) EXPECT() *MockAuthAuditLogStorage_Expecter { + return &MockAuthAuditLogStorage_Expecter{mock: &_m.Mock} +} + +// AddEntry provides a mock function with given fields: ctx, entry +func (_m *MockAuthAuditLogStorage) AddEntry(ctx context.Context, entry audit.AuditLogEntry) error { + ret := _m.Called(ctx, entry) + + if len(ret) == 0 { + panic("no return value specified for AddEntry") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, audit.AuditLogEntry) error); ok { + r0 = rf(ctx, entry) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockAuthAuditLogStorage_AddEntry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddEntry' +type MockAuthAuditLogStorage_AddEntry_Call struct { + *mock.Call +} + +// AddEntry is a helper method to define mock.On call +// - ctx context.Context +// - entry audit.AuditLogEntry +func (_e *MockAuthAuditLogStorage_Expecter) AddEntry(ctx interface{}, entry interface{}) *MockAuthAuditLogStorage_AddEntry_Call { + return &MockAuthAuditLogStorage_AddEntry_Call{Call: _e.mock.On("AddEntry", ctx, entry)} +} + +func (_c *MockAuthAuditLogStorage_AddEntry_Call) Run(run func(ctx context.Context, entry audit.AuditLogEntry)) *MockAuthAuditLogStorage_AddEntry_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(audit.AuditLogEntry)) + }) + return _c +} + +func (_c *MockAuthAuditLogStorage_AddEntry_Call) Return(_a0 error) *MockAuthAuditLogStorage_AddEntry_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockAuthAuditLogStorage_AddEntry_Call) RunAndReturn(run func(context.Context, audit.AuditLogEntry) error) *MockAuthAuditLogStorage_AddEntry_Call { + _c.Call.Return(run) + return _c +} + +// NewMockAuthAuditLogStorage creates a new instance of MockAuthAuditLogStorage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockAuthAuditLogStorage(t interface { + mock.TestingT + Cleanup(func()) +}) *MockAuthAuditLogStorage { + mock := &MockAuthAuditLogStorage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_AuthStorage.go b/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_AuthStorage.go new file mode 100644 index 0000000..c8bb2ad --- /dev/null +++ b/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_AuthStorage.go @@ -0,0 +1,377 @@ +// Code generated by mockery v2.48.0. DO NOT EDIT. + +package storage + +import ( + context "context" + + models "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" + mock "github.com/stretchr/testify/mock" +) + +// MockAuthStorage is an autogenerated mock type for the AuthStorage type +type MockAuthStorage struct { + mock.Mock +} + +type MockAuthStorage_Expecter struct { + mock *mock.Mock +} + +func (_m *MockAuthStorage) EXPECT() *MockAuthStorage_Expecter { + return &MockAuthStorage_Expecter{mock: &_m.Mock} +} + +// AddSession provides a mock function with given fields: ctx, ses +func (_m *MockAuthStorage) AddSession(ctx context.Context, ses *models.Session) (int64, error) { + ret := _m.Called(ctx, ses) + + if len(ret) == 0 { + panic("no return value specified for AddSession") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *models.Session) (int64, error)); ok { + return rf(ctx, ses) + } + if rf, ok := ret.Get(0).(func(context.Context, *models.Session) int64); ok { + r0 = rf(ctx, ses) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, *models.Session) error); ok { + r1 = rf(ctx, ses) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockAuthStorage_AddSession_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddSession' +type MockAuthStorage_AddSession_Call struct { + *mock.Call +} + +// AddSession is a helper method to define mock.On call +// - ctx context.Context +// - ses *models.Session +func (_e *MockAuthStorage_Expecter) AddSession(ctx interface{}, ses interface{}) *MockAuthStorage_AddSession_Call { + return &MockAuthStorage_AddSession_Call{Call: _e.mock.On("AddSession", ctx, ses)} +} + +func (_c *MockAuthStorage_AddSession_Call) Run(run func(ctx context.Context, ses *models.Session)) *MockAuthStorage_AddSession_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*models.Session)) + }) + return _c +} + +func (_c *MockAuthStorage_AddSession_Call) Return(_a0 int64, _a1 error) *MockAuthStorage_AddSession_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockAuthStorage_AddSession_Call) RunAndReturn(run func(context.Context, *models.Session) (int64, error)) *MockAuthStorage_AddSession_Call { + _c.Call.Return(run) + return _c +} + +// AddUser provides a mock function with given fields: ctx, login, username, passwordHash +func (_m *MockAuthStorage) AddUser(ctx context.Context, login string, username string, passwordHash []byte) (int64, error) { + ret := _m.Called(ctx, login, username, passwordHash) + + if len(ret) == 0 { + panic("no return value specified for AddUser") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, []byte) (int64, error)); ok { + return rf(ctx, login, username, passwordHash) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, []byte) int64); ok { + r0 = rf(ctx, login, username, passwordHash) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, []byte) error); ok { + r1 = rf(ctx, login, username, passwordHash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockAuthStorage_AddUser_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddUser' +type MockAuthStorage_AddUser_Call struct { + *mock.Call +} + +// AddUser is a helper method to define mock.On call +// - ctx context.Context +// - login string +// - username string +// - passwordHash []byte +func (_e *MockAuthStorage_Expecter) AddUser(ctx interface{}, login interface{}, username interface{}, passwordHash interface{}) *MockAuthStorage_AddUser_Call { + return &MockAuthStorage_AddUser_Call{Call: _e.mock.On("AddUser", ctx, login, username, passwordHash)} +} + +func (_c *MockAuthStorage_AddUser_Call) Run(run func(ctx context.Context, login string, username string, passwordHash []byte)) *MockAuthStorage_AddUser_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].([]byte)) + }) + return _c +} + +func (_c *MockAuthStorage_AddUser_Call) Return(_a0 int64, _a1 error) *MockAuthStorage_AddUser_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockAuthStorage_AddUser_Call) RunAndReturn(run func(context.Context, string, string, []byte) (int64, error)) *MockAuthStorage_AddUser_Call { + _c.Call.Return(run) + return _c +} + +// GetSession provides a mock function with given fields: ctx, sessionToken +func (_m *MockAuthStorage) GetSession(ctx context.Context, sessionToken string) (*models.Session, error) { + ret := _m.Called(ctx, sessionToken) + + if len(ret) == 0 { + panic("no return value specified for GetSession") + } + + var r0 *models.Session + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*models.Session, error)); ok { + return rf(ctx, sessionToken) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *models.Session); ok { + r0 = rf(ctx, sessionToken) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.Session) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, sessionToken) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockAuthStorage_GetSession_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSession' +type MockAuthStorage_GetSession_Call struct { + *mock.Call +} + +// GetSession is a helper method to define mock.On call +// - ctx context.Context +// - sessionToken string +func (_e *MockAuthStorage_Expecter) GetSession(ctx interface{}, sessionToken interface{}) *MockAuthStorage_GetSession_Call { + return &MockAuthStorage_GetSession_Call{Call: _e.mock.On("GetSession", ctx, sessionToken)} +} + +func (_c *MockAuthStorage_GetSession_Call) Run(run func(ctx context.Context, sessionToken string)) *MockAuthStorage_GetSession_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockAuthStorage_GetSession_Call) Return(_a0 *models.Session, _a1 error) *MockAuthStorage_GetSession_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockAuthStorage_GetSession_Call) RunAndReturn(run func(context.Context, string) (*models.Session, error)) *MockAuthStorage_GetSession_Call { + _c.Call.Return(run) + return _c +} + +// GetUserByID provides a mock function with given fields: ctx, id +func (_m *MockAuthStorage) GetUserByID(ctx context.Context, id uint64) (*models.User, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for GetUserByID") + } + + var r0 *models.User + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64) (*models.User, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64) *models.User); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.User) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockAuthStorage_GetUserByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetUserByID' +type MockAuthStorage_GetUserByID_Call struct { + *mock.Call +} + +// GetUserByID is a helper method to define mock.On call +// - ctx context.Context +// - id uint64 +func (_e *MockAuthStorage_Expecter) GetUserByID(ctx interface{}, id interface{}) *MockAuthStorage_GetUserByID_Call { + return &MockAuthStorage_GetUserByID_Call{Call: _e.mock.On("GetUserByID", ctx, id)} +} + +func (_c *MockAuthStorage_GetUserByID_Call) Run(run func(ctx context.Context, id uint64)) *MockAuthStorage_GetUserByID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64)) + }) + return _c +} + +func (_c *MockAuthStorage_GetUserByID_Call) Return(_a0 *models.User, _a1 error) *MockAuthStorage_GetUserByID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockAuthStorage_GetUserByID_Call) RunAndReturn(run func(context.Context, uint64) (*models.User, error)) *MockAuthStorage_GetUserByID_Call { + _c.Call.Return(run) + return _c +} + +// GetUserByLogin provides a mock function with given fields: ctx, login +func (_m *MockAuthStorage) GetUserByLogin(ctx context.Context, login string) (*models.User, error) { + ret := _m.Called(ctx, login) + + if len(ret) == 0 { + panic("no return value specified for GetUserByLogin") + } + + var r0 *models.User + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*models.User, error)); ok { + return rf(ctx, login) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *models.User); ok { + r0 = rf(ctx, login) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.User) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, login) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockAuthStorage_GetUserByLogin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetUserByLogin' +type MockAuthStorage_GetUserByLogin_Call struct { + *mock.Call +} + +// GetUserByLogin is a helper method to define mock.On call +// - ctx context.Context +// - login string +func (_e *MockAuthStorage_Expecter) GetUserByLogin(ctx interface{}, login interface{}) *MockAuthStorage_GetUserByLogin_Call { + return &MockAuthStorage_GetUserByLogin_Call{Call: _e.mock.On("GetUserByLogin", ctx, login)} +} + +func (_c *MockAuthStorage_GetUserByLogin_Call) Run(run func(ctx context.Context, login string)) *MockAuthStorage_GetUserByLogin_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockAuthStorage_GetUserByLogin_Call) Return(_a0 *models.User, _a1 error) *MockAuthStorage_GetUserByLogin_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockAuthStorage_GetUserByLogin_Call) RunAndReturn(run func(context.Context, string) (*models.User, error)) *MockAuthStorage_GetUserByLogin_Call { + _c.Call.Return(run) + return _c +} + +// RemoveSession provides a mock function with given fields: ctx, id +func (_m *MockAuthStorage) RemoveSession(ctx context.Context, id int64) error { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for RemoveSession") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockAuthStorage_RemoveSession_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveSession' +type MockAuthStorage_RemoveSession_Call struct { + *mock.Call +} + +// RemoveSession is a helper method to define mock.On call +// - ctx context.Context +// - id int64 +func (_e *MockAuthStorage_Expecter) RemoveSession(ctx interface{}, id interface{}) *MockAuthStorage_RemoveSession_Call { + return &MockAuthStorage_RemoveSession_Call{Call: _e.mock.On("RemoveSession", ctx, id)} +} + +func (_c *MockAuthStorage_RemoveSession_Call) Run(run func(ctx context.Context, id int64)) *MockAuthStorage_RemoveSession_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64)) + }) + return _c +} + +func (_c *MockAuthStorage_RemoveSession_Call) Return(_a0 error) *MockAuthStorage_RemoveSession_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockAuthStorage_RemoveSession_Call) RunAndReturn(run func(context.Context, int64) error) *MockAuthStorage_RemoveSession_Call { + _c.Call.Return(run) + return _c +} + +// NewMockAuthStorage creates a new instance of MockAuthStorage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockAuthStorage(t interface { + mock.TestingT + Cleanup(func()) +}) *MockAuthStorage { + mock := &MockAuthStorage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_BlobStorage.go b/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_BlobStorage.go new file mode 100644 index 0000000..2bc2787 --- /dev/null +++ b/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_BlobStorage.go @@ -0,0 +1,191 @@ +// Code generated by mockery v2.48.0. DO NOT EDIT. + +package storage + +import ( + context "context" + os "os" + + mock "github.com/stretchr/testify/mock" +) + +// MockBlobStorage is an autogenerated mock type for the BlobStorage type +type MockBlobStorage struct { + mock.Mock +} + +type MockBlobStorage_Expecter struct { + mock *mock.Mock +} + +func (_m *MockBlobStorage) EXPECT() *MockBlobStorage_Expecter { + return &MockBlobStorage_Expecter{mock: &_m.Mock} +} + +// DeleteFile provides a mock function with given fields: ctx, id +func (_m *MockBlobStorage) DeleteFile(ctx context.Context, id int64) error { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for DeleteFile") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBlobStorage_DeleteFile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteFile' +type MockBlobStorage_DeleteFile_Call struct { + *mock.Call +} + +// DeleteFile is a helper method to define mock.On call +// - ctx context.Context +// - id int64 +func (_e *MockBlobStorage_Expecter) DeleteFile(ctx interface{}, id interface{}) *MockBlobStorage_DeleteFile_Call { + return &MockBlobStorage_DeleteFile_Call{Call: _e.mock.On("DeleteFile", ctx, id)} +} + +func (_c *MockBlobStorage_DeleteFile_Call) Run(run func(ctx context.Context, id int64)) *MockBlobStorage_DeleteFile_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64)) + }) + return _c +} + +func (_c *MockBlobStorage_DeleteFile_Call) Return(_a0 error) *MockBlobStorage_DeleteFile_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBlobStorage_DeleteFile_Call) RunAndReturn(run func(context.Context, int64) error) *MockBlobStorage_DeleteFile_Call { + _c.Call.Return(run) + return _c +} + +// GetFile provides a mock function with given fields: ctx, id +func (_m *MockBlobStorage) GetFile(ctx context.Context, id int64) (*os.File, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for GetFile") + } + + var r0 *os.File + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (*os.File, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) *os.File); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*os.File) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockBlobStorage_GetFile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFile' +type MockBlobStorage_GetFile_Call struct { + *mock.Call +} + +// GetFile is a helper method to define mock.On call +// - ctx context.Context +// - id int64 +func (_e *MockBlobStorage_Expecter) GetFile(ctx interface{}, id interface{}) *MockBlobStorage_GetFile_Call { + return &MockBlobStorage_GetFile_Call{Call: _e.mock.On("GetFile", ctx, id)} +} + +func (_c *MockBlobStorage_GetFile_Call) Run(run func(ctx context.Context, id int64)) *MockBlobStorage_GetFile_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64)) + }) + return _c +} + +func (_c *MockBlobStorage_GetFile_Call) Return(_a0 *os.File, _a1 error) *MockBlobStorage_GetFile_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockBlobStorage_GetFile_Call) RunAndReturn(run func(context.Context, int64) (*os.File, error)) *MockBlobStorage_GetFile_Call { + _c.Call.Return(run) + return _c +} + +// SaveBlob provides a mock function with given fields: ctx, id, data +func (_m *MockBlobStorage) SaveBlob(ctx context.Context, id int64, data []byte) error { + ret := _m.Called(ctx, id, data) + + if len(ret) == 0 { + panic("no return value specified for SaveBlob") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64, []byte) error); ok { + r0 = rf(ctx, id, data) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBlobStorage_SaveBlob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveBlob' +type MockBlobStorage_SaveBlob_Call struct { + *mock.Call +} + +// SaveBlob is a helper method to define mock.On call +// - ctx context.Context +// - id int64 +// - data []byte +func (_e *MockBlobStorage_Expecter) SaveBlob(ctx interface{}, id interface{}, data interface{}) *MockBlobStorage_SaveBlob_Call { + return &MockBlobStorage_SaveBlob_Call{Call: _e.mock.On("SaveBlob", ctx, id, data)} +} + +func (_c *MockBlobStorage_SaveBlob_Call) Run(run func(ctx context.Context, id int64, data []byte)) *MockBlobStorage_SaveBlob_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64), args[2].([]byte)) + }) + return _c +} + +func (_c *MockBlobStorage_SaveBlob_Call) Return(_a0 error) *MockBlobStorage_SaveBlob_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBlobStorage_SaveBlob_Call) RunAndReturn(run func(context.Context, int64, []byte) error) *MockBlobStorage_SaveBlob_Call { + _c.Call.Return(run) + return _c +} + +// NewMockBlobStorage creates a new instance of MockBlobStorage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockBlobStorage(t interface { + mock.TestingT + Cleanup(func()) +}) *MockBlobStorage { + mock := &MockBlobStorage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_Database.go b/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_Database.go new file mode 100644 index 0000000..90c7c42 --- /dev/null +++ b/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_Database.go @@ -0,0 +1,377 @@ +// Code generated by mockery v2.48.0. DO NOT EDIT. + +package storage + +import ( + context "context" + + models "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" + mock "github.com/stretchr/testify/mock" +) + +// MockDatabase is an autogenerated mock type for the Database type +type MockDatabase struct { + mock.Mock +} + +type MockDatabase_Expecter struct { + mock *mock.Mock +} + +func (_m *MockDatabase) EXPECT() *MockDatabase_Expecter { + return &MockDatabase_Expecter{mock: &_m.Mock} +} + +// AddSession provides a mock function with given fields: ctx, ses +func (_m *MockDatabase) AddSession(ctx context.Context, ses *models.Session) (int64, error) { + ret := _m.Called(ctx, ses) + + if len(ret) == 0 { + panic("no return value specified for AddSession") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *models.Session) (int64, error)); ok { + return rf(ctx, ses) + } + if rf, ok := ret.Get(0).(func(context.Context, *models.Session) int64); ok { + r0 = rf(ctx, ses) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, *models.Session) error); ok { + r1 = rf(ctx, ses) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockDatabase_AddSession_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddSession' +type MockDatabase_AddSession_Call struct { + *mock.Call +} + +// AddSession is a helper method to define mock.On call +// - ctx context.Context +// - ses *models.Session +func (_e *MockDatabase_Expecter) AddSession(ctx interface{}, ses interface{}) *MockDatabase_AddSession_Call { + return &MockDatabase_AddSession_Call{Call: _e.mock.On("AddSession", ctx, ses)} +} + +func (_c *MockDatabase_AddSession_Call) Run(run func(ctx context.Context, ses *models.Session)) *MockDatabase_AddSession_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*models.Session)) + }) + return _c +} + +func (_c *MockDatabase_AddSession_Call) Return(_a0 int64, _a1 error) *MockDatabase_AddSession_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockDatabase_AddSession_Call) RunAndReturn(run func(context.Context, *models.Session) (int64, error)) *MockDatabase_AddSession_Call { + _c.Call.Return(run) + return _c +} + +// AddUser provides a mock function with given fields: ctx, login, username, passwordHash +func (_m *MockDatabase) AddUser(ctx context.Context, login string, username string, passwordHash []byte) (int64, error) { + ret := _m.Called(ctx, login, username, passwordHash) + + if len(ret) == 0 { + panic("no return value specified for AddUser") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, []byte) (int64, error)); ok { + return rf(ctx, login, username, passwordHash) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, []byte) int64); ok { + r0 = rf(ctx, login, username, passwordHash) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, []byte) error); ok { + r1 = rf(ctx, login, username, passwordHash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockDatabase_AddUser_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddUser' +type MockDatabase_AddUser_Call struct { + *mock.Call +} + +// AddUser is a helper method to define mock.On call +// - ctx context.Context +// - login string +// - username string +// - passwordHash []byte +func (_e *MockDatabase_Expecter) AddUser(ctx interface{}, login interface{}, username interface{}, passwordHash interface{}) *MockDatabase_AddUser_Call { + return &MockDatabase_AddUser_Call{Call: _e.mock.On("AddUser", ctx, login, username, passwordHash)} +} + +func (_c *MockDatabase_AddUser_Call) Run(run func(ctx context.Context, login string, username string, passwordHash []byte)) *MockDatabase_AddUser_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].([]byte)) + }) + return _c +} + +func (_c *MockDatabase_AddUser_Call) Return(_a0 int64, _a1 error) *MockDatabase_AddUser_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockDatabase_AddUser_Call) RunAndReturn(run func(context.Context, string, string, []byte) (int64, error)) *MockDatabase_AddUser_Call { + _c.Call.Return(run) + return _c +} + +// GetSession provides a mock function with given fields: ctx, sessionToken +func (_m *MockDatabase) GetSession(ctx context.Context, sessionToken string) (*models.Session, error) { + ret := _m.Called(ctx, sessionToken) + + if len(ret) == 0 { + panic("no return value specified for GetSession") + } + + var r0 *models.Session + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*models.Session, error)); ok { + return rf(ctx, sessionToken) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *models.Session); ok { + r0 = rf(ctx, sessionToken) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.Session) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, sessionToken) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockDatabase_GetSession_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSession' +type MockDatabase_GetSession_Call struct { + *mock.Call +} + +// GetSession is a helper method to define mock.On call +// - ctx context.Context +// - sessionToken string +func (_e *MockDatabase_Expecter) GetSession(ctx interface{}, sessionToken interface{}) *MockDatabase_GetSession_Call { + return &MockDatabase_GetSession_Call{Call: _e.mock.On("GetSession", ctx, sessionToken)} +} + +func (_c *MockDatabase_GetSession_Call) Run(run func(ctx context.Context, sessionToken string)) *MockDatabase_GetSession_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockDatabase_GetSession_Call) Return(_a0 *models.Session, _a1 error) *MockDatabase_GetSession_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockDatabase_GetSession_Call) RunAndReturn(run func(context.Context, string) (*models.Session, error)) *MockDatabase_GetSession_Call { + _c.Call.Return(run) + return _c +} + +// GetUserByID provides a mock function with given fields: ctx, id +func (_m *MockDatabase) GetUserByID(ctx context.Context, id uint64) (*models.User, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for GetUserByID") + } + + var r0 *models.User + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64) (*models.User, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64) *models.User); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.User) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockDatabase_GetUserByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetUserByID' +type MockDatabase_GetUserByID_Call struct { + *mock.Call +} + +// GetUserByID is a helper method to define mock.On call +// - ctx context.Context +// - id uint64 +func (_e *MockDatabase_Expecter) GetUserByID(ctx interface{}, id interface{}) *MockDatabase_GetUserByID_Call { + return &MockDatabase_GetUserByID_Call{Call: _e.mock.On("GetUserByID", ctx, id)} +} + +func (_c *MockDatabase_GetUserByID_Call) Run(run func(ctx context.Context, id uint64)) *MockDatabase_GetUserByID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64)) + }) + return _c +} + +func (_c *MockDatabase_GetUserByID_Call) Return(_a0 *models.User, _a1 error) *MockDatabase_GetUserByID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockDatabase_GetUserByID_Call) RunAndReturn(run func(context.Context, uint64) (*models.User, error)) *MockDatabase_GetUserByID_Call { + _c.Call.Return(run) + return _c +} + +// GetUserByLogin provides a mock function with given fields: ctx, login +func (_m *MockDatabase) GetUserByLogin(ctx context.Context, login string) (*models.User, error) { + ret := _m.Called(ctx, login) + + if len(ret) == 0 { + panic("no return value specified for GetUserByLogin") + } + + var r0 *models.User + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*models.User, error)); ok { + return rf(ctx, login) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *models.User); ok { + r0 = rf(ctx, login) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.User) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, login) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockDatabase_GetUserByLogin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetUserByLogin' +type MockDatabase_GetUserByLogin_Call struct { + *mock.Call +} + +// GetUserByLogin is a helper method to define mock.On call +// - ctx context.Context +// - login string +func (_e *MockDatabase_Expecter) GetUserByLogin(ctx interface{}, login interface{}) *MockDatabase_GetUserByLogin_Call { + return &MockDatabase_GetUserByLogin_Call{Call: _e.mock.On("GetUserByLogin", ctx, login)} +} + +func (_c *MockDatabase_GetUserByLogin_Call) Run(run func(ctx context.Context, login string)) *MockDatabase_GetUserByLogin_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockDatabase_GetUserByLogin_Call) Return(_a0 *models.User, _a1 error) *MockDatabase_GetUserByLogin_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockDatabase_GetUserByLogin_Call) RunAndReturn(run func(context.Context, string) (*models.User, error)) *MockDatabase_GetUserByLogin_Call { + _c.Call.Return(run) + return _c +} + +// RemoveSession provides a mock function with given fields: ctx, id +func (_m *MockDatabase) RemoveSession(ctx context.Context, id int64) error { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for RemoveSession") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockDatabase_RemoveSession_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveSession' +type MockDatabase_RemoveSession_Call struct { + *mock.Call +} + +// RemoveSession is a helper method to define mock.On call +// - ctx context.Context +// - id int64 +func (_e *MockDatabase_Expecter) RemoveSession(ctx interface{}, id interface{}) *MockDatabase_RemoveSession_Call { + return &MockDatabase_RemoveSession_Call{Call: _e.mock.On("RemoveSession", ctx, id)} +} + +func (_c *MockDatabase_RemoveSession_Call) Run(run func(ctx context.Context, id int64)) *MockDatabase_RemoveSession_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64)) + }) + return _c +} + +func (_c *MockDatabase_RemoveSession_Call) Return(_a0 error) *MockDatabase_RemoveSession_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockDatabase_RemoveSession_Call) RunAndReturn(run func(context.Context, int64) error) *MockDatabase_RemoveSession_Call { + _c.Call.Return(run) + return _c +} + +// NewMockDatabase creates a new instance of MockDatabase. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockDatabase(t interface { + mock.TestingT + Cleanup(func()) +}) *MockDatabase { + mock := &MockDatabase{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_FileStorage.go b/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_FileStorage.go new file mode 100644 index 0000000..58900cb --- /dev/null +++ b/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_FileStorage.go @@ -0,0 +1,32 @@ +// Code generated by mockery v2.48.0. DO NOT EDIT. + +package storage + +import mock "github.com/stretchr/testify/mock" + +// MockFileStorage is an autogenerated mock type for the FileStorage type +type MockFileStorage struct { + mock.Mock +} + +type MockFileStorage_Expecter struct { + mock *mock.Mock +} + +func (_m *MockFileStorage) EXPECT() *MockFileStorage_Expecter { + return &MockFileStorage_Expecter{mock: &_m.Mock} +} + +// NewMockFileStorage creates a new instance of MockFileStorage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockFileStorage(t interface { + mock.TestingT + Cleanup(func()) +}) *MockFileStorage { + mock := &MockFileStorage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_MetaStorage.go b/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_MetaStorage.go new file mode 100644 index 0000000..b6f8492 --- /dev/null +++ b/mocks/git.optclblast.xyz/draincloud/draincloud-core/internal/storage/mock_MetaStorage.go @@ -0,0 +1,95 @@ +// Code generated by mockery v2.48.0. DO NOT EDIT. + +package storage + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// MockMetaStorage is an autogenerated mock type for the MetaStorage type +type MockMetaStorage struct { + mock.Mock +} + +type MockMetaStorage_Expecter struct { + mock *mock.Mock +} + +func (_m *MockMetaStorage) EXPECT() *MockMetaStorage_Expecter { + return &MockMetaStorage_Expecter{mock: &_m.Mock} +} + +// SaveMetadata provides a mock function with given fields: ctx, fileType, size, ext +func (_m *MockMetaStorage) SaveMetadata(ctx context.Context, fileType string, size int64, ext string) (int64, error) { + ret := _m.Called(ctx, fileType, size, ext) + + if len(ret) == 0 { + panic("no return value specified for SaveMetadata") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, int64, string) (int64, error)); ok { + return rf(ctx, fileType, size, ext) + } + if rf, ok := ret.Get(0).(func(context.Context, string, int64, string) int64); ok { + r0 = rf(ctx, fileType, size, ext) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, int64, string) error); ok { + r1 = rf(ctx, fileType, size, ext) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockMetaStorage_SaveMetadata_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveMetadata' +type MockMetaStorage_SaveMetadata_Call struct { + *mock.Call +} + +// SaveMetadata is a helper method to define mock.On call +// - ctx context.Context +// - fileType string +// - size int64 +// - ext string +func (_e *MockMetaStorage_Expecter) SaveMetadata(ctx interface{}, fileType interface{}, size interface{}, ext interface{}) *MockMetaStorage_SaveMetadata_Call { + return &MockMetaStorage_SaveMetadata_Call{Call: _e.mock.On("SaveMetadata", ctx, fileType, size, ext)} +} + +func (_c *MockMetaStorage_SaveMetadata_Call) Run(run func(ctx context.Context, fileType string, size int64, ext string)) *MockMetaStorage_SaveMetadata_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(int64), args[3].(string)) + }) + return _c +} + +func (_c *MockMetaStorage_SaveMetadata_Call) Return(_a0 int64, _a1 error) *MockMetaStorage_SaveMetadata_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockMetaStorage_SaveMetadata_Call) RunAndReturn(run func(context.Context, string, int64, string) (int64, error)) *MockMetaStorage_SaveMetadata_Call { + _c.Call.Return(run) + return _c +} + +// NewMockMetaStorage creates a new instance of MockMetaStorage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockMetaStorage(t interface { + mock.TestingT + Cleanup(func()) +}) *MockMetaStorage { + mock := &MockMetaStorage{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +}