fix: scope email-account list/detail queries by organization_id instead of the logged-in user_id, so every member of a workspace sees the org's mailboxes (not just the owner who connected them)

This commit is contained in:
Matthew Meszaros
2026-06-11 17:43:56 +02:00
parent 4440613d94
commit 6ae5e52c4e
3 changed files with 18 additions and 14 deletions
+6 -2
View File
@@ -11,14 +11,18 @@ import (
)
func (h *Handler) EmailsSearch(c *gin.Context) {
userID := middleware.GetUserID(c)
orgID := middleware.GetOrganizationID(c)
if orgID == nil {
errx.Handle(c, errx.New(errx.BadRequest, "no organization selected"))
return
}
query := c.Query("q")
cursor := c.Query("cursor")
tag := c.Query("tag")
limit := c.Query("limit")
resp, err := h.EmailService.Search(c.Request.Context(), userID, query, cursor, tag, limit, middleware.GetAPIKeyAllowedEmailAccounts(c))
resp, err := h.EmailService.Search(c.Request.Context(), orgID.String(), query, cursor, tag, limit, middleware.GetAPIKeyAllowedEmailAccounts(c))
if err != nil {
errx.Handle(c, err)
return
+4 -4
View File
@@ -13,7 +13,7 @@ import (
"github.com/warmbly/warmbly/internal/utils/validate"
)
func (s *emailService) Search(ctx context.Context, userID, search, cursor, tag, limit string, allowedAccountIDs []uuid.UUID) (*models.EmailsResult, *errx.Error) {
func (s *emailService) Search(ctx context.Context, orgID, search, cursor, tag, limit string, allowedAccountIDs []uuid.UUID) (*models.EmailsResult, *errx.Error) {
cursorId, err := validate.Uuid(cursor)
if err != nil {
return nil, err
@@ -32,11 +32,11 @@ func (s *emailService) Search(ctx context.Context, userID, search, cursor, tag,
return nil, err
}
return s.emailRepository.Search(ctx, userID, search, cursorId, tagId, limitN, allowedAccountIDs)
return s.emailRepository.Search(ctx, orgID, search, cursorId, tagId, limitN, allowedAccountIDs)
}
func (s *emailService) Get(ctx context.Context, userID, emailAccountID string) (*models.Email, *errx.Error) {
return s.emailRepository.Get(ctx, userID, emailAccountID)
func (s *emailService) Get(ctx context.Context, orgID, emailAccountID string) (*models.Email, *errx.Error) {
return s.emailRepository.Get(ctx, orgID, emailAccountID)
}
func (s *emailService) Update(ctx context.Context, userID, emailAccountID string, udata *models.UpdateEmail) (*models.Email, *errx.Error) {
+8 -8
View File
@@ -403,7 +403,7 @@ func (r *emailRepository) NewSMTPIMAPAccount(ctx context.Context, userID string,
}, nil
}
func (r *emailRepository) Search(ctx context.Context, userID, search string, cursor, tag *string, limit int32, allowedAccountIDs []uuid.UUID) (*models.EmailsResult, *errx.Error) {
func (r *emailRepository) Search(ctx context.Context, orgID, search string, cursor, tag *string, limit int32, allowedAccountIDs []uuid.UUID) (*models.EmailsResult, *errx.Error) {
tx, err := r.DB.Begin(ctx)
if err != nil {
db.CaptureError(err, "", nil, "begin")
@@ -427,7 +427,7 @@ func (r *emailRepository) Search(ctx context.Context, userID, search string, cur
) AS tags
FROM email_accounts ea
LEFT JOIN email_tags eat ON eat.email_id = ea.id
WHERE ea.user_id = $1
WHERE ea.organization_id = $1
AND ($2::uuid IS NULL OR (ea.created_at, ea.id) < (
SELECT created_at, id
FROM email_accounts
@@ -448,7 +448,7 @@ func (r *emailRepository) Search(ctx context.Context, userID, search string, cur
allowedAccountParam = allowedAccountIDs
}
params := []any{
userID,
orgID,
cursor,
"%" + search + "%",
tag,
@@ -495,7 +495,7 @@ func (r *emailRepository) Search(ctx context.Context, userID, search string, cur
SELECT COUNT(DISTINCT ea.id)
FROM email_accounts ea
LEFT JOIN email_tags et ON et.email_id = ea.id
WHERE ea.user_id = $1
WHERE ea.organization_id = $1
AND (ea.name ILIKE $2 OR ea.email ILIKE $2)
AND ($3::uuid IS NULL OR EXISTS (
SELECT 1 FROM email_tags cf WHERE cf.email_id = ea.id AND cf.tag_id = $3
@@ -504,7 +504,7 @@ func (r *emailRepository) Search(ctx context.Context, userID, search string, cur
`
params = []any{
userID,
orgID,
"%" + search + "%",
tag,
allowedAccountParam,
@@ -533,7 +533,7 @@ func (r *emailRepository) Search(ctx context.Context, userID, search string, cur
}, nil
}
func (r *emailRepository) Get(ctx context.Context, userID, emailAccountID string) (*models.Email, *errx.Error) {
func (r *emailRepository) Get(ctx context.Context, orgID, emailAccountID string) (*models.Email, *errx.Error) {
query := `
SELECT
ea.id, ea.email, ea.name, ea.signature_plain, ea.signature_html, ea.signature_sync, ea.signature_code,
@@ -544,12 +544,12 @@ func (r *emailRepository) Get(ctx context.Context, userID, emailAccountID string
COALESCE(array_agg(eat.tag_id) FILTER (WHERE eat.tag_id IS NOT NULL), '{}') AS tags
FROM email_accounts ea
LEFT JOIN email_tags eat ON eat.email_id = ea.id
WHERE ea.user_id = $1 AND ea.id = $2
WHERE ea.organization_id = $1 AND ea.id = $2
GROUP BY ea.id
`
params := []any{
userID,
orgID,
emailAccountID,
}