service backend
This commit is contained in:
32
api/pkg/db/internal/mongo/organizationdb/archived.go
Normal file
32
api/pkg/db/internal/mongo/organizationdb/archived.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package organizationdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// SetArchived sets the archived status of an organization and optionally cascades to projects, tasks, comments, and reactions
|
||||
func (db *OrganizationDB) SetArchived(ctx context.Context, accountRef, organizationRef primitive.ObjectID, archived, cascade bool) error {
|
||||
db.DBImp.Logger.Debug("Setting organization archived status", mzap.ObjRef("organization_ref", organizationRef), zap.Bool("archived", archived), zap.Bool("cascade", cascade))
|
||||
|
||||
// Get the organization first
|
||||
var organization model.Organization
|
||||
if err := db.Get(ctx, accountRef, organizationRef, &organization); err != nil {
|
||||
db.DBImp.Logger.Warn("Error retrieving organization for archival", zap.Error(err), mzap.ObjRef("organization_ref", organizationRef))
|
||||
return err
|
||||
}
|
||||
|
||||
// Update the organization's archived status
|
||||
organization.SetArchived(archived)
|
||||
if err := db.Update(ctx, accountRef, &organization); err != nil {
|
||||
db.DBImp.Logger.Warn("Error updating organization archived status", zap.Error(err), mzap.ObjRef("organization_ref", organizationRef))
|
||||
return err
|
||||
}
|
||||
|
||||
db.DBImp.Logger.Debug("Successfully set organization archived status", mzap.ObjRef("organization_ref", organizationRef), zap.Bool("archived", archived))
|
||||
return nil
|
||||
}
|
||||
23
api/pkg/db/internal/mongo/organizationdb/cascade.go
Normal file
23
api/pkg/db/internal/mongo/organizationdb/cascade.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package organizationdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// DeleteCascade deletes an organization and all its related data (projects, tasks, comments, reactions, statuses)
|
||||
func (db *OrganizationDB) DeleteCascade(ctx context.Context, organizationRef primitive.ObjectID) error {
|
||||
db.DBImp.Logger.Debug("Starting organization deletion with projects", mzap.ObjRef("organization_ref", organizationRef))
|
||||
|
||||
// Delete the organization itself
|
||||
if err := db.Unprotected().Delete(ctx, organizationRef); err != nil {
|
||||
db.DBImp.Logger.Warn("Error deleting organization", zap.Error(err), mzap.ObjRef("organization_ref", organizationRef))
|
||||
return err
|
||||
}
|
||||
|
||||
db.DBImp.Logger.Debug("Successfully deleted organization with projects", mzap.ObjRef("organization_ref", organizationRef))
|
||||
return nil
|
||||
}
|
||||
19
api/pkg/db/internal/mongo/organizationdb/create.go
Normal file
19
api/pkg/db/internal/mongo/organizationdb/create.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package organizationdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
func (db *OrganizationDB) Create(ctx context.Context, _, _ primitive.ObjectID, org *model.Organization) error {
|
||||
if org == nil {
|
||||
return merrors.InvalidArgument("Organization object is nil")
|
||||
}
|
||||
org.SetID(primitive.NewObjectID())
|
||||
// Organizaiton reference must be set to the same value as own organization reference
|
||||
org.SetOrganizationRef(*org.GetID())
|
||||
return db.DBImp.Create(ctx, org)
|
||||
}
|
||||
34
api/pkg/db/internal/mongo/organizationdb/db.go
Normal file
34
api/pkg/db/internal/mongo/organizationdb/db.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package organizationdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/auth"
|
||||
"github.com/tech/sendico/pkg/db/policy"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
)
|
||||
|
||||
type OrganizationDB struct {
|
||||
auth.ProtectedDBImp[*model.Organization]
|
||||
}
|
||||
|
||||
func Create(ctx context.Context,
|
||||
logger mlogger.Logger,
|
||||
enforcer auth.Enforcer,
|
||||
pdb policy.DB,
|
||||
db *mongo.Database,
|
||||
) (*OrganizationDB, error) {
|
||||
p, err := auth.CreateDBImp[*model.Organization](ctx, logger, pdb, enforcer, mservice.Organizations, db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := &OrganizationDB{
|
||||
ProtectedDBImp: *p,
|
||||
}
|
||||
p.DBImp.SetDeleter(res.DeleteCascade)
|
||||
return res, nil
|
||||
}
|
||||
12
api/pkg/db/internal/mongo/organizationdb/get.go
Normal file
12
api/pkg/db/internal/mongo/organizationdb/get.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package organizationdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
func (db *OrganizationDB) GetByRef(ctx context.Context, organizationRef primitive.ObjectID, org *model.Organization) error {
|
||||
return db.Unprotected().Get(ctx, organizationRef, org)
|
||||
}
|
||||
16
api/pkg/db/internal/mongo/organizationdb/list.go
Normal file
16
api/pkg/db/internal/mongo/organizationdb/list.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package organizationdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/db/repository"
|
||||
"github.com/tech/sendico/pkg/db/repository/builder"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
mutil "github.com/tech/sendico/pkg/mutil/db"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
func (db *OrganizationDB) List(ctx context.Context, accountRef primitive.ObjectID, cursor *model.ViewCursor) ([]model.Organization, error) {
|
||||
filter := repository.Query().Comparison(repository.Field("members"), builder.Eq, accountRef)
|
||||
return mutil.GetObjects[model.Organization](ctx, db.DBImp.Logger, filter, cursor, db.DBImp.Repository)
|
||||
}
|
||||
14
api/pkg/db/internal/mongo/organizationdb/owned.go
Normal file
14
api/pkg/db/internal/mongo/organizationdb/owned.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package organizationdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/db/repository"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
mutil "github.com/tech/sendico/pkg/mutil/db"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
func (db *OrganizationDB) ListOwned(ctx context.Context, accountRef primitive.ObjectID) ([]model.Organization, error) {
|
||||
return mutil.GetObjects[model.Organization](ctx, db.DBImp.Logger, repository.Filter("ownerRef", accountRef), nil, db.DBImp.Repository)
|
||||
}
|
||||
562
api/pkg/db/internal/mongo/organizationdb/setarchived_test.go
Normal file
562
api/pkg/db/internal/mongo/organizationdb/setarchived_test.go
Normal file
@@ -0,0 +1,562 @@
|
||||
//go:build integration
|
||||
// +build integration
|
||||
|
||||
package organizationdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"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/tech/sendico/pkg/db/repository/builder"
|
||||
"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()) {
|
||||
ctx := context.Background()
|
||||
|
||||
// Start MongoDB container
|
||||
mongodbContainer, err := mongodb.Run(ctx, "mongo:latest")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get connection string
|
||||
endpoint, err := mongodbContainer.Endpoint(ctx, "")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Connect to MongoDB
|
||||
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://"+endpoint))
|
||||
require.NoError(t, err)
|
||||
|
||||
db := client.Database("test_organization_setarchived")
|
||||
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,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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 {
|
||||
result[*obj.GetID()] = true
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (m *mockSetArchivedEnforcer) GetRoles(ctx context.Context, accountRef, organizationRef primitive.ObjectID) ([]model.Role, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *mockSetArchivedEnforcer) GetPermissions(ctx context.Context, accountRef, organizationRef primitive.ObjectID) ([]model.Role, []model.Permission, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
type mockSetArchivedPolicyDB struct{}
|
||||
|
||||
func (m *mockSetArchivedPolicyDB) Create(ctx context.Context, policy *model.PolicyDescription) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockSetArchivedPolicyDB) Get(ctx context.Context, policyRef primitive.ObjectID, result *model.PolicyDescription) error {
|
||||
return merrors.ErrNoData
|
||||
}
|
||||
|
||||
func (m *mockSetArchivedPolicyDB) InsertMany(ctx context.Context, objects []*model.PolicyDescription) error { return nil }
|
||||
|
||||
func (m *mockSetArchivedPolicyDB) Update(ctx context.Context, policy *model.PolicyDescription) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockSetArchivedPolicyDB) Patch(ctx context.Context, objectRef primitive.ObjectID, patch builder.Patch) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockSetArchivedPolicyDB) Delete(ctx context.Context, policyRef primitive.ObjectID) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockSetArchivedPolicyDB) DeleteMany(ctx context.Context, filter builder.Query) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
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",
|
||||
},
|
||||
}
|
||||
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))
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user