From ec77a3e3d254bc0a0e24bb62e58fbd65a4bb6918 Mon Sep 17 00:00:00 2001 From: Matthew Meszaros Date: Sun, 4 Oct 2026 03:07:37 -0700 Subject: [PATCH] feat: key unibox snoozes by organization as well as user and thread (migration 000259 backfills from each thread's mailbox organization), scope every snooze read and write and the org-transfer scope to it, and resolve unibox list cursors only within the caller's organization or user --- internal/api/handler/unibox.go | 21 ++++++- internal/app/aitools/tools_inbox.go | 4 +- internal/app/orgtransfer/spec.go | 3 +- internal/app/unibox/service.go | 6 +- internal/app/unibox/snooze.go | 12 ++-- ...00259_unibox_snoozes_organization.down.sql | 12 ++++ .../000259_unibox_snoozes_organization.up.sql | 23 +++++++ internal/repository/pg_unibox.go | 60 ++++++++++--------- .../unibox_notification_live_test.go | 2 +- internal/repository/unibox_scope_live_test.go | 8 +-- 10 files changed, 101 insertions(+), 50 deletions(-) create mode 100644 internal/infrastructure/db/migrations/000259_unibox_snoozes_organization.down.sql create mode 100644 internal/infrastructure/db/migrations/000259_unibox_snoozes_organization.up.sql diff --git a/internal/api/handler/unibox.go b/internal/api/handler/unibox.go index 3b95df260..73ebd5b01 100644 --- a/internal/api/handler/unibox.go +++ b/internal/api/handler/unibox.go @@ -688,8 +688,13 @@ func (h *Handler) CreateUniboxSnooze(c *gin.Context) { return } + orgID := middleware.GetOrganizationID(c) + if orgID == nil { + errx.Handle(c, errx.ErrNoOrganization) + return + } threads := req.threads() - rows, xerr := h.UniboxService.Snooze(c.Request.Context(), uid, threads, req.SnoozedUntil) + rows, xerr := h.UniboxService.Snooze(c.Request.Context(), *orgID, uid, threads, req.SnoozedUntil) if xerr != nil { errx.Handle(c, xerr) return @@ -734,7 +739,12 @@ func (h *Handler) DeleteUniboxSnooze(c *gin.Context) { return } - if xerr := h.UniboxService.Unsnooze(c.Request.Context(), uid, threads); xerr != nil { + orgID := middleware.GetOrganizationID(c) + if orgID == nil { + errx.Handle(c, errx.ErrNoOrganization) + return + } + if xerr := h.UniboxService.Unsnooze(c.Request.Context(), *orgID, uid, threads); xerr != nil { errx.Handle(c, xerr) return } @@ -827,7 +837,12 @@ func (h *Handler) ListUniboxSnoozes(c *gin.Context) { return } - resp, xerr := h.UniboxService.ListSnoozes(c.Request.Context(), uid) + orgID := middleware.GetOrganizationID(c) + if orgID == nil { + errx.Handle(c, errx.ErrNoOrganization) + return + } + resp, xerr := h.UniboxService.ListSnoozes(c.Request.Context(), *orgID, uid) if xerr != nil { errx.Handle(c, xerr) return diff --git a/internal/app/aitools/tools_inbox.go b/internal/app/aitools/tools_inbox.go index df4a9feae..8d12dac0d 100644 --- a/internal/app/aitools/tools_inbox.go +++ b/internal/app/aitools/tools_inbox.go @@ -175,7 +175,7 @@ func (d Deps) snoozeThread(ctx context.Context, inv Invocation, args json.RawMes if perr != nil { return "", ErrInvalidArgs } - snooze, xerr := d.Unibox.Snooze(ctx, inv.UserID, []string{in.ThreadID}, until) + snooze, xerr := d.Unibox.Snooze(ctx, inv.OrgID, inv.UserID, []string{in.ThreadID}, until) if xerr != nil { return "", fromErrx(xerr) } @@ -196,7 +196,7 @@ func (d Deps) unsnoozeThread(ctx context.Context, inv Invocation, args json.RawM if in.ThreadID == "" { return "", ErrInvalidArgs } - if xerr := d.Unibox.Unsnooze(ctx, inv.UserID, []string{in.ThreadID}); xerr != nil { + if xerr := d.Unibox.Unsnooze(ctx, inv.OrgID, inv.UserID, []string{in.ThreadID}); xerr != nil { return "", fromErrx(xerr) } d.logAudit(ctx, inv, models.AuditActionUpdate, models.AuditEntityUnibox, nil, nil) diff --git a/internal/app/orgtransfer/spec.go b/internal/app/orgtransfer/spec.go index d01aefde5..aef946cde 100644 --- a/internal/app/orgtransfer/spec.go +++ b/internal/app/orgtransfer/spec.go @@ -105,7 +105,6 @@ const ( orgCampaigns = `(SELECT id FROM campaigns WHERE organization_id = $1)` orgContacts = `(SELECT id FROM contacts WHERE organization_id = $1)` orgTasks = `(SELECT id FROM tasks WHERE email_account_id IN ` + orgMailboxes + ` AND task_type <> 'placement')` - orgThreads = `(SELECT DISTINCT thread_id FROM unibox_emails WHERE email_id IN ` + orgMailboxes + `)` orgPipelines = `(SELECT id FROM pipelines WHERE organization_id = $1)` orgInvitations = `(SELECT id FROM organization_invitations WHERE organization_id = $1)` orgTeams = `(SELECT id FROM teams WHERE organization_id = $1)` @@ -713,7 +712,7 @@ var Tables = []Table{ }, { Name: "unibox_snoozes", Group: models.OrgDataGroupInbox, - Scope: `thread_id IN ` + orgThreads, + Scope: scopeOrg, }, { Name: "inbox_tag_results", Group: models.OrgDataGroupInbox, diff --git a/internal/app/unibox/service.go b/internal/app/unibox/service.go index 2f8afefed..a7179608b 100644 --- a/internal/app/unibox/service.go +++ b/internal/app/unibox/service.go @@ -52,9 +52,9 @@ type UniboxService interface { // Snooze hides conversations until `until`. Unsnooze drops the rows. Both // take a set so the list's selection bar is one call, not one per row. - Snooze(ctx context.Context, userID uuid.UUID, threadIDs []string, until time.Time) ([]models.UniboxSnooze, *errx.Error) - Unsnooze(ctx context.Context, userID uuid.UUID, threadIDs []string) *errx.Error - ListSnoozes(ctx context.Context, userID uuid.UUID) ([]models.UniboxSnooze, *errx.Error) + Snooze(ctx context.Context, orgID, userID uuid.UUID, threadIDs []string, until time.Time) ([]models.UniboxSnooze, *errx.Error) + Unsnooze(ctx context.Context, orgID, userID uuid.UUID, threadIDs []string) *errx.Error + ListSnoozes(ctx context.Context, orgID, userID uuid.UUID) ([]models.UniboxSnooze, *errx.Error) // Overview powers the scope rail + top metric strip in one call. Overview(ctx context.Context, orgID, userID uuid.UUID) (*models.UniboxOverview, *errx.Error) diff --git a/internal/app/unibox/snooze.go b/internal/app/unibox/snooze.go index 1740190fc..ff8c34261 100644 --- a/internal/app/unibox/snooze.go +++ b/internal/app/unibox/snooze.go @@ -13,7 +13,7 @@ import ( // Snooze takes a set of conversations so the list's selection bar is one call. // A single thread is the one-element case. -func (s *uniboxService) Snooze(ctx context.Context, userID uuid.UUID, threadIDs []string, until time.Time) ([]models.UniboxSnooze, *errx.Error) { +func (s *uniboxService) Snooze(ctx context.Context, orgID, userID uuid.UUID, threadIDs []string, until time.Time) ([]models.UniboxSnooze, *errx.Error) { threadIDs = nonEmpty(threadIDs) if len(threadIDs) == 0 { return nil, errx.New(errx.BadRequest, "thread_id is required") @@ -32,7 +32,7 @@ func (s *uniboxService) Snooze(ctx context.Context, userID uuid.UUID, threadIDs return nil, errx.New(errx.BadRequest, "snoozed_until is too far in the future (max 90 days)") } - rows, err := s.uniboxRepository.UpsertSnoozes(ctx, userID, threadIDs, until.UTC()) + rows, err := s.uniboxRepository.UpsertSnoozes(ctx, orgID, userID, threadIDs, until.UTC()) if err != nil { errs.CaptureException(err) return nil, errx.InternalError() @@ -40,7 +40,7 @@ func (s *uniboxService) Snooze(ctx context.Context, userID uuid.UUID, threadIDs return rows, nil } -func (s *uniboxService) Unsnooze(ctx context.Context, userID uuid.UUID, threadIDs []string) *errx.Error { +func (s *uniboxService) Unsnooze(ctx context.Context, orgID, userID uuid.UUID, threadIDs []string) *errx.Error { threadIDs = nonEmpty(threadIDs) if len(threadIDs) == 0 { return errx.New(errx.BadRequest, "thread_id is required") @@ -48,7 +48,7 @@ func (s *uniboxService) Unsnooze(ctx context.Context, userID uuid.UUID, threadID if len(threadIDs) > SnoozeMaxThreads { return errx.ErrSeenMax } - if err := s.uniboxRepository.DeleteSnoozes(ctx, userID, threadIDs); err != nil { + if err := s.uniboxRepository.DeleteSnoozes(ctx, orgID, userID, threadIDs); err != nil { errs.CaptureException(err) return errx.InternalError() } @@ -67,8 +67,8 @@ func nonEmpty(in []string) []string { return out } -func (s *uniboxService) ListSnoozes(ctx context.Context, userID uuid.UUID) ([]models.UniboxSnooze, *errx.Error) { - rows, err := s.uniboxRepository.ListSnoozes(ctx, userID) +func (s *uniboxService) ListSnoozes(ctx context.Context, orgID, userID uuid.UUID) ([]models.UniboxSnooze, *errx.Error) { + rows, err := s.uniboxRepository.ListSnoozes(ctx, orgID, userID) if err != nil { errs.CaptureException(err) return nil, errx.InternalError() diff --git a/internal/infrastructure/db/migrations/000259_unibox_snoozes_organization.down.sql b/internal/infrastructure/db/migrations/000259_unibox_snoozes_organization.down.sql new file mode 100644 index 000000000..1805dd565 --- /dev/null +++ b/internal/infrastructure/db/migrations/000259_unibox_snoozes_organization.down.sql @@ -0,0 +1,12 @@ +ALTER TABLE public.unibox_snoozes DROP CONSTRAINT IF EXISTS unibox_snoozes_org_user_thread_key; + +-- Keep the latest snooze per (user, thread) so the old key can return. +DELETE FROM public.unibox_snoozes s +USING public.unibox_snoozes newer +WHERE s.user_id = newer.user_id AND s.thread_id = newer.thread_id + AND (s.snoozed_until, s.id) < (newer.snoozed_until, newer.id); + +ALTER TABLE public.unibox_snoozes + ADD CONSTRAINT unibox_snoozes_user_id_thread_id_key UNIQUE (user_id, thread_id); + +ALTER TABLE public.unibox_snoozes DROP COLUMN organization_id; diff --git a/internal/infrastructure/db/migrations/000259_unibox_snoozes_organization.up.sql b/internal/infrastructure/db/migrations/000259_unibox_snoozes_organization.up.sql new file mode 100644 index 000000000..ab9772519 --- /dev/null +++ b/internal/infrastructure/db/migrations/000259_unibox_snoozes_organization.up.sql @@ -0,0 +1,23 @@ +-- A snooze belongs to the organization whose inbox it hides a thread in. +ALTER TABLE public.unibox_snoozes + ADD COLUMN organization_id uuid REFERENCES public.organizations (id) ON DELETE CASCADE; + +ALTER TABLE public.unibox_snoozes DROP CONSTRAINT unibox_snoozes_user_id_thread_id_key; + +DELETE FROM public.unibox_snoozes WHERE snoozed_until <= now(); + +-- One row per organization the thread's mail sits in, read the way the inbox +-- matches a snooze (the mail's user and thread). +INSERT INTO public.unibox_snoozes (user_id, thread_id, snoozed_until, created_at, updated_at, organization_id) +SELECT DISTINCT s.user_id, s.thread_id, s.snoozed_until, s.created_at, s.updated_at, ea.organization_id +FROM public.unibox_snoozes s +JOIN public.unibox_emails ue ON ue.user_id = s.user_id AND ue.thread_id = s.thread_id +JOIN public.email_accounts ea ON ea.id = ue.email_id +WHERE s.organization_id IS NULL AND ea.organization_id IS NOT NULL; + +DELETE FROM public.unibox_snoozes WHERE organization_id IS NULL; + +ALTER TABLE public.unibox_snoozes ALTER COLUMN organization_id SET NOT NULL; + +ALTER TABLE public.unibox_snoozes + ADD CONSTRAINT unibox_snoozes_org_user_thread_key UNIQUE (organization_id, user_id, thread_id); diff --git a/internal/repository/pg_unibox.go b/internal/repository/pg_unibox.go index 66d728f38..9d0b6fd02 100644 --- a/internal/repository/pg_unibox.go +++ b/internal/repository/pg_unibox.go @@ -96,15 +96,15 @@ type UniboxRepository interface { ProcessPendingWarmupVerification(ctx context.Context, id uuid.UUID, process func(*models.JobEventNewEmail) error) error UpdatePendingEmail(ctx context.Context, userID, id uuid.UUID, update func(*models.EmailMessageStoreData)) (bool, error) - // Snooze: per (user, thread). UpsertSnooze adopts the new + // Snooze: per (organization, user, thread). UpsertSnooze adopts the new // snoozed_until even if one already exists; DeleteSnooze removes // the row outright (instant un-snooze). ListSnoozes returns the // active set for the user. // The bulk forms back the conversation list's selection bar, so filing a // screenful of mail is one round trip rather than one per row. - UpsertSnoozes(ctx context.Context, userID uuid.UUID, threadIDs []string, until time.Time) ([]models.UniboxSnooze, error) - DeleteSnoozes(ctx context.Context, userID uuid.UUID, threadIDs []string) error - ListSnoozes(ctx context.Context, userID uuid.UUID) ([]models.UniboxSnooze, error) + UpsertSnoozes(ctx context.Context, orgID, userID uuid.UUID, threadIDs []string, until time.Time) ([]models.UniboxSnooze, error) + DeleteSnoozes(ctx context.Context, orgID, userID uuid.UUID, threadIDs []string) error + ListSnoozes(ctx context.Context, orgID, userID uuid.UUID) ([]models.UniboxSnooze, error) // Overview powers the scope rail + top metric strip. Single call // so the client doesn't fan out N+M queries for each mailbox/tag. @@ -356,7 +356,7 @@ func (r *uniboxRepository) GetIncoming(ctx context.Context, userID uuid.UUID, li if err == nil { query += fmt.Sprintf(` AND (internal_date, id) < ( - SELECT internal_date, id FROM unibox_emails WHERE id = $%d + SELECT internal_date, id FROM unibox_emails WHERE id = $%d AND user_id = $1 )`, argPos) args = append(args, cursorID) argPos++ @@ -471,7 +471,8 @@ func (r *uniboxRepository) GetByThread(ctx context.Context, orgID, emailID uuid. if err == nil { query += fmt.Sprintf(` AND (internal_date, id) > ( - SELECT internal_date, id FROM unibox_emails WHERE id = $%d + SELECT internal_date, id FROM unibox_emails + WHERE id = $%d AND email_id IN (SELECT id FROM email_accounts WHERE organization_id = $1) )`, argPos) args = append(args, cursorID) argPos++ @@ -564,7 +565,7 @@ func (r *uniboxRepository) GetBySender(ctx context.Context, userID uuid.UUID, se if err == nil { query += fmt.Sprintf(` AND (internal_date, id) < ( - SELECT internal_date, id FROM unibox_emails WHERE id = $%d + SELECT internal_date, id FROM unibox_emails WHERE id = $%d AND user_id = $1 )`, argPos) args = append(args, cursorID) argPos++ @@ -634,7 +635,7 @@ func (r *uniboxRepository) Search(ctx context.Context, orgID uuid.UUID, params * inner += ` AND NOT EXISTS ( SELECT 1 FROM unibox_snoozes s - WHERE s.user_id = ue.user_id + WHERE s.organization_id = $1 AND s.user_id = ue.user_id AND s.thread_id = ue.thread_id AND s.snoozed_until > NOW() )` @@ -642,7 +643,7 @@ func (r *uniboxRepository) Search(ctx context.Context, orgID uuid.UUID, params * inner += ` AND EXISTS ( SELECT 1 FROM unibox_snoozes s - WHERE s.user_id = ue.user_id + WHERE s.organization_id = $1 AND s.user_id = ue.user_id AND s.thread_id = ue.thread_id AND s.snoozed_until > NOW() )` @@ -825,7 +826,8 @@ func (r *uniboxRepository) Search(ctx context.Context, orgID uuid.UUID, params * if err == nil { query += fmt.Sprintf(` AND (b.internal_date, b.id) < ( - SELECT internal_date, id FROM unibox_emails WHERE id = $%d + SELECT internal_date, id FROM unibox_emails + WHERE id = $%d AND email_id IN (SELECT id FROM email_accounts WHERE organization_id = $1) )`, argPos) args = append(args, cursorID) argPos++ @@ -848,7 +850,7 @@ func (r *uniboxRepository) GetUnseenCount(ctx context.Context, orgID uuid.UUID, AND ue.folder = '` + models.FolderInbox + `' AND NOT EXISTS ( SELECT 1 FROM unibox_snoozes s - WHERE s.user_id = ue.user_id + WHERE s.organization_id = $1 AND s.user_id = ue.user_id AND s.thread_id = ue.thread_id AND s.snoozed_until > NOW() ) @@ -1431,18 +1433,18 @@ func (r *uniboxRepository) LatestMessageIDInThread(ctx context.Context, orgID uu // ── Snoozes ──────────────────────────────────────────────────────────── -func (r *uniboxRepository) UpsertSnoozes(ctx context.Context, userID uuid.UUID, threadIDs []string, until time.Time) ([]models.UniboxSnooze, error) { +func (r *uniboxRepository) UpsertSnoozes(ctx context.Context, orgID, userID uuid.UUID, threadIDs []string, until time.Time) ([]models.UniboxSnooze, error) { if len(threadIDs) == 0 { return nil, errors.New("threadIDs required") } rows, err := r.db.Query(ctx, ` - INSERT INTO unibox_snoozes (user_id, thread_id, snoozed_until, created_at, updated_at) - SELECT $1, t, $3, NOW(), NOW() FROM unnest($2::text[]) AS t - ON CONFLICT (user_id, thread_id) DO UPDATE SET + INSERT INTO unibox_snoozes (organization_id, user_id, thread_id, snoozed_until, created_at, updated_at) + SELECT $4, $1, t, $3, NOW(), NOW() FROM unnest($2::text[]) AS t + ON CONFLICT (organization_id, user_id, thread_id) DO UPDATE SET snoozed_until = EXCLUDED.snoozed_until, updated_at = NOW() RETURNING id, user_id, thread_id, snoozed_until, created_at, updated_at - `, userID, threadIDs, until) + `, userID, threadIDs, until, orgID) if err != nil { return nil, err } @@ -1459,24 +1461,24 @@ func (r *uniboxRepository) UpsertSnoozes(ctx context.Context, userID uuid.UUID, return out, rows.Err() } -func (r *uniboxRepository) DeleteSnoozes(ctx context.Context, userID uuid.UUID, threadIDs []string) error { +func (r *uniboxRepository) DeleteSnoozes(ctx context.Context, orgID, userID uuid.UUID, threadIDs []string) error { if len(threadIDs) == 0 { return nil } _, err := r.db.Exec(ctx, - `DELETE FROM unibox_snoozes WHERE user_id = $1 AND thread_id = ANY($2)`, - userID, threadIDs, + `DELETE FROM unibox_snoozes WHERE organization_id = $3 AND user_id = $1 AND thread_id = ANY($2)`, + userID, threadIDs, orgID, ) return err } -func (r *uniboxRepository) ListSnoozes(ctx context.Context, userID uuid.UUID) ([]models.UniboxSnooze, error) { +func (r *uniboxRepository) ListSnoozes(ctx context.Context, orgID, userID uuid.UUID) ([]models.UniboxSnooze, error) { rows, err := r.db.Query(ctx, ` SELECT id, user_id, thread_id, snoozed_until, created_at, updated_at FROM unibox_snoozes - WHERE user_id = $1 AND snoozed_until > NOW() + WHERE organization_id = $2 AND user_id = $1 AND snoozed_until > NOW() ORDER BY snoozed_until ASC - `, userID) + `, userID, orgID) if err != nil { return nil, err } @@ -1532,7 +1534,7 @@ func (r *uniboxRepository) Overview(ctx context.Context, orgID uuid.UUID) (*mode e.folder = 'archive' AS is_archived, EXISTS ( SELECT 1 FROM unibox_snoozes s - WHERE s.user_id = e.user_id + WHERE s.organization_id = $1 AND s.user_id = e.user_id AND s.thread_id = e.thread_id AND s.snoozed_until > NOW() ) AS is_snoozed @@ -1599,7 +1601,7 @@ func (r *uniboxRepository) Overview(ctx context.Context, orgID uuid.UUID) (*mode WHERE e.email_id IN (SELECT id FROM email_accounts WHERE organization_id = $1) AND NOT EXISTS ( SELECT 1 FROM unibox_snoozes s - WHERE s.user_id = e.user_id + WHERE s.organization_id = $1 AND s.user_id = e.user_id AND s.thread_id = e.thread_id AND s.snoozed_until > NOW() ) @@ -1636,12 +1638,12 @@ func (r *uniboxRepository) Overview(ctx context.Context, orgID uuid.UUID) (*mode COUNT(DISTINCT COALESCE(NULLIF(ue.thread_id, ''), ue.id::text)) FILTER (WHERE ue.id IS NOT NULL AND NOT ue.seen AND NOT EXISTS ( SELECT 1 FROM unibox_snoozes s - WHERE s.user_id = ea.user_id AND s.thread_id = ue.thread_id AND s.snoozed_until > NOW() + WHERE s.organization_id = $1 AND s.user_id = ea.user_id AND s.thread_id = ue.thread_id AND s.snoozed_until > NOW() )) AS unread, COUNT(DISTINCT COALESCE(NULLIF(ue.thread_id, ''), ue.id::text)) FILTER (WHERE ue.id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM unibox_snoozes s - WHERE s.user_id = ea.user_id AND s.thread_id = ue.thread_id AND s.snoozed_until > NOW() + WHERE s.organization_id = $1 AND s.user_id = ea.user_id AND s.thread_id = ue.thread_id AND s.snoozed_until > NOW() )) AS total FROM email_accounts ea LEFT JOIN unibox_emails ue ON ue.email_id = ea.id AND ue.user_id = ea.user_id @@ -1678,12 +1680,12 @@ func (r *uniboxRepository) Overview(ctx context.Context, orgID uuid.UUID) (*mode COUNT(DISTINCT COALESCE(NULLIF(ue.thread_id, ''), ue.id::text)) FILTER (WHERE ue.id IS NOT NULL AND NOT ue.seen AND NOT EXISTS ( SELECT 1 FROM unibox_snoozes s - WHERE s.user_id = ue.user_id AND s.thread_id = ue.thread_id AND s.snoozed_until > NOW() + WHERE s.organization_id = $1 AND s.user_id = ue.user_id AND s.thread_id = ue.thread_id AND s.snoozed_until > NOW() )) AS unread, COUNT(DISTINCT COALESCE(NULLIF(ue.thread_id, ''), ue.id::text)) FILTER (WHERE ue.id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM unibox_snoozes s - WHERE s.user_id = ue.user_id AND s.thread_id = ue.thread_id AND s.snoozed_until > NOW() + WHERE s.organization_id = $1 AND s.user_id = ue.user_id AND s.thread_id = ue.thread_id AND s.snoozed_until > NOW() )) AS total FROM tags t LEFT JOIN email_tags et ON et.tag_id = t.id @@ -1726,7 +1728,7 @@ func (r *uniboxRepository) Overview(ctx context.Context, orgID uuid.UUID) (*mode AND e.folder NOT IN `+foldersOutsideWorkingViews+` AND NOT EXISTS ( SELECT 1 FROM unibox_snoozes s - WHERE s.user_id = e.user_id AND s.thread_id = e.thread_id AND s.snoozed_until > NOW() + WHERE s.organization_id = $1 AND s.user_id = e.user_id AND s.thread_id = e.thread_id AND s.snoozed_until > NOW() ) GROUP BY e.thread_id ) diff --git a/internal/repository/unibox_notification_live_test.go b/internal/repository/unibox_notification_live_test.go index 42a672f66..dfc7ea06d 100644 --- a/internal/repository/unibox_notification_live_test.go +++ b/internal/repository/unibox_notification_live_test.go @@ -30,7 +30,7 @@ func TestLiveUniboxNotificationBadgeCountsOnlyWhatInboxLists(t *testing.T) { f.scopedMessage(t, repo, "thread-sent", "them@example.com", models.FolderSent, now) f.scopedMessage(t, repo, "thread-draft", "them@example.com", models.FolderDrafts, now) f.scopedMessage(t, repo, "thread-snoozed", "them@example.com", models.FolderInbox, now) - if _, err := repo.UpsertSnoozes(ctx, f.user, []string{"thread-snoozed"}, now.Add(24*time.Hour)); err != nil { + if _, err := repo.UpsertSnoozes(ctx, f.org, f.user, []string{"thread-snoozed"}, now.Add(24*time.Hour)); err != nil { t.Fatalf("UpsertSnoozes: %v", err) } diff --git a/internal/repository/unibox_scope_live_test.go b/internal/repository/unibox_scope_live_test.go index e63e2a3c4..3b47ec54e 100644 --- a/internal/repository/unibox_scope_live_test.go +++ b/internal/repository/unibox_scope_live_test.go @@ -304,10 +304,10 @@ func TestLiveUniboxScopeSnoozeTakesASet(t *testing.T) { f.scopedMessage(t, repo, "thread-a", "them@example.com", models.FolderInbox, now) f.scopedMessage(t, repo, "thread-b", "them@example.com", models.FolderInbox, now) t.Cleanup(func() { - _ = repo.DeleteSnoozes(context.Background(), f.user, []string{"thread-a", "thread-b"}) + _ = repo.DeleteSnoozes(context.Background(), f.org, f.user, []string{"thread-a", "thread-b"}) }) - rows, err := repo.UpsertSnoozes(ctx, f.user, []string{"thread-a", "thread-b"}, now.Add(time.Hour)) + rows, err := repo.UpsertSnoozes(ctx, f.org, f.user, []string{"thread-a", "thread-b"}, now.Add(time.Hour)) if err != nil { t.Fatalf("UpsertSnoozes: %v", err) } @@ -324,11 +324,11 @@ func TestLiveUniboxScopeSnoozeTakesASet(t *testing.T) { } // A second pass over the same set moves the time instead of erroring. - if _, err := repo.UpsertSnoozes(ctx, f.user, []string{"thread-a", "thread-b"}, now.Add(2*time.Hour)); err != nil { + if _, err := repo.UpsertSnoozes(ctx, f.org, f.user, []string{"thread-a", "thread-b"}, now.Add(2*time.Hour)); err != nil { t.Fatalf("UpsertSnoozes again: %v", err) } - if err := repo.DeleteSnoozes(ctx, f.user, []string{"thread-a", "thread-b"}); err != nil { + if err := repo.DeleteSnoozes(ctx, f.org, f.user, []string{"thread-a", "thread-b"}); err != nil { t.Fatalf("DeleteSnoozes: %v", err) } back, err := repo.Search(ctx, f.org, &models.MailSearchParams{PageSize: 50})