package test import ( "RenewCMS/internal/domain/audit" "RenewCMS/internal/domain/author" "RenewCMS/internal/domain/role" "RenewCMS/internal/domain/user" "RenewCMS/internal/infrastructure/useCases" "bytes" "context" "encoding/csv" "errors" "strings" "testing" "time" ) func TestRolesPermissionsEnforcementActivityExportPaging(t *testing.T) { w := newActivityWorld(t) for i := 0; i < 501; i++ { w.seedAt(t, time.Duration(i+1)*time.Second, func(e *audit.Event) { e.Action = "article.edit" }) } w.probe.maxReads = 5 prepared, err := w.export.Prepare(useCases.ExportActivityCommand{Grants: activityViewAllGrants}) if err != nil { t.Fatalf("prepare failed: %v", err) } var out bytes.Buffer if err := prepared.WriteCSV(&out); err != nil { t.Fatalf("write failed: %v", err) } rows, err := csv.NewReader(strings.NewReader(out.String())).ReadAll() if err != nil || len(rows) != 502 { t.Fatalf("expected 502 rows, got %d (%v)", len(rows), err) } if len(w.probe.listCalls) != 2 || w.probe.listCalls[0].Page != 1 || w.probe.listCalls[1].Page != 2 { t.Errorf("expected pages 1 and 2, got %+v", w.probe.listCalls) } } func TestRolesPermissionsEnforcementAuthorLinking(t *testing.T) { t.Run("linking an author to an unknown user is refused", func(t *testing.T) { authors := plainAuthors() users := newMockUserRepo() create := useCases.NewCreateAuthorUseCase(authors, users, newMockImageRepo(), discardRecorder) unknown := uint32(77) _, err := create.Create(context.Background(), useCases.CreateAuthorCommand{Name: "Ghost", Slug: "ghost", UserID: &unknown}) if !errors.Is(err, user.ErrUserNotFound) || len(authors.authors) != 0 { t.Fatalf("expected ErrUserNotFound and no author, got %v (%d)", err, len(authors.authors)) } }) t.Run("linking a user who already has an author is refused", func(t *testing.T) { authors := plainAuthors() authors.seedLinked(1, "Taken", "taken", 5) users := newMockUserRepo() users.users[5] = user.User{ID: 5, Email: "five@example.com"} create := useCases.NewCreateAuthorUseCase(authors, users, newMockImageRepo(), discardRecorder) five := uint32(5) _, err := create.Create(context.Background(), useCases.CreateAuthorCommand{Name: "Second", Slug: "second", UserID: &five}) if !errors.Is(err, author.ErrUserAlreadyLinked) { t.Fatalf("expected ErrUserAlreadyLinked, got %v", err) } }) t.Run("user_email is set only for a linked author whose user exists", func(t *testing.T) { authors := plainAuthors() authors.seed(1, "Unlinked", "unlinked") authors.seedLinked(2, "Linked", "linked", 5) authors.seedLinked(3, "Dangling", "dangling", 99) users := newMockUserRepo() users.users[5] = user.User{ID: 5, Email: "five@example.com"} grants := unlockedGrantSet(role.KeyUsersView + "=all") page, err := useCases.NewListAuthorsUseCase(authors, users).List(useCases.ListAuthorsCommand{Page: 1, Size: 25, Grants: grants}) if err != nil || len(page.Items) != 3 { t.Fatalf("unexpected %v %+v", err, page) } emails := map[uint32]*string{} for _, item := range page.Items { emails[item.ID] = item.UserEmail } if emails[1] != nil || emails[3] != nil { t.Errorf("expected no email for unlinked and dangling, got %v %v", emails[1], emails[3]) } if emails[2] == nil || *emails[2] != "five@example.com" { t.Errorf("expected the linked email, got %v", emails[2]) } }) } func TestRolesPermissionsEnforcementMissingPermissionMessage(t *testing.T) { err := role.MissingPermissionError{Key: "users.invite"} if got := err.Error(); got != role.ErrMissingPermission.Error()+": users.invite" { t.Errorf("unexpected message %q", got) } if !errors.Is(err, role.ErrMissingPermission) || errors.Is(err, role.ErrRoleNotFound) { t.Errorf("unexpected Is behaviour") } }