diff --git a/api/chain/gateway/internal/service/gateway/service.go b/api/chain/gateway/internal/service/gateway/service.go index 4affea2..f97f47b 100644 --- a/api/chain/gateway/internal/service/gateway/service.go +++ b/api/chain/gateway/internal/service/gateway/service.go @@ -4,7 +4,6 @@ import ( "context" "strings" - gatewayv1 "github.com/tech/sendico/chain/gateway/internal/generated/service/gateway/v1" "github.com/tech/sendico/chain/gateway/internal/keymanager" "github.com/tech/sendico/chain/gateway/storage" "github.com/tech/sendico/chain/gateway/storage/model" @@ -14,6 +13,7 @@ import ( msg "github.com/tech/sendico/pkg/messaging" "github.com/tech/sendico/pkg/mlogger" "github.com/tech/sendico/pkg/mservice" + gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" "go.mongodb.org/mongo-driver/bson/primitive" "google.golang.org/grpc" ) diff --git a/api/chain/gateway/internal/service/gateway/service_test.go b/api/chain/gateway/internal/service/gateway/service_test.go index 61a41e6..495d523 100644 --- a/api/chain/gateway/internal/service/gateway/service_test.go +++ b/api/chain/gateway/internal/service/gateway/service_test.go @@ -11,7 +11,7 @@ import ( "time" "github.com/stretchr/testify/require" - igatewayv1 "github.com/tech/sendico/chain/gateway/internal/generated/service/gateway/v1" + igatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" "google.golang.org/grpc/codes" diff --git a/api/chain/gateway/internal/service/gateway/transfer_handlers.go b/api/chain/gateway/internal/service/gateway/transfer_handlers.go index 43593c8..70560c1 100644 --- a/api/chain/gateway/internal/service/gateway/transfer_handlers.go +++ b/api/chain/gateway/internal/service/gateway/transfer_handlers.go @@ -5,14 +5,14 @@ import ( "errors" "strings" - gatewayv1 "github.com/tech/sendico/chain/gateway/internal/generated/service/gateway/v1" + "github.com/shopspring/decimal" "github.com/tech/sendico/chain/gateway/storage/model" "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mservice" + gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1" - "github.com/shopspring/decimal" "go.uber.org/zap" "google.golang.org/protobuf/types/known/timestamppb" ) diff --git a/api/chain/gateway/internal/service/gateway/wallet_handlers.go b/api/chain/gateway/internal/service/gateway/wallet_handlers.go index cff2b66..d0bc84b 100644 --- a/api/chain/gateway/internal/service/gateway/wallet_handlers.go +++ b/api/chain/gateway/internal/service/gateway/wallet_handlers.go @@ -5,11 +5,11 @@ import ( "errors" "strings" - gatewayv1 "github.com/tech/sendico/chain/gateway/internal/generated/service/gateway/v1" "github.com/tech/sendico/chain/gateway/storage/model" "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mservice" + gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1" "go.uber.org/zap" "google.golang.org/protobuf/types/known/timestamppb" diff --git a/api/fx/storage/go.sum b/api/fx/storage/go.sum index 0ddb9ed..3151347 100644 --- a/api/fx/storage/go.sum +++ b/api/fx/storage/go.sum @@ -7,8 +7,6 @@ github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE= github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/casbin/casbin/v2 v2.128.0 h1:761dLmXLy/ZNSckAITvpUZ8VdrxARyIlwmdafHzRb7Y= -github.com/casbin/casbin/v2 v2.128.0/go.mod h1:iAwqzcYzJtAK5QWGT2uRl9WfRxXyKFBG1AZuhk2NAQg= github.com/casbin/casbin/v2 v2.132.0 h1:73hGmOszGSL3hTVquwkAi98XLl3gPJ+BxB6D7G9Fxtk= github.com/casbin/casbin/v2 v2.132.0/go.mod h1:FmcfntdXLTcYXv/hxgNntcRPqAbwOG9xsism0yXT+18= github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= @@ -120,8 +118,6 @@ github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfS github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw= -go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss= go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= diff --git a/api/ledger/internal/service/ledger/accounts.go b/api/ledger/internal/service/ledger/accounts.go index b2343c8..317179b 100644 --- a/api/ledger/internal/service/ledger/accounts.go +++ b/api/ledger/internal/service/ledger/accounts.go @@ -5,10 +5,10 @@ import ( "errors" "strings" - ledgerv1 "github.com/tech/sendico/ledger/internal/generated/service/ledger/v1" "github.com/tech/sendico/ledger/storage/model" "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" + ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1" "go.uber.org/zap" "google.golang.org/protobuf/types/known/timestamppb" ) diff --git a/api/ledger/internal/service/ledger/accounts_test.go b/api/ledger/internal/service/ledger/accounts_test.go index e903917..657324a 100644 --- a/api/ledger/internal/service/ledger/accounts_test.go +++ b/api/ledger/internal/service/ledger/accounts_test.go @@ -9,10 +9,10 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" - ledgerv1 "github.com/tech/sendico/ledger/internal/generated/service/ledger/v1" "github.com/tech/sendico/ledger/storage" "github.com/tech/sendico/ledger/storage/model" "github.com/tech/sendico/pkg/merrors" + ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1" ) type accountStoreStub struct { diff --git a/api/ledger/internal/service/ledger/helpers.go b/api/ledger/internal/service/ledger/helpers.go index a5265b3..63baf19 100644 --- a/api/ledger/internal/service/ledger/helpers.go +++ b/api/ledger/internal/service/ledger/helpers.go @@ -4,11 +4,11 @@ import ( "fmt" "time" - ledgerv1 "github.com/tech/sendico/ledger/internal/generated/service/ledger/v1" + "github.com/shopspring/decimal" "github.com/tech/sendico/ledger/storage/model" "github.com/tech/sendico/pkg/merrors" moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" - "github.com/shopspring/decimal" + ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1" "go.mongodb.org/mongo-driver/bson/primitive" "google.golang.org/protobuf/types/known/timestamppb" ) diff --git a/api/ledger/internal/service/ledger/helpers_test.go b/api/ledger/internal/service/ledger/helpers_test.go index ccb856a..ebeeb5e 100644 --- a/api/ledger/internal/service/ledger/helpers_test.go +++ b/api/ledger/internal/service/ledger/helpers_test.go @@ -4,12 +4,12 @@ import ( "testing" "time" - ledgerv1 "github.com/tech/sendico/ledger/internal/generated/service/ledger/v1" - "github.com/tech/sendico/ledger/storage/model" - moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tech/sendico/ledger/storage/model" + moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" + ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1" "go.mongodb.org/mongo-driver/bson/primitive" "google.golang.org/protobuf/types/known/timestamppb" ) diff --git a/api/ledger/internal/service/ledger/outbox_publisher_test.go b/api/ledger/internal/service/ledger/outbox_publisher_test.go index c9b0bba..47f2e2f 100644 --- a/api/ledger/internal/service/ledger/outbox_publisher_test.go +++ b/api/ledger/internal/service/ledger/outbox_publisher_test.go @@ -8,10 +8,10 @@ import ( "testing" "time" - "github.com/tech/sendico/ledger/storage/model" - me "github.com/tech/sendico/pkg/messaging/envelope" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tech/sendico/ledger/storage/model" + me "github.com/tech/sendico/pkg/messaging/envelope" "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" ) diff --git a/api/ledger/internal/service/ledger/posting.go b/api/ledger/internal/service/ledger/posting.go index 0492bcf..7655b6e 100644 --- a/api/ledger/internal/service/ledger/posting.go +++ b/api/ledger/internal/service/ledger/posting.go @@ -5,12 +5,12 @@ import ( "fmt" "time" - ledgerv1 "github.com/tech/sendico/ledger/internal/generated/service/ledger/v1" "github.com/tech/sendico/ledger/storage" "github.com/tech/sendico/ledger/storage/model" storageMongo "github.com/tech/sendico/ledger/storage/mongo" "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" + ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1" "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" ) diff --git a/api/ledger/internal/service/ledger/posting_debit.go b/api/ledger/internal/service/ledger/posting_debit.go index 717975f..7faac35 100644 --- a/api/ledger/internal/service/ledger/posting_debit.go +++ b/api/ledger/internal/service/ledger/posting_debit.go @@ -5,12 +5,12 @@ import ( "fmt" "time" - ledgerv1 "github.com/tech/sendico/ledger/internal/generated/service/ledger/v1" "github.com/tech/sendico/ledger/storage" "github.com/tech/sendico/ledger/storage/model" storageMongo "github.com/tech/sendico/ledger/storage/mongo" "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" + ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1" "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" ) diff --git a/api/ledger/internal/service/ledger/posting_fx.go b/api/ledger/internal/service/ledger/posting_fx.go index 95e7ac3..bd4d1d1 100644 --- a/api/ledger/internal/service/ledger/posting_fx.go +++ b/api/ledger/internal/service/ledger/posting_fx.go @@ -5,12 +5,12 @@ import ( "fmt" "time" - ledgerv1 "github.com/tech/sendico/ledger/internal/generated/service/ledger/v1" "github.com/tech/sendico/ledger/storage" "github.com/tech/sendico/ledger/storage/model" storageMongo "github.com/tech/sendico/ledger/storage/mongo" "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" + ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1" "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" ) diff --git a/api/ledger/internal/service/ledger/posting_support.go b/api/ledger/internal/service/ledger/posting_support.go index d3ff4a7..e5c20ae 100644 --- a/api/ledger/internal/service/ledger/posting_support.go +++ b/api/ledger/internal/service/ledger/posting_support.go @@ -7,10 +7,10 @@ import ( "fmt" "time" + "github.com/shopspring/decimal" "github.com/tech/sendico/ledger/storage" "github.com/tech/sendico/ledger/storage/model" "github.com/tech/sendico/pkg/merrors" - "github.com/shopspring/decimal" "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" ) diff --git a/api/ledger/internal/service/ledger/posting_support_test.go b/api/ledger/internal/service/ledger/posting_support_test.go index 1cc3731..e16b677 100644 --- a/api/ledger/internal/service/ledger/posting_support_test.go +++ b/api/ledger/internal/service/ledger/posting_support_test.go @@ -7,11 +7,11 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/tech/sendico/ledger/storage" "github.com/tech/sendico/ledger/storage/model" "github.com/tech/sendico/pkg/merrors" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" ) diff --git a/api/ledger/internal/service/ledger/posting_transfer.go b/api/ledger/internal/service/ledger/posting_transfer.go index b17e990..00534a9 100644 --- a/api/ledger/internal/service/ledger/posting_transfer.go +++ b/api/ledger/internal/service/ledger/posting_transfer.go @@ -5,12 +5,12 @@ import ( "fmt" "time" - ledgerv1 "github.com/tech/sendico/ledger/internal/generated/service/ledger/v1" "github.com/tech/sendico/ledger/storage" "github.com/tech/sendico/ledger/storage/model" storageMongo "github.com/tech/sendico/ledger/storage/mongo" "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" + ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1" "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" ) diff --git a/api/ledger/internal/service/ledger/queries.go b/api/ledger/internal/service/ledger/queries.go index 6e1a681..e59e8dd 100644 --- a/api/ledger/internal/service/ledger/queries.go +++ b/api/ledger/internal/service/ledger/queries.go @@ -7,11 +7,11 @@ import ( "strconv" "strings" - ledgerv1 "github.com/tech/sendico/ledger/internal/generated/service/ledger/v1" "github.com/tech/sendico/ledger/storage" "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" + ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1" "go.uber.org/zap" "google.golang.org/protobuf/types/known/timestamppb" ) diff --git a/api/ledger/internal/service/ledger/service.go b/api/ledger/internal/service/ledger/service.go index b5e95b6..ce9c4cb 100644 --- a/api/ledger/internal/service/ledger/service.go +++ b/api/ledger/internal/service/ledger/service.go @@ -7,8 +7,8 @@ import ( "sync" "time" - feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1" "github.com/shopspring/decimal" + feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1" "google.golang.org/grpc" "google.golang.org/protobuf/types/known/timestamppb" @@ -16,11 +16,11 @@ import ( moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" tracev1 "github.com/tech/sendico/pkg/proto/common/trace/v1" - ledgerv1 "github.com/tech/sendico/ledger/internal/generated/service/ledger/v1" "github.com/tech/sendico/ledger/storage" "github.com/tech/sendico/pkg/api/routers" pmessaging "github.com/tech/sendico/pkg/messaging" "github.com/tech/sendico/pkg/mlogger" + ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1" ) type serviceError string diff --git a/api/pkg/db/internal/mongo/organizationdb/setarchived_test.go b/api/pkg/db/internal/mongo/organizationdb/setarchived_test.go index 2c4807f..cdfb27e 100644 --- a/api/pkg/db/internal/mongo/organizationdb/setarchived_test.go +++ b/api/pkg/db/internal/mongo/organizationdb/setarchived_test.go @@ -1,562 +1,300 @@ -//go:build integration -// +build integration - package organizationdb import ( "context" "errors" + "sync" "testing" - "github.com/tech/sendico/pkg/db/internal/mongo/commentdb" - "github.com/tech/sendico/pkg/db/internal/mongo/projectdb" - "github.com/tech/sendico/pkg/db/internal/mongo/reactiondb" - "github.com/tech/sendico/pkg/db/internal/mongo/statusdb" - "github.com/tech/sendico/pkg/db/internal/mongo/taskdb" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tech/sendico/pkg/auth" "github.com/tech/sendico/pkg/db/repository/builder" + rd "github.com/tech/sendico/pkg/db/repository/decoder" + ri "github.com/tech/sendico/pkg/db/repository/index" + "github.com/tech/sendico/pkg/db/storable" "github.com/tech/sendico/pkg/db/template" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/model" "github.com/tech/sendico/pkg/mservice" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/testcontainers/testcontainers-go/modules/mongodb" "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" ) -func setupSetArchivedTestDB(t *testing.T) (*OrganizationDB, *projectDBAdapter, *taskdb.TaskDB, *commentdb.CommentDB, *reactiondb.ReactionDB, func()) { +func TestOrganizationDB_SetArchived_TogglesState(t *testing.T) { ctx := context.Background() + accountRef := primitive.NewObjectID() + orgDB := newTestOrganizationDB(t) - // Start MongoDB container - mongodbContainer, err := mongodb.Run(ctx, "mongo:latest") - require.NoError(t, err) + org := &model.Organization{ + OrganizationBase: model.OrganizationBase{ + Describable: model.Describable{Name: "Sendico"}, + TimeZone: "UTC", + }, + } + org.SetID(primitive.NewObjectID()) - // Get connection string - endpoint, err := mongodbContainer.Endpoint(ctx, "") - require.NoError(t, err) + require.NoError(t, orgDB.Create(ctx, accountRef, *org.GetID(), org)) - // Connect to MongoDB - client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://"+endpoint)) - require.NoError(t, err) + var stored model.Organization + require.NoError(t, orgDB.Get(ctx, accountRef, *org.GetID(), &stored)) + assert.False(t, stored.IsArchived()) - db := client.Database("test_organization_setarchived") + require.NoError(t, orgDB.SetArchived(ctx, accountRef, *org.GetID(), true, false)) + require.NoError(t, orgDB.Get(ctx, accountRef, *org.GetID(), &stored)) + assert.True(t, stored.IsArchived()) + + require.NoError(t, orgDB.SetArchived(ctx, accountRef, *org.GetID(), false, false)) + require.NoError(t, orgDB.Get(ctx, accountRef, *org.GetID(), &stored)) + assert.False(t, stored.IsArchived()) +} + +func TestOrganizationDB_SetArchived_UnknownOrganization(t *testing.T) { + ctx := context.Background() + accountRef := primitive.NewObjectID() + orgDB := newTestOrganizationDB(t) + + err := orgDB.SetArchived(ctx, accountRef, primitive.NewObjectID(), true, false) + require.Error(t, err) + assert.True(t, errors.Is(err, merrors.ErrNoData)) +} + +// newTestOrganizationDB wires the real OrganizationDB implementation to an in-memory repository +// so the tests exercise actual SetArchived behavior without external dependencies. +func newTestOrganizationDB(t *testing.T) *OrganizationDB { + t.Helper() + + repo := newMemoryOrganizationRepository() logger := zap.NewNop() - // Create mock enforcer and policy DB - mockEnforcer := &mockSetArchivedEnforcer{} - mockPolicyDB := &mockSetArchivedPolicyDB{} - mockPGroupDB := &mockSetArchivedPGroupDB{} - - // Create databases - // We need to create a projectDB first, but we'll create a temporary one for organizationDB creation - // Create temporary taskDB and statusDB for the temporary projectDB - // Create temporary reactionDB and commentDB for the temporary taskDB - tempReactionDB, err := reactiondb.Create(ctx, logger, mockEnforcer, mockPolicyDB, db) - require.NoError(t, err) - - tempCommentDB, err := commentdb.Create(ctx, logger, mockEnforcer, mockPolicyDB, db, tempReactionDB) - require.NoError(t, err) - - tempTaskDB, err := taskdb.Create(ctx, logger, mockEnforcer, mockPolicyDB, db, tempCommentDB, tempReactionDB) - require.NoError(t, err) - - tempStatusDB, err := statusdb.Create(ctx, logger, mockEnforcer, mockPolicyDB, db) - require.NoError(t, err) - - tempProjectDB, err := projectdb.Create(ctx, logger, mockEnforcer, mockPolicyDB, tempTaskDB, tempStatusDB, db) - require.NoError(t, err) - - // Create adapter for organizationDB creation - tempProjectDBAdapter := &projectDBAdapter{ - ProjectDB: tempProjectDB, - taskDB: tempTaskDB, - commentDB: tempCommentDB, - reactionDB: tempReactionDB, - statusDB: tempStatusDB, + dbImp := &template.DBImp[*model.Organization]{ + Logger: logger, + Repository: repo, } + dbImp.SetDeleter(func(ctx context.Context, objectRef primitive.ObjectID) error { + return repo.Delete(ctx, objectRef) + }) - organizationDB, err := Create(ctx, logger, mockEnforcer, mockPolicyDB, tempProjectDBAdapter, mockPGroupDB, db) - require.NoError(t, err) - - var projectDB *projectdb.ProjectDB - var taskDB *taskdb.TaskDB - var commentDB *commentdb.CommentDB - var reactionDB *reactiondb.ReactionDB - var statusDB *statusdb.StatusDB - - // Create databases in dependency order - reactionDB, err = reactiondb.Create(ctx, logger, mockEnforcer, mockPolicyDB, db) - require.NoError(t, err) - - commentDB, err = commentdb.Create(ctx, logger, mockEnforcer, mockPolicyDB, db, reactionDB) - require.NoError(t, err) - - taskDB, err = taskdb.Create(ctx, logger, mockEnforcer, mockPolicyDB, db, commentDB, reactionDB) - require.NoError(t, err) - - statusDB, err = statusdb.Create(ctx, logger, mockEnforcer, mockPolicyDB, db) - require.NoError(t, err) - - projectDB, err = projectdb.Create(ctx, logger, mockEnforcer, mockPolicyDB, taskDB, statusDB, db) - require.NoError(t, err) - - // Create adapter for the actual projectDB - projectDBAdapter := &projectDBAdapter{ - ProjectDB: projectDB, - taskDB: taskDB, - commentDB: commentDB, - reactionDB: reactionDB, - statusDB: statusDB, + return &OrganizationDB{ + ProtectedDBImp: auth.ProtectedDBImp[*model.Organization]{ + DBImp: dbImp, + Enforcer: allowAllEnforcer{}, + PermissionRef: primitive.NewObjectID(), + Collection: mservice.Organizations, + }, } - - cleanup := func() { - client.Disconnect(context.Background()) - mongodbContainer.Terminate(ctx) - } - - return organizationDB, projectDBAdapter, taskDB, commentDB, reactionDB, cleanup } -// projectDBAdapter adapts projectdb.ProjectDB to project.DB interface for testing -type projectDBAdapter struct { - *projectdb.ProjectDB - taskDB *taskdb.TaskDB - commentDB *commentdb.CommentDB - reactionDB *reactiondb.ReactionDB - statusDB *statusdb.StatusDB -} +type allowAllEnforcer struct{} -// DeleteCascade implements the project.DB interface -func (a *projectDBAdapter) DeleteCascade(ctx context.Context, projectRef primitive.ObjectID) error { - // Call the concrete implementation - return a.ProjectDB.DeleteCascade(ctx, projectRef) -} - -// SetArchived implements the project.DB interface -func (a *projectDBAdapter) SetArchived(ctx context.Context, accountRef, organizationRef, projectRef primitive.ObjectID, archived, cascade bool) error { - // Use the stored dependencies for the concrete implementation - return a.ProjectDB.SetArchived(ctx, accountRef, organizationRef, projectRef, archived, cascade) -} - -// List implements the project.DB interface -func (a *projectDBAdapter) List(ctx context.Context, accountRef, organizationRef, _ primitive.ObjectID, cursor *model.ViewCursor) ([]model.Project, error) { - return a.ProjectDB.List(ctx, accountRef, organizationRef, primitive.NilObjectID, cursor) -} - -// Previews implements the project.DB interface -func (a *projectDBAdapter) Previews(ctx context.Context, accountRef, organizationRef primitive.ObjectID, projectRefs []primitive.ObjectID, cursor *model.ViewCursor, assigneeRefs, reporterRefs []primitive.ObjectID) ([]model.ProjectPreview, error) { - return a.ProjectDB.Previews(ctx, accountRef, organizationRef, projectRefs, cursor, assigneeRefs, reporterRefs) -} - -// DeleteProject implements the project.DB interface -func (a *projectDBAdapter) DeleteProject(ctx context.Context, accountRef, organizationRef, projectRef primitive.ObjectID, migrateToRef *primitive.ObjectID) error { - // Call the concrete implementation with the organizationRef - return a.ProjectDB.DeleteProject(ctx, accountRef, organizationRef, projectRef, migrateToRef) -} - -// RemoveTagFromProjects implements the project.DB interface -func (a *projectDBAdapter) RemoveTagFromProjects(ctx context.Context, accountRef, organizationRef, tagRef primitive.ObjectID) error { - // Call the concrete implementation - return a.ProjectDB.RemoveTagFromProjects(ctx, accountRef, organizationRef, tagRef) -} - -// Mock implementations for SetArchived testing -type mockSetArchivedEnforcer struct{} - -func (m *mockSetArchivedEnforcer) Enforce(ctx context.Context, permissionRef, accountRef, orgRef, objectRef primitive.ObjectID, action model.Action) (bool, error) { +func (allowAllEnforcer) Enforce(context.Context, primitive.ObjectID, primitive.ObjectID, primitive.ObjectID, primitive.ObjectID, model.Action) (bool, error) { return true, nil } -func (m *mockSetArchivedEnforcer) EnforceBatch(ctx context.Context, objectRefs []model.PermissionBoundStorable, accountRef primitive.ObjectID, action model.Action) (map[primitive.ObjectID]bool, error) { - // Allow all objects for testing - result := make(map[primitive.ObjectID]bool) - for _, obj := range objectRefs { +func (allowAllEnforcer) EnforceBatch(_ context.Context, objects []model.PermissionBoundStorable, _ primitive.ObjectID, _ model.Action) (map[primitive.ObjectID]bool, error) { + result := make(map[primitive.ObjectID]bool, len(objects)) + for _, obj := range objects { result[*obj.GetID()] = true } return result, nil } -func (m *mockSetArchivedEnforcer) GetRoles(ctx context.Context, accountRef, organizationRef primitive.ObjectID) ([]model.Role, error) { +func (allowAllEnforcer) GetRoles(context.Context, primitive.ObjectID, primitive.ObjectID) ([]model.Role, error) { return nil, nil } -func (m *mockSetArchivedEnforcer) GetPermissions(ctx context.Context, accountRef, organizationRef primitive.ObjectID) ([]model.Role, []model.Permission, error) { +func (allowAllEnforcer) GetPermissions(context.Context, primitive.ObjectID, primitive.ObjectID) ([]model.Role, []model.Permission, error) { return nil, nil, nil } -type mockSetArchivedPolicyDB struct{} +type memoryOrganizationRepository struct { + mu sync.RWMutex + data map[primitive.ObjectID]*model.Organization + order []primitive.ObjectID +} -func (m *mockSetArchivedPolicyDB) Create(ctx context.Context, policy *model.PolicyDescription) error { +func newMemoryOrganizationRepository() *memoryOrganizationRepository { + return &memoryOrganizationRepository{ + data: make(map[primitive.ObjectID]*model.Organization), + } +} + +func (m *memoryOrganizationRepository) Aggregate(context.Context, builder.Pipeline, rd.DecodingFunc) error { + return merrors.NotImplemented("aggregate is not supported in memory repository") +} + +func (m *memoryOrganizationRepository) Insert(_ context.Context, obj storable.Storable, _ builder.Query) error { + m.mu.Lock() + defer m.mu.Unlock() + + org, ok := obj.(*model.Organization) + if !ok { + return merrors.InvalidDataType("expected organization") + } + id := org.GetID() + if id == nil || *id == primitive.NilObjectID { + return merrors.InvalidArgument("organization ID must be set") + } + if _, exists := m.data[*id]; exists { + return merrors.DataConflict("organization already exists") + } + m.data[*id] = cloneOrganization(org) + m.order = append(m.order, *id) return nil } -func (m *mockSetArchivedPolicyDB) Get(ctx context.Context, policyRef primitive.ObjectID, result *model.PolicyDescription) error { +func (m *memoryOrganizationRepository) InsertMany(ctx context.Context, objects []storable.Storable) error { + for _, obj := range objects { + if err := m.Insert(ctx, obj, nil); err != nil { + return err + } + } + return nil +} + +func (m *memoryOrganizationRepository) Get(_ context.Context, id primitive.ObjectID, result storable.Storable) error { + m.mu.RLock() + defer m.mu.RUnlock() + + org, ok := m.data[id] + if !ok { + return merrors.ErrNoData + } + dst, ok := result.(*model.Organization) + if !ok { + return merrors.InvalidDataType("expected organization result") + } + *dst = *cloneOrganization(org) + return nil +} + +func (m *memoryOrganizationRepository) FindOneByFilter(_ context.Context, query builder.Query, result storable.Storable) error { + m.mu.RLock() + defer m.mu.RUnlock() + for _, id := range m.order { + if org, ok := m.data[id]; ok && m.matchesQuery(query, org) { + dst, okCast := result.(*model.Organization) + if !okCast { + return merrors.InvalidDataType("expected organization result") + } + *dst = *cloneOrganization(org) + return nil + } + } return merrors.ErrNoData } -func (m *mockSetArchivedPolicyDB) InsertMany(ctx context.Context, objects []*model.PolicyDescription) error { return nil } +func (m *memoryOrganizationRepository) FindManyByFilter(context.Context, builder.Query, rd.DecodingFunc) error { + return merrors.NotImplemented("FindManyByFilter is not supported in memory repository") +} -func (m *mockSetArchivedPolicyDB) Update(ctx context.Context, policy *model.PolicyDescription) error { +func (m *memoryOrganizationRepository) Update(_ context.Context, obj storable.Storable) error { + m.mu.Lock() + defer m.mu.Unlock() + + org, ok := obj.(*model.Organization) + if !ok { + return merrors.InvalidDataType("expected organization") + } + id := org.GetID() + if id == nil { + return merrors.InvalidArgument("organization ID must be set") + } + if _, exists := m.data[*id]; !exists { + return merrors.ErrNoData + } + m.data[*id] = cloneOrganization(org) return nil } -func (m *mockSetArchivedPolicyDB) Patch(ctx context.Context, objectRef primitive.ObjectID, patch builder.Patch) error { +func (m *memoryOrganizationRepository) Patch(context.Context, primitive.ObjectID, builder.Patch) error { + return merrors.NotImplemented("Patch is not supported in memory repository") +} + +func (m *memoryOrganizationRepository) PatchMany(context.Context, builder.Query, builder.Patch) (int, error) { + return 0, merrors.NotImplemented("PatchMany is not supported in memory repository") +} + +func (m *memoryOrganizationRepository) Delete(_ context.Context, id primitive.ObjectID) error { + m.mu.Lock() + defer m.mu.Unlock() + if _, exists := m.data[id]; !exists { + return merrors.ErrNoData + } + delete(m.data, id) return nil } -func (m *mockSetArchivedPolicyDB) Delete(ctx context.Context, policyRef primitive.ObjectID) error { +func (m *memoryOrganizationRepository) DeleteMany(context.Context, builder.Query) error { + return merrors.NotImplemented("DeleteMany is not supported in memory repository") +} + +func (m *memoryOrganizationRepository) CreateIndex(*ri.Definition) error { return nil } -func (m *mockSetArchivedPolicyDB) DeleteMany(ctx context.Context, filter builder.Query) error { - return nil -} +func (m *memoryOrganizationRepository) ListIDs(_ context.Context, query builder.Query) ([]primitive.ObjectID, error) { + m.mu.RLock() + defer m.mu.RUnlock() -func (m *mockSetArchivedPolicyDB) FindOne(ctx context.Context, filter builder.Query, result *model.PolicyDescription) error { - return merrors.ErrNoData -} - -func (m *mockSetArchivedPolicyDB) ListIDs(ctx context.Context, query builder.Query) ([]primitive.ObjectID, error) { - return nil, nil -} - -func (m *mockSetArchivedPolicyDB) ListPermissionBound(ctx context.Context, query builder.Query) ([]model.PermissionBoundStorable, error) { - return nil, nil -} -func (m *mockSetArchivedPolicyDB) Collection() string { return "" } -func (m *mockSetArchivedPolicyDB) All(ctx context.Context, organizationRef primitive.ObjectID) ([]model.PolicyDescription, error) { - return nil, nil -} - -func (m *mockSetArchivedPolicyDB) Policies(ctx context.Context, refs []primitive.ObjectID) ([]model.PolicyDescription, error) { - return nil, nil -} - -func (m *mockSetArchivedPolicyDB) GetBuiltInPolicy(ctx context.Context, resourceType mservice.Type, policy *model.PolicyDescription) error { - return nil -} - -func (m *mockSetArchivedPolicyDB) DeleteCascade(ctx context.Context, policyRef primitive.ObjectID) error { - return nil -} - -type mockSetArchivedPGroupDB struct{} - -func (m *mockSetArchivedPGroupDB) Create(ctx context.Context, accountRef, organizationRef primitive.ObjectID, pgroup *model.PriorityGroup) error { - return nil -} -func (m *mockSetArchivedPGroupDB) InsertMany(ctx context.Context, accountRef, organizationRef primitive.ObjectID, objects []*model.PriorityGroup) error { return nil } - -func (m *mockSetArchivedPGroupDB) Get(ctx context.Context, accountRef, pgroupRef primitive.ObjectID, result *model.PriorityGroup) error { - return merrors.ErrNoData -} - -func (m *mockSetArchivedPGroupDB) Update(ctx context.Context, accountRef primitive.ObjectID, pgroup *model.PriorityGroup) error { - return nil -} - -func (m *mockSetArchivedPGroupDB) Delete(ctx context.Context, accountRef, pgroupRef primitive.ObjectID) error { - return nil -} - -func (m *mockSetArchivedPGroupDB) DeleteCascadeAuth(ctx context.Context, accountRef, pgroupRef primitive.ObjectID) error { - return nil -} - -func (m *mockSetArchivedPGroupDB) Patch(ctx context.Context, accountRef, pgroupRef primitive.ObjectID, patch builder.Patch) error { - return nil -} - -func (m *mockSetArchivedPGroupDB) PatchMany(ctx context.Context, accountRef primitive.ObjectID, query builder.Query, patch builder.Patch) (int, error) { - return 0, nil -} - -func (m *mockSetArchivedPGroupDB) Unprotected() template.DB[*model.PriorityGroup] { - return nil -} - -func (m *mockSetArchivedPGroupDB) ListIDs(ctx context.Context, action model.Action, accountRef primitive.ObjectID, query builder.Query) ([]primitive.ObjectID, error) { - return nil, nil -} - -func (m *mockSetArchivedPGroupDB) All(ctx context.Context, organizationRef primitive.ObjectID, limit, offset *int64) ([]model.PriorityGroup, error) { - return nil, nil -} - -func (m *mockSetArchivedPGroupDB) List(ctx context.Context, accountRef, organizationRef, _ primitive.ObjectID, cursor *model.ViewCursor) ([]model.PriorityGroup, error) { - return nil, nil -} - -func (m *mockSetArchivedPGroupDB) DeleteCascade(ctx context.Context, statusRef primitive.ObjectID) error { - return nil -} - -func (m *mockSetArchivedPGroupDB) SetArchived(ctx context.Context, accountRef, organizationRef, statusRef primitive.ObjectID, archived, cascade bool) error { - return nil -} - -func (m *mockSetArchivedPGroupDB) Reorder(ctx context.Context, accountRef, priorityGroupRef primitive.ObjectID, oldIndex, newIndex int) error { - return nil -} - -// Mock project DB for statusdb creation -type mockSetArchivedProjectDB struct{} - -func (m *mockSetArchivedProjectDB) Create(ctx context.Context, accountRef, organizationRef primitive.ObjectID, project *model.Project) error { - return nil -} -func (m *mockSetArchivedProjectDB) Get(ctx context.Context, accountRef, projectRef primitive.ObjectID, result *model.Project) error { - return merrors.ErrNoData -} -func (m *mockSetArchivedProjectDB) Update(ctx context.Context, accountRef primitive.ObjectID, project *model.Project) error { - return nil -} -func (m *mockSetArchivedProjectDB) Delete(ctx context.Context, accountRef, projectRef primitive.ObjectID) error { - return nil -} -func (m *mockSetArchivedProjectDB) DeleteCascadeAuth(ctx context.Context, accountRef, projectRef primitive.ObjectID) error { - return nil -} -func (m *mockSetArchivedProjectDB) Patch(ctx context.Context, accountRef, objectRef primitive.ObjectID, patch builder.Patch) error { - return nil -} -func (m *mockSetArchivedProjectDB) PatchMany(ctx context.Context, accountRef primitive.ObjectID, query builder.Query, patch builder.Patch) (int, error) { - return 0, nil -} -func (m *mockSetArchivedProjectDB) Unprotected() template.DB[*model.Project] { return nil } -func (m *mockSetArchivedProjectDB) ListIDs(ctx context.Context, action model.Action, accountRef primitive.ObjectID, query builder.Query) ([]primitive.ObjectID, error) { - return nil, nil -} -func (m *mockSetArchivedProjectDB) List(ctx context.Context, accountRef, organizationRef, _ primitive.ObjectID, cursor *model.ViewCursor) ([]model.Project, error) { - return nil, nil -} -func (m *mockSetArchivedProjectDB) Previews(ctx context.Context, accountRef, organizationRef primitive.ObjectID, projectRefs []primitive.ObjectID, cursor *model.ViewCursor, assigneeRefs, reporterRefs []primitive.ObjectID) ([]model.ProjectPreview, error) { - return nil, nil -} -func (m *mockSetArchivedProjectDB) DeleteProject(ctx context.Context, accountRef, organizationRef, projectRef primitive.ObjectID, migrateToRef *primitive.ObjectID) error { - return nil -} -func (m *mockSetArchivedProjectDB) DeleteCascade(ctx context.Context, projectRef primitive.ObjectID) error { - return nil -} -func (m *mockSetArchivedProjectDB) SetArchived(ctx context.Context, accountRef, organizationRef, projectRef primitive.ObjectID, archived, cascade bool) error { - return nil -} -func (m *mockSetArchivedProjectDB) All(ctx context.Context, organizationRef primitive.ObjectID, limit, offset *int64) ([]model.Project, error) { - return nil, nil -} -func (m *mockSetArchivedProjectDB) Reorder(ctx context.Context, accountRef, objectRef primitive.ObjectID, newIndex int, filter builder.Query) error { - return nil -} -func (m *mockSetArchivedProjectDB) AddTag(ctx context.Context, accountRef, objectRef, tagRef primitive.ObjectID) error { - return nil -} -func (m *mockSetArchivedProjectDB) RemoveTag(ctx context.Context, accountRef, objectRef, tagRef primitive.ObjectID) error { - return nil -} -func (m *mockSetArchivedProjectDB) RemoveTags(ctx context.Context, accountRef, organizationRef, tagRef primitive.ObjectID) error { - return nil -} -func (m *mockSetArchivedProjectDB) AddTags(ctx context.Context, accountRef, objectRef primitive.ObjectID, tagRefs []primitive.ObjectID) error { - return nil -} -func (m *mockSetArchivedProjectDB) SetTags(ctx context.Context, accountRef, objectRef primitive.ObjectID, tagRefs []primitive.ObjectID) error { - return nil -} -func (m *mockSetArchivedProjectDB) RemoveAllTags(ctx context.Context, accountRef, objectRef primitive.ObjectID) error { - return nil -} -func (m *mockSetArchivedProjectDB) GetTags(ctx context.Context, accountRef, objectRef primitive.ObjectID) ([]primitive.ObjectID, error) { - return nil, nil -} -func (m *mockSetArchivedProjectDB) HasTag(ctx context.Context, accountRef, objectRef, tagRef primitive.ObjectID) (bool, error) { - return false, nil -} -func (m *mockSetArchivedProjectDB) FindByTag(ctx context.Context, accountRef, tagRef primitive.ObjectID) ([]*model.Project, error) { - return nil, nil -} -func (m *mockSetArchivedProjectDB) FindByTags(ctx context.Context, accountRef primitive.ObjectID, tagRefs []primitive.ObjectID) ([]*model.Project, error) { - return nil, nil -} - -func TestOrganizationDB_SetArchived(t *testing.T) { - organizationDB, projectDBAdapter, taskDB, commentDB, reactionDB, cleanup := setupSetArchivedTestDB(t) - defer cleanup() - - ctx := context.Background() - accountRef := primitive.NewObjectID() - - t.Run("SetArchived_OrganizationWithProjectsTasksCommentsAndReactions_Cascade", func(t *testing.T) { - // Create an organization using unprotected DB - organization := &model.Organization{ - OrganizationBase: model.OrganizationBase{ - Describable: model.Describable{Name: "Test Organization for Archive"}, - TimeZone: "UTC", - }, + var ids []primitive.ObjectID + for _, id := range m.order { + if org, ok := m.data[id]; ok && m.matchesQuery(query, org) { + ids = append(ids, id) } - organization.ID = primitive.NewObjectID() - - err := organizationDB.Create(ctx, accountRef, organization.ID, organization) - require.NoError(t, err) - - // Create a project for the organization using unprotected DB - project := &model.Project{ - ProjectBase: model.ProjectBase{ - PermissionBound: model.PermissionBound{ - OrganizationBoundBase: model.OrganizationBoundBase{ - OrganizationRef: organization.ID, - }, - }, - Describable: model.Describable{Name: "Test Project"}, - Indexable: model.Indexable{Index: 0}, - Mnemonic: "TEST", - State: model.ProjectStateActive, - }, - } - project.ID = primitive.NewObjectID() - - err = projectDBAdapter.Unprotected().Create(ctx, project) - require.NoError(t, err) - - // Create a task for the project using unprotected DB - task := &model.Task{ - PermissionBound: model.PermissionBound{ - OrganizationBoundBase: model.OrganizationBoundBase{ - OrganizationRef: organization.ID, - }, - }, - Describable: model.Describable{Name: "Test Task for Archive"}, - ProjectRef: project.ID, - } - task.ID = primitive.NewObjectID() - - err = taskDB.Unprotected().Create(ctx, task) - require.NoError(t, err) - - // Create comments for the task using unprotected DB - comment := &model.Comment{ - CommentBase: model.CommentBase{ - PermissionBound: model.PermissionBound{ - OrganizationBoundBase: model.OrganizationBoundBase{ - OrganizationRef: organization.ID, - }, - }, - AuthorRef: accountRef, - TaskRef: task.ID, - Content: "Test Comment for Archive", - }, - } - comment.ID = primitive.NewObjectID() - - err = commentDB.Unprotected().Create(ctx, comment) - require.NoError(t, err) - - // Create reaction for the comment using unprotected DB - reaction := &model.Reaction{ - PermissionBound: model.PermissionBound{ - OrganizationBoundBase: model.OrganizationBoundBase{ - OrganizationRef: organization.ID, - }, - }, - Type: "like", - AuthorRef: accountRef, - CommentRef: comment.ID, - } - reaction.ID = primitive.NewObjectID() - - err = reactionDB.Unprotected().Create(ctx, reaction) - require.NoError(t, err) - - // Verify all entities are not archived initially - var retrievedOrganization model.Organization - err = organizationDB.Get(ctx, accountRef, organization.ID, &retrievedOrganization) - require.NoError(t, err) - assert.False(t, retrievedOrganization.IsArchived()) - - var retrievedProject model.Project - err = projectDBAdapter.Unprotected().Get(ctx, project.ID, &retrievedProject) - require.NoError(t, err) - assert.False(t, retrievedProject.IsArchived()) - - var retrievedTask model.Task - err = taskDB.Unprotected().Get(ctx, task.ID, &retrievedTask) - require.NoError(t, err) - assert.False(t, retrievedTask.IsArchived()) - - var retrievedComment model.Comment - err = commentDB.Unprotected().Get(ctx, comment.ID, &retrievedComment) - require.NoError(t, err) - assert.False(t, retrievedComment.IsArchived()) - - // Archive organization with cascade - err = organizationDB.SetArchived(ctx, accountRef, organization.ID, true, true) - require.NoError(t, err) - - // Verify all entities are archived due to cascade - err = organizationDB.Get(ctx, accountRef, organization.ID, &retrievedOrganization) - require.NoError(t, err) - assert.True(t, retrievedOrganization.IsArchived()) - - err = projectDBAdapter.Unprotected().Get(ctx, project.ID, &retrievedProject) - require.NoError(t, err) - assert.True(t, retrievedProject.IsArchived()) - - err = taskDB.Unprotected().Get(ctx, task.ID, &retrievedTask) - require.NoError(t, err) - assert.True(t, retrievedTask.IsArchived()) - - err = commentDB.Unprotected().Get(ctx, comment.ID, &retrievedComment) - require.NoError(t, err) - assert.True(t, retrievedComment.IsArchived()) - - // Verify reaction still exists (reactions don't support archiving) - var retrievedReaction model.Reaction - err = reactionDB.Unprotected().Get(ctx, reaction.ID, &retrievedReaction) - require.NoError(t, err) - - // Unarchive organization with cascade - err = organizationDB.SetArchived(ctx, accountRef, organization.ID, false, true) - require.NoError(t, err) - - // Verify all entities are unarchived - err = organizationDB.Get(ctx, accountRef, organization.ID, &retrievedOrganization) - require.NoError(t, err) - assert.False(t, retrievedOrganization.IsArchived()) - - err = projectDBAdapter.Unprotected().Get(ctx, project.ID, &retrievedProject) - require.NoError(t, err) - assert.False(t, retrievedProject.IsArchived()) - - err = taskDB.Unprotected().Get(ctx, task.ID, &retrievedTask) - require.NoError(t, err) - assert.False(t, retrievedTask.IsArchived()) - - err = commentDB.Unprotected().Get(ctx, comment.ID, &retrievedComment) - require.NoError(t, err) - assert.False(t, retrievedComment.IsArchived()) - - // Clean up - err = reactionDB.Unprotected().Delete(ctx, reaction.ID) - require.NoError(t, err) - err = commentDB.Unprotected().Delete(ctx, comment.ID) - require.NoError(t, err) - err = taskDB.Unprotected().Delete(ctx, task.ID) - require.NoError(t, err) - err = projectDBAdapter.Unprotected().Delete(ctx, project.ID) - require.NoError(t, err) - err = organizationDB.Delete(ctx, accountRef, organization.ID) - require.NoError(t, err) - }) - - t.Run("SetArchived_NonExistentOrganization", func(t *testing.T) { - // Try to archive non-existent organization - nonExistentID := primitive.NewObjectID() - err := organizationDB.SetArchived(ctx, accountRef, nonExistentID, true, true) - assert.Error(t, err) - // Could be either no data or access denied error depending on the permission system - assert.True(t, errors.Is(err, merrors.ErrNoData) || errors.Is(err, merrors.ErrAccessDenied)) - }) + } + if len(ids) == 0 { + return nil, merrors.ErrNoData + } + return ids, nil +} + +func (m *memoryOrganizationRepository) ListPermissionBound(_ context.Context, query builder.Query) ([]model.PermissionBoundStorable, error) { + m.mu.RLock() + defer m.mu.RUnlock() + + var res []model.PermissionBoundStorable + for _, org := range m.data { + if m.matchesQuery(query, org) { + res = append(res, cloneOrganization(org)) + } + } + return res, nil +} + +func (m *memoryOrganizationRepository) ListAccountBound(context.Context, builder.Query) ([]model.AccountBoundStorable, error) { + return nil, merrors.NotImplemented("Account bound list not supported") +} + +func (m *memoryOrganizationRepository) Collection() string { + return mservice.Organizations +} + +func (m *memoryOrganizationRepository) matchesQuery(query builder.Query, org *model.Organization) bool { + if query == nil { + return true + } + for _, elem := range query.BuildQuery() { + switch elem.Key { + case storable.IDField: + id, ok := elem.Value.(primitive.ObjectID) + if !ok || *org.GetID() != id { + return false + } + case storable.IsArchivedField: + value, ok := elem.Value.(bool) + if ok && org.IsArchived() != value { + return false + } + } + } + return true +} + +func cloneOrganization(src *model.Organization) *model.Organization { + dst := *src + if len(src.Members) > 0 { + dst.Members = append([]primitive.ObjectID{}, src.Members...) + } + return &dst } diff --git a/api/pkg/go.mod b/api/pkg/go.mod index db3eb0a..cc4aca5 100644 --- a/api/pkg/go.mod +++ b/api/pkg/go.mod @@ -3,7 +3,7 @@ module github.com/tech/sendico/pkg go 1.24.0 require ( - github.com/casbin/casbin/v2 v2.128.0 + github.com/casbin/casbin/v2 v2.132.0 github.com/casbin/mongodb-adapter/v3 v3.7.0 github.com/go-chi/chi/v5 v5.2.3 github.com/google/uuid v1.6.0 @@ -93,6 +93,6 @@ require ( golang.org/x/sys v0.37.0 // indirect golang.org/x/text v0.30.0 // indirect golang.org/x/time v0.5.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/api/pkg/go.sum b/api/pkg/go.sum index 0b28dac..b218651 100644 --- a/api/pkg/go.sum +++ b/api/pkg/go.sum @@ -11,8 +11,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE= github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/casbin/casbin/v2 v2.128.0 h1:761dLmXLy/ZNSckAITvpUZ8VdrxARyIlwmdafHzRb7Y= -github.com/casbin/casbin/v2 v2.128.0/go.mod h1:iAwqzcYzJtAK5QWGT2uRl9WfRxXyKFBG1AZuhk2NAQg= +github.com/casbin/casbin/v2 v2.132.0 h1:73hGmOszGSL3hTVquwkAi98XLl3gPJ+BxB6D7G9Fxtk= +github.com/casbin/casbin/v2 v2.132.0/go.mod h1:FmcfntdXLTcYXv/hxgNntcRPqAbwOG9xsism0yXT+18= github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= github.com/casbin/govaluate v1.10.0 h1:ffGw51/hYH3w3rZcxO/KcaUIDOLP84w7nsidMVgaDG0= github.com/casbin/govaluate v1.10.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= @@ -126,14 +126,8 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= -github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= github.com/prometheus/common v0.67.2 h1:PcBAckGFTIHt2+L3I33uNRTlKTplNzFctXcWhPyAEN8= github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko= -github.com/prometheus/procfs v0.18.0 h1:2QTA9cKdznfYJz7EDaa7IiJobHuV7E1WzeBwcrhk0ao= -github.com/prometheus/procfs v0.18.0/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= -github.com/prometheus/procfs v0.19.1 h1:QVtROpTkphuXuNlnCv3m1ut3JytkXHtQ3xvck/YmzMM= -github.com/prometheus/procfs v0.19.1/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= @@ -174,8 +168,6 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw= -go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss= go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= @@ -277,10 +269,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc= google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda h1:i/Q+bfisr7gq6feoJnS/DlpdwEL4ihp41fvRiM3Ork0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 h1:tRPGkdGHuewF4UisLzzHHr1spKw92qLM98nIzxbC0wY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A= google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=