Commit graph

73 commits

Author SHA1 Message Date
Harshil Sharma
6a76833148 Added tracking 2026-05-26 07:56:05 +05:30
Harshil Sharma
6b7d9ec905 Renamed storage 2026-05-26 06:52:32 +05:30
Harshil Sharma
4ff072e4e0 WIP 2026-05-25 11:31:44 +05:30
David Krauser
e8632bd456
[MM-68777] Add admin property field permission level (#36558) 2026-05-22 11:01:41 -04:00
Ben Schumacher
209606f15b
MM-68419: Add expires_at to PAT data model and enforce expiry at token validation (#36243)
* Add expires_at to PAT data model and enforce expiry at token validation

Adds an ExpiresAt field (int64 millis, 0 = never expires) to the
UserAccessToken model and DB table, enforces expiry when a PAT is used
to create a session, clamps the resulting session's ExpiresAt to the
token's expiry so cached sessions also honor it, ships a background job
(cleanup_expired_access_tokens) that periodically deletes expired
tokens along with any sessions minted from them, and emits audit events
for rejected and reaped expired tokens.

Refs: MM-68419

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Fix govet shadow warnings in DeleteExpired

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Stabilize expired PAT test by persisting an already-expired token

The previous variant created a live token, used it to mint a session,
then backdated the row and revoked the cached session to force a
re-validation. That flow was race-prone under parallel test execution
and was flagged as flaky in CI. Replace it with a direct store write
that persists the PAT with ExpiresAt already in the past, so
createSessionForUserAccessToken is exercised deterministically on the
first HTTP call and no session cache races are possible.

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Address PR review: batched cleanup, consistent filters, audit ordering

- server.go: initialize s.Audit before initJobs() so the cleanup worker
  never captures a nil audit logger.

- Replace DeleteExpired(cutoff) with DeleteByIds([]string) on
  UserAccessTokenStore. The worker now fetches a batch via
  GetExpiredBefore, emits one audit record per token, then deletes
  exactly that batch by id — guaranteeing 1:1 audit/delete pairing
  and eliminating the IsActive-filter mismatch between reads and
  deletes. The worker loops up to maxBatches (=1000) x batchLimit
  (=1000) rows per run and stops when GetExpiredBefore returns less
  than batchLimit or zero rows.

- GetExpiredBefore now selects an explicit column set that omits the
  secret Token column, so the PAT secret never travels from DB to app.

- DeleteByIds surfaces an error from RowsAffected instead of silently
  returning 0.

- Remove dead job.Data initialization in the worker.

- api4 test: set IsActive: true explicitly, walk the AppError chain
  and assert the specific Id app.user_access_token.expired so future
  401 regressions are caught.

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Use named returns in DeleteByIds and clean up expired fixture in test

- DeleteByIds now declares (deleted int64, err error) and uses bare
  returns on every error path so finalizeTransactionX can append a
  rollback failure to the returned error via merror.Append. Previously
  early returns short-circuited the deferred rollback's error
  contribution.
- Add the expired token to the test cleanup so all three fixtures are
  removed even on early test exit.

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Guard GetExpiredBefore against non-positive limit + tighten store test

- GetExpiredBefore now short-circuits when limit <= 0 and returns an
  empty slice without hitting the DB. This prevents the int -> uint64
  cast on a negative value from wrapping into an effectively unbounded
  query.
- Store test now asserts row.Token is empty for every row returned by
  GetExpiredBefore (not just the matched one) to catch any future
  query change that accidentally re-introduces the secret column.
- Added store-level coverage for the limit=0 and limit<0 short-circuit
  contract.

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Add session-clamping and worker tests; bump migration to 172

Address PR test-coverage analysis (issuecomment-4336010565):

- api4/user_test.go: add two subtests covering session.ExpiresAt
  behavior — clamped to token.ExpiresAt when the PAT has a non-zero
  ExpiresAt, and untouched (long-lived) when the PAT has no expiry.
- cleanup_expired_access_tokens/worker.go: extract the batching/audit/
  error orchestration into a package-private cleanupExpired() taking
  small interfaces (expiredTokenStore, auditRecorder) so it can be
  unit-tested without spinning up a job server.
- cleanup_expired_access_tokens/worker_test.go (new): seven unit tests
  cover happy path, empty result, full-batch -> next iteration,
  maxIter cap, GetExpiredBefore error propagation, DeleteByIds error
  propagation, and nil auditLogger guard.
- Bump migration 000170_add_expiresat_to_user_access_tokens to 000172
  to slot in behind the master-side 000170 (property_groups_version)
  and 000171 (drop_property_fields_protected_index).

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Fix PAT expiry audit ordering and cleanup scheduler gate

- Move IsExpired() check after EnableUserAccessTokens gate in
  createSessionForUserAccessToken so the AuditEventRejectExpiredUserAccessToken
  event only fires when PATs are active for the user, not when the feature
  is globally disabled.
- Tie the cleanup_expired_access_tokens scheduler to EnableUserAccessTokens
  so the hourly job does not schedule on servers where PATs are disabled.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Remove per-token audit logging from expired PAT cleanup job

Background system jobs do not emit audit events in this codebase —
only user/admin-initiated actions do. The cleanup worker's per-token
AuditEventExpireUserAccessToken records were inconsistent with that
pattern (cleanup_desktop_tokens and other session jobs log nothing).

Also removes the early s.Audit init in NewServer that existed solely
to supply a non-nil logger to the worker.

The AuditEventRejectExpiredUserAccessToken event (emitted by
createSessionForUserAccessToken when a live request is rejected) is
unchanged — that is an auth gate firing in response to a request and
warrants auditing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Replace hand-rolled IN-clause helpers with squirrel query builder

Remove placeholders() and idsToArgs() from DeleteByIds — squirrel's
sq.Eq{"column": slice} generates the IN clause and argument list
automatically, matching the pattern used throughout the sqlstore package.

Also restructures the sessions delete from a PostgreSQL-specific
USING join to a portable subquery, keeping both statements expressible
via the query builder.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Drop redundant logger.Error calls in cleanup worker

SimpleWorker already logs any error returned from execute at the
Error level (base_workers.go:86). The extra logger.Error calls before
return were double-logging every failure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Use mlog.CreateConsoleTestLogger in cleanup worker tests

Replaces the hand-rolled newTestLogger helper with the established
mlog.CreateConsoleTestLogger(t) pattern used by other job tests in
this package (jobs_test.go, recap/worker_test.go). It wires cleanup
and test-runner output automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Consolidate cleanup worker tests into subtests

Groups the six top-level TestCleanupExpiredXxx functions under a single
TestCleanupExpired parent with t.Run subtests. One shared logger is
created at the parent level; each subtest gets its own fakeStore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Revert incidental configureAudit restructure in server.go

The separation of s.Audit init from configureAudit was an unintended
side effect of an earlier commit. Restore the original pattern where
configureAudit is only called when s.Audit was nil at startup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Remove api4 PAT expiry tests until API endpoint exists

The three tests (expired token rejected, session clamped, no-expiry
default) bypass the API to inject ExpiresAt via the store directly,
since no API endpoint exists yet to create tokens with an expiry.
They belong in the PR that adds that endpoint.

The same behaviors are covered at the appropriate layer by
storetest/user_access_token_store.go and model/user_access_token_test.go.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Prevent ExtendSessionExpiryIfNeeded from overriding PAT session expiry

PAT-authenticated sessions have their ExpiresAt clamped to the token's
ExpiresAt in createSessionForUserAccessToken. However, ExtendSessionExpiryIfNeeded
was resetting that expiry to now+SessionLengthWebInHours on the first
subsequent request, effectively bypassing PAT expiry for cached sessions.

Guard the extension to skip SessionTypeUserAccessToken sessions until
GetSessionLengthInMillis learns to return a length bounded by token.ExpiresAt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Strip ExpiresAt in create-token handler until API officially supports it

The JSON decoder populates the full accessToken struct from the request body,
and only UserId and Token were being overwritten before the store call. This
allowed clients to set an arbitrary expires_at (including 0 for non-expiring)
through the existing endpoint, contradicting the PR description.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Clear session cache for affected users after DeleteByIds in cleanup worker

DeleteByIds removes sessions from the DB but did not invalidate the in-memory
session cache. This left stale sessions readable from cache until eviction,
inconsistent with the RevokeSession path.

Thread a clearSessionCache callback through MakeWorker and cleanupExpired.
After each successful batch delete, call it for each unique UserId in the
batch. The callback is deduplicated per batch to avoid redundant cache
invalidations when a user has multiple expired tokens.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add partial index on useraccesstokens.expiresat

The cleanup job queries expiresat on every scheduled run (hourly). Without an
index this is a full sequential scan. Add a partial index WHERE expiresat > 0
to match the query's filter, keeping the index small since most tokens have no
expiry set. Mirrors the idx_sessions_expires_at pattern on the sessions table.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Register JobTypeCleanupExpiredAccessTokens in job permission switches

Without entries in SessionHasPermissionToReadJob, SessionHasPermissionToCreateJob,
and SessionHasPermissionToManageJob, the job type falls through to (false, nil),
which API handlers treat as HTTP 400. This made the cleanup job invisible to
System Console and unmanageable via API (list, cancel, manual trigger all 400).

Add the job type to the PermissionManageJobs / PermissionReadJobs groups in
all three switches, matching how other internal jobs like JobTypeMigrations
are handled.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Teach GetSessionLengthInMillis to honor PAT ExpiresAt

Replace the blunt guard in ExtendSessionExpiryIfNeeded with proper logic in
GetSessionLengthInMillis: for PAT sessions with a fixed ExpiresAt, return the
remaining lifetime instead of the configured web-session hours.

This means newExpiry = now + (ExpiresAt - now) = ExpiresAt, so extension never
pushes the session past the token's own expiry. The elapsed threshold
collapses to zero for such sessions, so no spurious DB writes occur either.

Non-expiring PAT sessions (ExpiresAt == 0) continue to use normal web-session
extension, which is correct behavior.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Split expiresat index into separate non-transactional migration (000175)

CREATE INDEX CONCURRENTLY cannot run inside a transaction block. The morph
migration runner wraps each file in a transaction by default, causing the
combined migration to fail.

Split the index creation out of 000174 into a new 000175 migration file
with the -- morph:nontransactional directive, following the same pattern
used by 000135, 000155, 000173 and others. The 174 down migration no longer
needs to drop the index since 175 owns it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update Beginx call to renamed Begin (sqlx wrapper API change on master)

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 10:30:30 +02:00
Christopher Poile
03f2eaaa0b
[MM-68400] Four plugin hooks and ChannelGuard enforcement (#36152)
* allow workflow_dispatch trigger for Server CI (for plugins CI)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [MM-68402] MBE Phase 2: declare four generic plugin hooks (#36291)

* new hooks-only phase 2

* remove ChannelWillBeMoved

* remove RecapWillBeProcessed and MessageWillBeRewrittenByAI

Drop the AI/recap hooks from the new-hook surface; AI-LLM paths
remain uncovered in tech preview and are documented as residuals.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [MM-68403] MBE Phase 3: ChannelGuards primitive (storage + cache + plugin API) (#36365)

* phase 3

* phase 3: register ChannelGuard mock in test setup helper

NewChannels' startup-time call to reloadGuardCache invokes
s.ChannelGuard().GetAll(); without an expectation on the mock store,
every test that sets up the server with GetMockStoreForSetupFunctions
panics during init.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* phase 3: register ChannelGuard mock in retrylayer test

retrylayer.New walks every store getter to wrap it; without the mock
expectation on ChannelGuard, TestRetry panics during layer construction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* use rctx properly in the store methods

* phase 3: match rctx arg in testlib ChannelGuard mock

GetAll now takes request.CTX, so the testify expectation must include
mock.Anything; otherwise the call panics under the mocked store.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* phase 3: set api.ctx in TestChannelGuardLowercaseNormalization

The test constructs PluginAPI directly without a ctx, which used to
work when App.RegisterChannelGuard built its own EmptyContext. Now
that the App methods take rctx from the caller, the nil ctx panics
inside RequestContextWithMaster.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [MM-68404] MBE Phase 4: App-layer plugin hook wiring (#36407)

* phase 4

* Fix nil rctx in TestChannelGuardLowercaseNormalization

The PluginAPI struct literal was missing ctx: rctx after a refactor
moved the rctx declaration below the struct construction, leaving
api.ctx as nil. This caused a nil pointer dereference in reloadGuardCache
when RegisterChannelGuard called store.RequestContextWithMaster(nil).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* Remove ChannelWillBeMoved hook call from MoveChannel (phase 4)

The hook and its ID were removed from mbe-phase-2 but the call site in
MoveChannel and its i18n string were not cleaned up during the rebase.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* remove channel will be moved test

* Remove RecapWillBeProcessed and MessageWillBeRewrittenByAI hook calls (phase 4)

The hooks and their IDs were removed from mbe-phase-2 but the call sites
in ProcessRecapChannel and RewriteMessage, their i18n strings, and their
tests were not cleaned up during the rebase.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Revert channel_id plumbing on rewrite endpoint (phase 4)

The channel_id field on RewriteRequest was added in phase 4 to feed the
synthetic post passed to MessageWillBeRewrittenByAI. With that hook
removed from mbe-phase-2, channel_id has no consumer; revert the field,
the api4 validation, the app.RewriteMessage parameter, and the
corresponding webapp client + hook plumbing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [MM-68555] MBE Phase 5: Channel-guard enforcement + two-phase dispatch (#36473)

* phase 5

* Bake plugin counter-file paths into source instead of env vars

t.Setenv panics when an ancestor test calls t.Parallel, so the two
channel-guard tests broke under ENABLE_FULLY_PARALLEL_TESTS in CI.
Build each plugin source per-subtest with its temp file path embedded
as a Go literal — same pattern as TestPluginUploadsAPI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Remove guarded helpers and tests for dropped hooks (phase 5)

The runGuardedRecapWillBeProcessed and runGuardedMessageWillBeRewrittenByAI
helpers were never wired (their app-layer call sites were already removed
in the phase-4 cleanup), and the corresponding sub-tests across panic /
allow / reject / partial plugins reference hooks that no longer exist.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [MM-68405] MBE Phase 6: fire MessagesWillBeConsumed on the edit path (#36475)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* rebase onto master

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 18:16:05 +00:00
Daniel Espino García
92f6870a2b
Add "last used" field for incoming webhooks (#36416)
* Add "last used" field for incoming webhooks

* Address feedback

* Rename migrations

* Fix web lint
2026-05-19 15:22:04 +02:00
Ibrahim Serdar Acikgoz
deafd88fd5
MM-68762: Discoverable Private Channels — Server data layer (#36539)
* MM-68762: Add Postgres migrations for discoverable private channels

Three online-safe migrations introduce the schema that supports the
Discoverable Private Channels feature (PRs 2-5 of MM-68430 will land
behind it):

- 000175 adds Channels.Discoverable BOOLEAN NOT NULL DEFAULT FALSE.
  Metadata-only on Postgres >= 11; no table rewrite.
- 000176 creates a partial index on
  (TeamId) WHERE Discoverable AND Type='P' AND DeleteAt=0
  using CREATE INDEX CONCURRENTLY (-- morph:nontransactional) so the
  build never blocks writes on the populated Channels table.
- 000177 creates the ChannelJoinRequests table with three indexes, the
  important one being the partial unique index on (ChannelId, UserId)
  WHERE Status = 'pending'. That keeps the full audit history intact
  while still enforcing at-most-one active pending request per
  (channel, user).

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Add FeatureFlagDiscoverableChannels (default false)

Gates the per-channel Discoverable toggle and the channel-join-request
flow. Default-OFF so all PRs in the MM-68430 series can land on master
without exposing partial UX.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Add Discoverable + ChannelJoinRequest models

- Channel gains a Discoverable bool, ChannelPatch a *bool, both serialized
  as 'discoverable'. Patch() applies it, Auditable() logs it, and IsValid()
  rejects Discoverable=true on any non-private channel so a misconfigured
  patch can never produce a public discoverable channel.
- New ChannelJoinRequest type captures the per-row state of a non-member's
  request: pending -> approved | denied | withdrawn. Rows are append-only
  with reviewer and timestamps so the table is also the audit trail.
  IsValid() enforces:
  * recognized status,
  * Message and DenialReason rune limits,
  * DenialReason only on denied rows (no orphan reasons),
  * reviewer + reviewed_at present for any terminal review (approved /
    denied) but not for self-service withdrawal.
- Two new WebSocket event constants -- channel_join_request_created and
  channel_join_request_updated -- that later PRs broadcast on the admin
  queue and the requester's My Pending Requests panel.

Unit tests cover Patch(), the new IsValid() rule on Discoverable, the
PreSave/PreUpdate timestamp behavior on ChannelJoinRequest, and every
IsValid branch including the reviewer-required-on-review invariant.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Add discoverable-channel permissions

Two new channel-scoped permissions, each independently rebindable from
the System Console:

- manage_private_channel_discoverability gates the per-channel toggle so
  admins can restrict who can flip discoverability without also handing
  out manage_private_channel_properties.
- manage_channel_join_requests gates the queue list / approve / deny /
  count endpoints (added in PR 2).

Both are added to the channel_admin role bootstrap so new deployments
get them by default, and a new permissions migration
(add_discoverable_channel_permissions) grants them to channel_admin,
team_admin and system_admin scheme roles on existing deployments.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Add ChannelJoinRequestStore and wire Discoverable into channel store

- channelSliceColumns / channelToSlice / updateChannelT now include the
  new Discoverable column so Save() and Update() round-trip the field.
  Existing select paths inherit the column automatically because every
  read goes through channelSliceColumns.
- New ChannelJoinRequestStore interface and SQL implementation:
  Save / Get / GetPendingForChannelAndUser / GetForChannel / GetForUser
  / Update / CountPending. Save translates the
  idx_channeljoinrequests_pending_unique partial unique index violation
  into store.ErrConflict so the app layer (PR 2) can return 409 without
  re-parsing pq errors.
- Storetest suite at storetest/channel_join_request_store.go is invoked
  from sqlstore via the existing StoreTest harness; covers insert /
  partial-unique conflict / re-insert after withdrawal / NotFound /
  status filtering / pagination with TotalCount / Update / CountPending.
- Mocks and retrylayer / timerlayer are regenerated via make store-mocks
  and go generate ./channels/store -- no hand-written generator output.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Add TS types for Discoverable channels + join requests

webapp/platform/types:
- Channel.discoverable?: boolean alongside existing policy_enforced /
  policy_is_active so the web client sees the same wire shape the server
  emits.
- ChannelJoinRequest, ChannelJoinRequestStatus, ChannelJoinRequestList,
  GetChannelJoinRequestsOptions for the API contract surfaced in PR 2.

webapp/platform/client:
- WebSocketEvents enum gains ChannelJoinRequestCreated and
  ChannelJoinRequestUpdated so PR 3 can hang WS handlers off them
  without redeclaring constants.

These are model-only updates with no UI consumer yet; PR 3 introduces
the toggle, request flow, and admin queue surfaces.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Split ChannelJoinRequests indexes into concurrent migrations

The mattermost-govet concurrentIndex lint check enforces CREATE INDEX
CONCURRENTLY on every CREATE INDEX statement, even on an empty
freshly-created table where it would be a no-op. The original 000177
file inlined three CREATE INDEX statements; that failed check-style.

Mirror the convention used by 000166_create_views +
000167_create_views_channel_id_delete_at_index: keep the CREATE TABLE
in its own (transactional) file, and move each index into a separate
nontransactional file that runs CREATE INDEX CONCURRENTLY. Verified
locally against Postgres 15 that all four new migrations apply in
order and the storetest suite (partial unique constraint + paged
list + count) still passes.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Wire new permission migration into test fixtures

Two CI test surfaces missed when the channel_admin role and the
permission-migration list gained the new
manage_private_channel_discoverability and manage_channel_join_requests
entries:

- testlib/store.go: the shared mocked SystemStore used by
  SetupWithStoreMock / SetupEnterpriseWithStoreMock needs an explicit
  GetByName expectation for every migration key (because the mock
  panics on unexpected calls). Add the new
  MigrationKeyAddDiscoverableChannelPermissions key so
  TestCreateOrUpdateAccessControlPolicy, the elasticsearch
  aggregation_job_test, and every other mock-store test stop panicking
  on server bootstrap.
- cmd/mmctl/commands/permissions_test.go: TestResetPermissionsCmd
  hard-codes the channel_admin default permission list and expects
  PatchRole to be called with exactly that slice. Extend the expected
  slice with the two new permission ids so the mmctl reset path stays
  in sync with the role bootstrap.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Register new idx_channels_discoverable_team in TestGetSchemaDefinition

The schema-dump test asserts an exact index count and definition map
for the channels table. Migration 000176 added
idx_channels_discoverable_team — a partial btree on (teamid) gated by
discoverable=true AND type='P' AND deleteat=0. Bump the expected count
from 12 to 13 and add the index's CREATE INDEX definition as produced
by pg_indexes (note: type is cast to channel_type, the existing
domain). Verified locally against Postgres 15.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Fix golangci-lint findings in ChannelJoinRequest store

Two golangci-lint findings on the freshly-added files:

- sqlstore/channel_join_request_store.go:133 (modernize): collapse the
  'if page < 0 { page = 0 }' clamp into max(opts.Page, 0).
- storetest/channel_join_request_store.go:243 (govet shadow): the
  inner Save loop redeclared err with :=, shadowing the outer err
  captured from the first CountPending call. Switch to plain
  assignment so the same err is reused.

Verified locally with golangci-lint v2.11.4 across public/...,
channels/app/..., channels/store/..., channels/testlib/... and
cmd/mmctl/commands/... — 0 issues.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Sync channel_admin bootstrap with TestDoAdvancedPermissionsMigration

app_test.go pins the exact list of permissions the channel_admin role
is expected to hold after DoAdvancedPermissionsMigration completes.
The role bootstrap in role.go grew two entries
(manage_private_channel_discoverability and manage_channel_join_requests),
so the test's expected slice needs the same two entries appended in
the same order, otherwise assert.Equal fails on slice ordering.

This is the same class of fix as the mmctl/permissions_test.go change
in a previous commit -- two parallel test fixtures encode the
channel_admin defaults and have to be updated in lockstep with the
bootstrap.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Add English translations for new model error keys

12 keys were emitted by the new Discoverable + ChannelJoinRequest
validation paths but had no en.json entry, which trips i18n-check on
CI. Add the missing entries with one-line English copy that mirrors
adjacent model errors (Invalid <field>., Create at must be a valid
time., etc.). The new entries are:

- model.channel.is_valid.discoverable.app_error
- model.channel_join_request.is_valid.channel_id.app_error
- model.channel_join_request.is_valid.create_at.app_error
- model.channel_join_request.is_valid.denial_reason.app_error
- model.channel_join_request.is_valid.denial_reason_status.app_error
- model.channel_join_request.is_valid.id.app_error
- model.channel_join_request.is_valid.message.app_error
- model.channel_join_request.is_valid.reviewed_by.app_error
- model.channel_join_request.is_valid.reviewer.app_error
- model.channel_join_request.is_valid.status.app_error
- model.channel_join_request.is_valid.update_at.app_error
- model.channel_join_request.is_valid.user_id.app_error

Generated through 'make i18n-extract'; verified clean with
'make i18n-check'. Per the workspace rule, only en.json was modified --
no other locale files.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Address CodeRabbit review: stable pagination + redact denial reason from audit log

Two production-code findings from CodeRabbit on the freshly-added
ChannelJoinRequest server code:

- sqlstore/channel_join_request_store.go (GetForChannel / GetForUser):
  OrderBy("CreateAt DESC") alone is unstable when two rows share a
  millisecond (NewId is monotonic-ish but CreateAt is millisecond
  resolution), so offset paging could duplicate or skip rows between
  pages. Add Id DESC as a deterministic tie-breaker on both list
  queries.
- model/channel_join_request.Auditable: the denial reason is admin-typed
  free text and could carry sensitive content. Mirror the existing
  has_message pattern by emitting has_denial_reason as a boolean
  presence flag instead of the raw value. Reviewer id, review timestamp,
  and status are still logged, so the audit trail keeps every piece
  needed for compliance review.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Tighten model tests per CodeRabbit review

Two test-only findings from CodeRabbit:

- TestChannelJoinRequestPreUpdateAdvancesUpdateAt previously asserted
  GreaterOrEqual(r.UpdateAt, originalCreate). Because validRequest
  initialises UpdateAt to GetMillis() (same call site as CreateAt), a
  no-op PreUpdate would still pass that check. Seed r.UpdateAt = 1
  before calling PreUpdate() and assert Greater(r.UpdateAt, int64(1))
  so any regression that drops the GetMillis assignment fails the test.
- TestChannelIsValidDiscoverable did not cover ChannelTypeGroup. Add the
  case alongside ChannelTypeOpen and ChannelTypeDirect so the contract
  that 'only ChannelTypePrivate accepts Discoverable=true' is fully
  pinned across all four channel types.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Mock ChannelJoinRequest accessor in retrylayer test

retrylayer_test.go's genStore() helper mocks every Store() accessor
because retrylayer.New() wraps the entire surface. The new
ChannelJoinRequest() method I added on Store was missing from the
mock, so TestRetry/on_regular_error_should_not_retry panicked with
'Unexpected Method Call ChannelJoinRequest()' on Postgres shard 0.

Add the mock alongside the other accessors. No production code
change.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>
2026-05-15 21:04:32 +02:00
David Krauser
9f1fe90b69
Migrate CPA to the v2 Property System (#36180) 2026-05-14 12:46:07 -04:00
Julien Tant
323841e9c5
Add board channel types (BO/BP) for Integrated Boards (#35887)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* Add board channel types (BO/BP) with POST /boards API

Introduces board channel types as a new channel variant that reuses the
Channels table but is fully isolated from all /channels endpoints.

Model:
- Add ChannelTypeOpenBoard ("BO") and ChannelTypePrivateBoard ("BP")
- Add IsBoard(), IsOpenBoard(), IsPrivateBoard() helpers
- Add board-specific websocket events (board_created/updated/deleted/restored)

Store:
- SaveBoardChannel: atomic channel + view creation in a single transaction
- Save() rejects board types (forces use of SaveBoardChannel)
- Exclude boards from all channel listing/search queries (GetTeamChannels,
  GetAll, GetChannels, GetChannelsByUser, GetDeleted, autocomplete, search)

API:
- POST /boards: create board channel (feature-flagged behind IntegratedBoards)
- All /channels write endpoints reject board types with 400
- All /channels read endpoints reject or exclude board types
- Open boards get same public-read semantics as open channels

Tests:
- 15 rejection tests covering every /channels write + read endpoint
- 9 exclusion tests covering every listing/search endpoint
- 8 store tests for SaveBoardChannel + Save rejection
- 4 board creation API tests (create, private, flag off, sidebar exclusion)
- 3 authorization tests for board permission semantics

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update generated files: i18n, go.mod, migrations list

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add i18n translations for board channel error strings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix board guard ordering in getChannelMembers and getChannelStats

Move the board rejection check after the permission check so that
nonexistent channel IDs still return 403 (not 404) matching the
original behavior expected by TestGetChannelMembers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Filter boards at store level instead of API guards

Store.Get() now excludes board types via WHERE clause, making boards
invisible to all /channels endpoints. Added GetBoardChannel() for
/boards endpoints. Removed redundant API-level rejectBoardChannel
guards from 10 handlers that already call GetChannel(). Kept explicit
guards only on 3 handlers that don't fetch the channel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix empty i18n translation for app.channel.save_member.app_error

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add board system properties, kanban column config, and audit logging

Migration:
- Register "boards" property group with system-wide Assignee (user) and
  Status (select: Todo/In Progress/Complete) fields, both protected
- Idempotent migration following content flagging pattern

Board creation:
- Look up boards fields by name, set board:linked_properties on channel
- Build kanban view props with group_by mapping status options to columns
- Add typed KanbanProps/KanbanColumn/KanbanGroupBy structs with
  ToProps()/KanbanPropsFromProps() for round-tripping
- Add audit record logging for POST /boards
- Add early team_id validation in API handler
- Error on missing status options instead of silent empty columns

Tests:
- Migration test: field creation + idempotent re-run
- Board creation test: verify kanban props + linked_properties
- Fix updateChannelMemberRoles test to use valid role string

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add boards migration mock to testlib store setup

The boards property migration calls System().GetByName() which needs
a matching mock expectation, same pattern as content_flagging_setup_done.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add kanban view props validation and tests

Validate kanban View.Props in IsValid(): group_by required with valid
field_id, 1-100 columns, each column needs id, name, and at least one
option_id. Update all test helpers to produce valid kanban props.

11 dedicated validation tests + round-trip test for KanbanProps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Validate board display name is not empty

Add early DisplayName validation in CreateBoardChannel with a clear
error. Add tests for empty and whitespace-only display names.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Exclude boards from GetMany and getChannelsMemberCount

Add board type exclusion to Store.GetMany() and use filtered channel
IDs in getChannelsMemberCount handler so board channels don't leak
into member count results. Add test covering the endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix review issues: drop search indexing for boards, use request context

- Remove search layer indexing of board channels so they stay invisible
  to Elasticsearch/Bleve-powered search and autocomplete
- Replace context.Background() with rctx.Context() for proper
  cancellation and tracing in CreateBoardChannel

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix gofmt alignment in websocket_message.go after merge

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Regenerate server i18n after merge

* Restore translation for permission_policy.app_error

* Filter board channels in name lookups, autocomplete, and indexing

The store-layer board exclusion filter was missing from getByName,
getByNames, GetDeletedByName, the global Autocomplete, and
GetChannelsBatchForIndexing — leaving boards reachable via name
lookups, the no-team-filter search path, and admin reindex jobs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Reject boards in id-batch lookups, unread, and member-mutation endpoints

- GetChannelsByIds, GetChannelsWithTeamDataByIds, and GetChannelUnread
  now exclude BO/BP at the store layer so boards can't slip through if
  callers stop filtering first.
- updateChannelMemberNotifyProps, updateChannelMemberAutotranslation,
  and viewChannel now reject board IDs explicitly via the existing
  rejectBoardChannelByID helper, matching the other write endpoints.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Gate boards properties setup on the IntegratedBoards feature flag

doSetupBoardsProperties registered the boards property group and
fields at every server boot regardless of the IntegratedBoards
feature flag. Skip the migration when the flag is disabled so the
property metadata only appears once boards are actually enabled.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Use App accessors for boards property lookups

CreateBoardChannel reached into a.Srv().PropertyService() directly
instead of going through the App-level GetPropertyGroup and
GetPropertyFieldByName methods that already wrap the service. Switch
to the standard App accessors so the calls match the rest of the
codebase.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Log full channel input on createBoard audit record

createBoard only captured team_id and type on the audit record, so
failed creations lost most of the request payload. Use
AddEventParameterAuditableToAuditRec with the full channel struct,
matching createChannel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Use allow-list of message channel types in store filters

Inverted every sq.NotEq{[BO, BP]} filter into sq.Eq{messageChannelTypes}
(or teamMessageChannelTypes for queries that also exclude direct
channels) so that any future non-message channel type — wikis, etc. —
is excluded by default rather than requiring every existing call site
to be updated. Also rewrote GetChannelUnread on top of the squirrel
builder so the same allow-list slice can be reused.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* go.mod: promote prometheus/common to direct after merge

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Use model.NewPointer for boards property permission field

Drops the local permNone variable in doSetupBoardsProperties and uses
model.NewPointer(model.PermissionLevelNone) inline, matching the
surrounding ContentFlagging/ManagedCategory code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Extract saveViewT to share Views insert between Save and SaveBoardChannel

ViewStore.Save and SaveBoardChannel both built the same INSERT INTO
Views statement, so a future column addition would need updates in two
places. Extract the insert (plus PreSave/IsValid) into a private
saveViewT method that accepts any sqlxExecutor — the regular master
handle for ViewStore.Save, and the channel transaction for
SaveBoardChannel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add IsMessageChannel helper on model.Channel

Mirrors IsBoard for the positive case: returns true for Open, Private,
Direct, and Group channel types. Lets future filtering code be
expressed against the allow-list rather than enumerating board types,
so newly introduced non-message channel types are excluded by default.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Move board input validation into Channel.IsValidBoard

CreateBoardChannel inlined four guards for type, team, and display
name. Move the type/team_id/display_name checks into a new
Channel.IsValidBoard method so the rules live with the model and
return the AppError directly. The TrimSpace on DisplayName stays at
the call site to match how CreateChannel sanitizes before validating.

Drops the now-unused app.channel.create_board_channel.{invalid_type,
no_team,no_display_name} translations and adds matching
model.channel.is_valid_board.* keys.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Extract buildBoardKanbanView from CreateBoardChannel

The kanban view construction (read status options, build columns,
serialize props, assemble *model.View) only depends on the status
property field and the creator id. Pulling it into its own helper
shrinks CreateBoardChannel and makes the column-building logic
testable in isolation.

Adds board_test.go with coverage for the empty-options error path,
the standard happy path, and the option-skipping branches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Test Channel.IsValidBoard

Cover the four reject cases (wrong type, missing team_id, empty
display name) plus the open and private board accept cases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* gofmt board_test.go

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Document POST /api/v4/boards in OpenAPI spec

* Add valid kanban props to api4 makeTestViewForAPI helper

* Assert kanban.ToProps error in makeTestViewForAPI helper

The helper used to swallow the error from kanban.ToProps. Take *testing.T
and require.NoError so a serialization failure surfaces immediately at the
call site instead of producing a malformed view.

* Run boards properties setup unconditionally

The feature-flag gate added in 6298e15e86 made the test suite impossible:
test infra applies FeatureFlags overrides only after app.NewServer returns,
but doAppMigrations runs during NewServer, so the flag was always false at
migration time. The migration short-circuited, the boards property group
was never registered, and every CreateBoardChannel test 500'd with
"boards property group not found."

Drop the gate. The migration is idempotent (keyed in System) and benign —
matches doSetupContentFlaggingProperties and doSetupManagedCategoryProperties.
IntegratedBoards still gates route registration (api4/board.go) and the
CreateBoardChannel runtime entry (app/board.go), so the property group sits
unused until the feature is enabled.

* Add Client4.CreateBoard and use it in tests

Adds boardsRoute() and CreateBoard(ctx, channel) on Client4 mirroring
CreateChannel/CreateView. Refactors api4 board tests off the raw
DoAPIPost("/boards", ...) calls and the SaveBoardChannel store
inserts that predated the API; both now exercise the public client
method, drop the makeTestBoardView helper and the manual SaveMember
follow-ups, and route through setupBoardTest so IntegratedBoards is
enabled where needed.

* make modules-tidy

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 16:25:08 -07:00
Doug Lauder
0530d60e4a
MM-68722 - Set higher statistics target on posts.rootid and posts.channelid (#36506)
* MM-68722 - Set higher statistics target on posts.rootid and posts.channelid

  The default PostgreSQL column statistics target (100) is too coarse for
  posts.rootid: most rows have an empty rootid and the remainder is a long
  tail of distinct thread IDs, so the planner cannot accurately estimate
  selectivity for a specific non-empty rootid. As a result, queries like
  the per-thread MAX(createat) issued from updateThreadsFromPosts get
  planned to scan idx_posts_create_at backward and filter by rootid,
  scanning tens of millions of rows per call instead of using the
  idx_posts_root_id_delete_at index. This was observed during a large DM
  import where 16 workers were each stuck on the same query for 20 to 70
  seconds, dropping import throughput from a few thousand posts per minute
  to ~155 per minute.

  Raising the statistics target to 5000 on rootid (and on channelid for
  the same reason) lets ANALYZE record enough most-common-values that the
  planner correctly recognizes specific non-empty values as highly
  selective and picks the right index. Verified locally: post-fix the
  query runs in 0.058 ms with 11 buffer hits, vs 20725 ms with 25.8M
  buffer hits before.

  This is a metadata-only change. ALTER TABLE ... SET STATISTICS takes a
  SHARE UPDATE EXCLUSIVE lock and does not block concurrent DML.

* MM-68722 - Run ANALYZE in migration so new statistics target takes effect immediately

  ALTER TABLE ... SET STATISTICS only changes the target; the planner keeps
  using the existing sample in pg_statistic until ANALYZE runs. On a busy
  Posts table autoanalyze fires after ~10 percent of rows change, and on a
  quiet site it may not fire at all before the operator runs the import that
  motivates this change. Running ANALYZE in the migration ensures the new
  sample is collected at deploy time rather than at an indeterminate later
  point.

  Scoped to (rootid, channelid) since those are the only columns whose
  statistics target changed. Both are gathered in a single table scan.
  ANALYZE takes SHARE UPDATE EXCLUSIVE and does not block DML. No
  corresponding change in the down migration: resetting the target to -1
  leaves the existing samples valid for continued planner use, so no
  rollback-time ANALYZE is needed.
2026-05-12 08:45:11 -04:00
Guillermo Vayá
ecf8a741ac
Add unread badge to Recaps sidebar link (#36246)
* Add unread badge to Recaps sidebar link

Shows the count of unread finished recaps (completed or failed) on the
LHS Recaps link. Pending and processing recaps are excluded so the badge
only reflects work the user can actually read. When any unread recap has
failed, the badge is colored as an error to surface the failure.

The badge updates live through the existing recap_updated WebSocket
event, which refreshes the recap in the Redux store.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Fix Recaps failed-badge color losing to active sidebar rule

The failed-badge modifier selector had the same specificity (0,4,0) as
`.channel-view .sidebar--left .active .badge` in _badge.scss, so when
the Recaps link was the active route the global mention background
color won on cascade order. Scope the rule with `#SidebarContainer` so
it wins on specificity (1 id + 4 classes) regardless of active state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Fix Recaps badge selector memoization

getUnreadFinishedRecapsBadge was keyed off getAllRecaps, which is not
memoized and returns a new array on every call. That broke reselect's
reference-equality input check, so the selector recomputed and returned
a fresh {count, hasFailed} object on every store dispatch — forcing
RecapsLink (always mounted when the feature flag is on) to re-render
on every action. Key the selector off state.entities.recaps directly
and iterate ids in the result function so memoization holds when the
recaps slice is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Address PR feedback on Recaps sidebar badge

- Pass shallowEqual to the useSelector consuming
  getUnreadFinishedRecapsBadge. The selector returns a plain
  {count, hasFailed} object, so recap updates that change a recap
  but leave the badge values the same (e.g. marking a read recap)
  would otherwise force RecapsLink to re-render.
- Scope the "no badge" negative assertion to the render container so
  it only asserts on the badge element, not any '1' or '.badge'
  elsewhere in the DOM.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Address UX feedback on Recaps sidebar badge

- Add `unread` class to the sidebar item and `unread-title` to the
  link when there are unread recaps so the label goes bold and the
  icon goes full-opacity, matching how channels and the threads link
  indicate unread state.
- Keep the badge (and the new failed icon) visible on hover so it
  doesn't disappear under the cursor -- same override the threads
  link uses.
- Replace the red failed-badge modifier with an amber alert icon
  rendered in place of the count badge when any unread recap has
  failed. Red mention badges are reserved for urgent priority
  messages and caused confusion here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Keep Recaps badge in place on hover

The global sidebar hover rule shrinks padding-right from 16px to 5px
to make room for the per-channel menu button, which shifted the badge
right since it stays visible. Restore padding-right: 16px on hover for
the Recaps link, matching what the threads link already does.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Align Recaps failed-icon aria-label with tooltip

The aria-label on the .RecapsFailedIcon span was a hardcoded English
string ("Recap failed") that differed from the tooltip shown to
sighted users ("One or more recaps failed"). Derive the aria-label
from the same intl message used by the tooltip so screen readers and
sighted users get the same wording and the label is localized.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Stop Recaps link from overriding global unread label styling

The combined `.active .SidebarLink, .SidebarLink.unread-title` rule
pushed font-weight: 400 onto .SidebarChannelLinkLabel with specificity
(0,4,0), overriding the global `.SidebarChannel.unread` rule that sets
font-weight: 600 and --sidebar-unread-text at (0,3,0). As a result the
Recaps label rendered at normal weight when unread, inconsistent with
channels and the threads link. Split the rules: keep the active-state
overrides as they were, and limit the unread-title rule to the
icon-specific styling Recaps actually needs, letting the global unread
styling apply to the label.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add i18n entry for Recaps failed-tooltip

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* change size of alert icon

* fix the right icon

* Add ViewedAt to recaps and POST /recaps/mark_viewed endpoint

Introduce a new ViewedAt field on Recap, separate from ReadAt, that
tracks whether the user has at least seen a finished recap on the
recaps page. ReadAt keeps its existing per-recap "Mark read" semantics.

- New Postgres migration 000172 adds the ViewedAt column (default 0)
  and an idx_recaps_user_id_viewed_at index mirroring the existing
  ReadAt index.
- New store method MarkRecapsAsViewed(userId, statuses) does a single
  UPDATE ... WHERE ViewedAt = 0 AND Status IN (...) RETURNING Id so
  the app layer can fan out one WS event per affected recap.
- New App.MarkRecapsAsViewed(rctx) marks the user's not-yet-viewed
  completed/failed recaps and broadcasts WebsocketEventRecapUpdated
  per affected id.
- New POST /recaps/mark_viewed handler. Registered before the
  {recap_id} regex routes so mark_viewed isn't captured as an id.
- RegenerateRecap now resets ViewedAt = 0 so a regenerated recap is
  surfaced again in the badge once it completes. As a related fix,
  UpdateRecap now persists ReadAt and ViewedAt -- previously it
  silently dropped the ReadAt = 0 reset that RegenerateRecap was
  setting in memory.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Mark recaps as viewed when the recaps page mounts

Wire the new server endpoint into the webapp:

- Recap type now includes viewed_at: number.
- Client4.markRecapsAsViewed posts to /recaps/mark_viewed.
- New markRecapsAsViewed redux action, fired alongside getRecaps and
  getAgents in the recaps page mount effect. The server broadcasts
  recap_updated per affected recap so other tabs/devices receive the
  update through the existing handleRecapUpdated WS handler -- no new
  client-side handler needed.
- getUnreadFinishedRecapsBadge now filters on viewed_at === 0 instead
  of read_at === 0, so the sidebar badge clears on page open instead
  of requiring per-recap "Mark read" clicks. Selector tests updated to
  match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Address review feedback on Recaps viewed_at change

- Defer markRecapsAsViewed until after getRecaps resolves on the
  recaps page mount. Previously they ran in parallel, so getRecaps
  could land last and overwrite the viewed_at: <now> timestamps the
  WS-driven refresh had just written, briefly re-showing the badge.
- Switch the markRecapsAsViewed audit log to LevelContent and record
  the affected ids as result state, matching the pattern of every
  other mutating recap handler (markRecapAsRead, deleteRecap, etc).
  recap_count meta is now recorded unconditionally.
- Add an app-layer test that asserts MarkRecapsAsViewed publishes a
  recap_updated websocket event for each affected recap. The fan-out
  is the entire reason this lives in the app layer, so a regression
  removing the publish loop should fail loudly.
- Add a store-layer regression test that UpdateRecap actually
  persists ReadAt = 0 / ViewedAt = 0 resets, guarding the regenerate
  flow against a future change that drops those columns from the
  update map.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Update migrations.list for 000172_add_recaps_viewed_at

Regenerated via `make migrations-extract` so the autogenerated
sequence list includes the new recaps ViewedAt migration files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Use AddMeta for Recaps mark_viewed audit ids

AddEventResultState takes a model.Auditable, not a plain map[string]any,
so the previous attempt to record the affected ids did not compile.
Record them as audit metadata instead, matching the pattern used by
getRecaps which similarly returns a slice and uses AddMeta only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Split Recaps ViewedAt index into a CONCURRENTLY migration

The lint check rejects bare CREATE/DROP INDEX in migrations because
they take an ACCESS EXCLUSIVE lock and block DML. Split the index off
into 000173 with CONCURRENTLY + the morph:nontransactional directive,
matching the pattern used by 000168/000169 (LinkedFieldID column +
its index). 000172 keeps just the ALTER TABLE ADD COLUMN, which can
stay transactional.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add viewed_at to existing Recap test fixtures

The Recap type now requires viewed_at, so the fixtures in
recap_item.test.tsx, recap_processing.test.tsx, and recaps_list.test.tsx
need it too. CI was rejecting them with TS2741.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Mock markRecapsAsViewed in recaps.test.tsx

The mount effect now also dispatches markRecapsAsViewed, but the
manual jest.mock for 'mattermost-redux/actions/recaps' only exposed
getRecaps, so the runtime call resolved to undefined and crashed
with "markRecapsAsViewed is not a function". Add the missing entry
to the mock.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add /recaps/mark_viewed and Recap.viewed_at to OpenAPI spec

The recap-spec validator rejected the new POST /api/v4/recaps/mark_viewed
handler because it had no documented operation. Add the path with its
MarkRecapsAsViewed operationId, response shape, and behavior, and add
the new viewed_at timestamp field to the Recap schema in definitions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Fill in app.recap.mark_viewed.app_error translation

The new MarkRecapsAsViewed app method references this i18n key but the
en.json entry was added with an empty translation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Skip markRecapsAsViewed when getRecaps fails

Marking recaps as viewed implies the user just looked at them. If
getRecaps fails the user is staring at an error/empty state, so we
shouldn't ack them on the server. Gate the dispatch on the thunk's
result.error -- the codebase's bindClientFunc swallows errors and
returns {error}, so the conventional try/catch pattern doesn't apply
here.

Update the recaps.test.tsx dispatch mock to return a resolved promise
so the new awaited result has the expected shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Clear and assert markRecapsAsViewed mock in recaps.test.tsx

Reset the new mock in beforeEach so it doesn't carry state across
tests, and assert that the mount effect dispatches markRecapsAsViewed
after getRecaps resolves. Awaiting via waitFor since the mark fires
inside an async fetchData chain.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 15:14:18 +02:00
Miguel de la Cruz
5b4efbd28a
Remove unused property fields index (#36279)
* Remove unused property fields index

* Update server/channels/db/migrations/migrations.list

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-04-27 12:32:49 +02:00
Miguel de la Cruz
9c684e6313
Property System v2 Generic APIs blacklist (#36171)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* Adds version to the property group model

* Ensures that the REST API rejects v1 group calls

* Ensures field version and group version match

* Simplify property groups on app layer tests

* Add GetByID to PropertyGroupStore and enforce field/group version match on update

* Simplify bits of the code

* Fix i18n and add generic errors

* Fix PropertyGroupStore mock to return stable IDs and default zero version to V1

* Fix tests that were using nonexistent group IDs

* Fix rigidness on valid group names

* Update group not found slug

* Temporary allow to use tempaltes with v1

* Explicitly including tempaltes in the IsPSAv1 check for conflict check

* Return 404 on group not found and template explicit inclusion on patch API endpoint

* Fix CPA test that would use fields from unregistered groups

---------

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
2026-04-24 11:51:02 +02:00
David Krauser
3fa8776095
[MM-68100] Implement Linked Properties for the Property System (#35808) 2026-04-21 18:59:12 +00:00
Jesse Hallam
eb8310a30c
simplify CODEOWNERS (#35770)
* simplify CODEOWNERS

* dont .gitignore AGENTS.md

* AGENTS.md to document previous CODEOWNERS responsibilities

* update from https://developers.mattermost.com/contribute/more-info/server/schema-migration-guide/

* CREATE INDEX CONCURRENTLY now vetted

* rewrite and move to README.md

* dont limit to 80 chars

* rewrite webapp AGENTS.md and add to README.md

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2026-04-01 13:03:36 +00:00
Miguel de la Cruz
48f2fd0873
Merge the Integrated Boards MVP feature branch (#35796)
* Add CreatedBy and UpdatedBy to the properties fields and values (#34485)

* Add CreatedBy and UpdatedBy to the properties fields and values

* Fix types

---------

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>

* Adds ObjectType to the property fields table (#34908)

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>

* Update ObjectType migration setting an empty value and marking the column as not null (#34915)

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>

* Adds uniqueness mechanisms to the property fields (#35058)

* Adds uniqueness mechanisms to the property fields

After adding ObjectType, this commit ensures that both the PSAv1 and
PSAv2 schemas are supported, and enforces property uniqueness through
both database indexes and a logical check when creating new property
fields.

* Adds uniqueness check to property updates

Updates are covered on this commit and we refactor as well the SQL
code to use the squirrel builder and work better with the conditional
addition of the `existingID` piece of the query.

* Add translations to error messages

* Fixing retrylayer mocks

* Remove retrylayer duplication

* Address review comments

* Fix comment to avoid linter issues

* Address PR comments

* Update server/channels/db/migrations/postgres/000157_add_object_type_to_property_fields.down.sql

Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com>

* Update server/channels/db/migrations/postgres/000157_add_object_type_to_property_fields.up.sql

Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com>

* Update server/channels/db/migrations/postgres/000157_add_object_type_to_property_fields.up.sql

Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com>

* Update field validation to check only for valid target types

* Update migrations to avoid concurrent index creation within a transaction

* Update migrations to make all index ops concurrent

* Update tests to use valid PSAv2 property fields

* Adds a helper for valid PSAv2 TargetTypes

---------

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com>

* Fix property tests (#35388)

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>

* Adds Integrated Boards feature flag (#35378)

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>

* Adds Integrated Boards MVP API changes (#34822)

This PR includes the necessary changes for channels and posts
endpoints and adds a set of generic endpoints to retrieve and manage
property fields and values following the new Property System approach.

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
Co-authored-by: Mattermost Build <build@mattermost.com>

* Property System Architecture permissions for v2 (#35113)

* Adds uniqueness mechanisms to the property fields

After adding ObjectType, this commit ensures that both the PSAv1 and
PSAv2 schemas are supported, and enforces property uniqueness through
both database indexes and a logical check when creating new property
fields.

* Adds uniqueness check to property updates

Updates are covered on this commit and we refactor as well the SQL
code to use the squirrel builder and work better with the conditional
addition of the `existingID` piece of the query.

* Add translations to error messages

* Add the permissions to the migrations, model and update the store calls

* Adds the property field and property group app layer

* Adds authorization helpers for property fields and values

* Make sure that users cannot lock themselves out of property fields

* Migrate permissions from a JSON column to three normalized columns

* Remove the audit comment

* Use target level constants in authorization

* Log authorization membership failures

* Rename admin to sysadmin

* Fix i18n sorting

---------

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>

* Add Views store and app layer (#35361)

* Add Views store and app layer for Integrated Boards

Implements the View entity (model, SQL store, service, app) as described
in the Integrated Boards tech spec. Views are channel-scoped board
configurations with typed props (board, kanban subviews) and soft-delete.

- public/model: View, ViewBoardProps, Subview, ViewPatch types with
  PreSave/PreUpdate/IsValid/Patch/Clone/Auditable
- Migration 158: Views table with jsonb Props column and indexes
- SqlViewStore: CRUD with nil-safe Props marshaling (AppendBinaryFlag)
- ViewService: CreateView seeds default kanban subview and links the
  boards property field; caches boardPropertyFieldID at startup
- App layer: CreateView/GetView/GetViewsForChannel/UpdateView/DeleteView
  with channel-membership permission checks and WebSocket events
  (view_created, view_updated, view_deleted)
- doSetupBoardsPropertyField: registers the Boards property group and
  board field in NewServer() before ViewService construction
- GetFieldByName now returns store.ErrNotFound instead of raw sql.ErrNoRows

* Move permission checks out of App layer for views

- Remove HasPermissionToChannel calls from all App view methods
- Drop userID params from GetView, GetViewsForChannel, UpdateView, DeleteView
- Fix doSetupBoardsPropertyField to include required TargetType for PSAv2 field

* Make View service generic and enforce board validation in model

- Remove board-specific auto-setup from service and server startup
- Enforce that board views require Props, at least one subview, and at least one linked property in IsValid()
- Move default subview seeding out of app layer; callers must provide valid props
- Call PreSave on subviews during PreUpdate to assign IDs to new subviews
- Update all tests to reflect the new validation requirements

* Restore migrations files to match base branch

* Distinguish ErrNotFound from other errors in view store Get

* Use CONCURRENTLY and nontransactional for index operations in views migration

* Split views index creation into separate nontransactional migrations

* Update migrations.list

* Update i18n translations for views

* Fix makeView helper to include required Props for board view validation

* Rename ctx parameter from c to rctx in OAuthProvider mock

* Remove views service layer, call store directly from app

* Return 500 for unexpected DB errors in GetView, 404 only for not-found

* Harden View model: deep-copy Props, validate linked property IDs

- Add ViewBoardProps.Clone() to deep-copy LinkedProperties and Subviews
- Use it in View.Clone() and View.Patch() to prevent shared-slice aliasing
- Iterate over LinkedProperties in View.IsValid() and reject invalid IDs
  with a dedicated i18n key
- Register ViewStore in storetest AssertExpectations so mock expectations
  are enforced
- Add tests covering all new behaviours

* Restore autotranslation worker_stopped i18n translation

* Fix view store test IDs and improve error handling in app layer

- Use model.NewId() for linked property IDs in testUpdateView to fix
  validation failure (IsValid rejects non-UUID strings)
- Fix import grouping in app/view.go (stdlib imports in one block)
- Return 404 instead of 500 when Update/Delete store calls return
  ErrNotFound (e.g. concurrent deletion TOCTOU race)

* Add View store mock to retrylayer test genStore helper

The View store was added to the store interface but the genStore()
helper in retrylayer_test.go was not updated, causing TestRetry to panic.
Also removes the duplicate Recap mock registration.

* Refactor view deletion and websocket event handling; update SQL store methods to use query builder

* revert property field store

* Remove useless migrations

* Add cursor-based pagination to View store GetForChannel

- Add ViewQueryCursor and ViewQueryOpts types with validation
- Return (views, cursor, error) for caller-driven pagination
- PerPage clamping: <=0 defaults to 20, >200 clamps to 200
- Support IncludeDeleted filter
- Add comprehensive store tests for pagination, cursor edge cases,
  PerPage clamping, and invalid input rejection
- Add app layer test for empty channelID → 400
- Update interface, retrylayer, timerlayer, and mock signatures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Refactor test loops in ViewStore tests for improved readability

* change pagination to limit/offset

* Add upper-bound limits on View Subviews and LinkedProperties

Defense-in-depth validation: cap Subviews at 50 and LinkedProperties
at 500 to prevent abuse below the 300KB payload limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* MM-67388, MM-66528, MM-67750: Add View REST API endpoints, websocket events, and sort order (#35442)

* Add Views store and app layer for Integrated Boards

Implements the View entity (model, SQL store, service, app) as described
in the Integrated Boards tech spec. Views are channel-scoped board
configurations with typed props (board, kanban subviews) and soft-delete.

- public/model: View, ViewBoardProps, Subview, ViewPatch types with
  PreSave/PreUpdate/IsValid/Patch/Clone/Auditable
- Migration 158: Views table with jsonb Props column and indexes
- SqlViewStore: CRUD with nil-safe Props marshaling (AppendBinaryFlag)
- ViewService: CreateView seeds default kanban subview and links the
  boards property field; caches boardPropertyFieldID at startup
- App layer: CreateView/GetView/GetViewsForChannel/UpdateView/DeleteView
  with channel-membership permission checks and WebSocket events
  (view_created, view_updated, view_deleted)
- doSetupBoardsPropertyField: registers the Boards property group and
  board field in NewServer() before ViewService construction
- GetFieldByName now returns store.ErrNotFound instead of raw sql.ErrNoRows

* Move permission checks out of App layer for views

- Remove HasPermissionToChannel calls from all App view methods
- Drop userID params from GetView, GetViewsForChannel, UpdateView, DeleteView
- Fix doSetupBoardsPropertyField to include required TargetType for PSAv2 field

* Make View service generic and enforce board validation in model

- Remove board-specific auto-setup from service and server startup
- Enforce that board views require Props, at least one subview, and at least one linked property in IsValid()
- Move default subview seeding out of app layer; callers must provide valid props
- Call PreSave on subviews during PreUpdate to assign IDs to new subviews
- Update all tests to reflect the new validation requirements

* Restore migrations files to match base branch

* Distinguish ErrNotFound from other errors in view store Get

* Use CONCURRENTLY and nontransactional for index operations in views migration

* Split views index creation into separate nontransactional migrations

* Update migrations.list

* Update i18n translations for views

* Fix makeView helper to include required Props for board view validation

* Rename ctx parameter from c to rctx in OAuthProvider mock

* Remove views service layer, call store directly from app

* Return 500 for unexpected DB errors in GetView, 404 only for not-found

* Harden View model: deep-copy Props, validate linked property IDs

- Add ViewBoardProps.Clone() to deep-copy LinkedProperties and Subviews
- Use it in View.Clone() and View.Patch() to prevent shared-slice aliasing
- Iterate over LinkedProperties in View.IsValid() and reject invalid IDs
  with a dedicated i18n key
- Register ViewStore in storetest AssertExpectations so mock expectations
  are enforced
- Add tests covering all new behaviours

* Restore autotranslation worker_stopped i18n translation

* Fix view store test IDs and improve error handling in app layer

- Use model.NewId() for linked property IDs in testUpdateView to fix
  validation failure (IsValid rejects non-UUID strings)
- Fix import grouping in app/view.go (stdlib imports in one block)
- Return 404 instead of 500 when Update/Delete store calls return
  ErrNotFound (e.g. concurrent deletion TOCTOU race)

* Add View store mock to retrylayer test genStore helper

The View store was added to the store interface but the genStore()
helper in retrylayer_test.go was not updated, causing TestRetry to panic.
Also removes the duplicate Recap mock registration.

* Refactor view deletion and websocket event handling; update SQL store methods to use query builder

* revert property field store

* Add View API endpoints with OpenAPI spec, client methods, and i18n

Implement REST API for channel views (board-type) behind the
IntegratedBoards feature flag. Adds CRUD endpoints under
/api/v4/channels/{channel_id}/views with permission checks
matching the channel bookmark pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Remove useless migrations

* Add cursor-based pagination to View store GetForChannel

- Add ViewQueryCursor and ViewQueryOpts types with validation
- Return (views, cursor, error) for caller-driven pagination
- PerPage clamping: <=0 defaults to 20, >200 clamps to 200
- Support IncludeDeleted filter
- Add comprehensive store tests for pagination, cursor edge cases,
  PerPage clamping, and invalid input rejection
- Add app layer test for empty channelID → 400
- Update interface, retrylayer, timerlayer, and mock signatures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add cursor-based pagination to View API for channel views

* Enhance cursor handling in getViewsForChannel and update tests for pagination

* Refactor test loops in ViewStore tests for improved readability

* Refactor loop in TestGetViewsForChannel for improved readability

* change pagination to limit/offset

* switch to limit/offset pagination

* Add upper-bound limits on View Subviews and LinkedProperties

Defense-in-depth validation: cap Subviews at 50 and LinkedProperties
at 500 to prevent abuse below the 300KB payload limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add view sort order API endpoint

Add POST /api/v4/channels/{channel_id}/views/{view_id}/sort_order
endpoint following the channel bookmarks reorder pattern. Includes
store, app, and API layers with full test coverage at each layer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add connectionId to view WebSocket events and sort_order API spec

Thread connectionId from request header through all view handlers
(create, update, delete, sort_order) to WebSocket events, matching
the channel bookmarks pattern. Add sort_order endpoint to OpenAPI
spec. Update minimum server version to 11.6.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Remove duplicate View/ViewPatch definitions from definitions.yaml

The merge from integrated-boards-mvp introduced duplicate View and
ViewPatch schema definitions that were already defined earlier in
the file with more detail (including ViewBoardProps ref and enums).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update minimum server version to 11.6 in views API spec

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add missing translations for view sort order error messages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Merge integrated-boards-mvp into ibmvp_api-views; remove spec files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix flaky TestViewStore timestamp test on CI

Add sleep before UpdateSortOrder to ensure timestamps differ,
preventing same-millisecond comparisons on fast CI machines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* remove duplicate views.yaml imclude

* Use c.boolString() for include_deleted query param in GetViewsForChannel

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix views.yaml sort order schema: use integer type and require body

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Refactor view sort order tests to use named IDs instead of array indices

Extract idA/idB/idC from views slice and add BEFORE/AFTER comments
to make stateful subtest ordering easier to follow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Return 404 instead of 403 for view operations on deleted channels

Deleted channels should appear non-existent to callers rather than
revealing their existence via a 403. Detailed error text explains
the context for debugging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* add missing channel deleteat checks

* Use c.Params.Page instead of manual page query param parsing in getViewsForChannel

c.Params already validates and defaults page/per_page, so the manual
parsing was redundant.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add support for total count in views retrieval

* Add tests for handling deleted views in GetViewsForChannel and GetView

* Short-circuit negative newIndex in UpdateSortOrder before opening transaction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add per-channel limit on views to bound UpdateSortOrder cost

Without a cap, unbounded view creation makes sort-order updates
increasingly expensive (CASE WHEN per view, row locks). Adds
MaxViewsPerChannel=50 constant and enforces it in the app layer
before saving. Includes API and app layer tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Remove include_deleted support from views API

Soft-deleted views are structural metadata with low risk, but no other
similar endpoint (e.g. channel bookmarks) exposes deleted records without
an admin gate. Rather than adding an admin-only permission check for
consistency, remove the feature entirely since there is no current use case.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update view permissions to require `create_post` instead of channel management permissions

* Remove obsolete view management error messages for direct and group messages

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* feat(migrations): add user tracking and object type to property fields

- Introduced user tracking columns (CreatedBy, UpdatedBy) to PropertyFields and PropertyValues.
- Added ObjectType column to PropertyFields with associated unique indexes for legacy and typed properties.
- Created new migration scripts for adding and dropping these features, including necessary indexes for data integrity.
- Established views for managing property fields with new attributes.

This update enhances the schema to support better tracking and categorization of property fields.

* Add Property System Architecture v2 API endpoints (#35583)

* Adds uniqueness mechanisms to the property fields

After adding ObjectType, this commit ensures that both the PSAv1 and
PSAv2 schemas are supported, and enforces property uniqueness through
both database indexes and a logical check when creating new property
fields.

* Adds uniqueness check to property updates

Updates are covered on this commit and we refactor as well the SQL
code to use the squirrel builder and work better with the conditional
addition of the `existingID` piece of the query.

* Add translations to error messages

* Add the permissions to the migrations, model and update the store calls

* Adds the property field and property group app layer

* Adds authorization helpers for property fields and values

* Make sure that users cannot lock themselves out of property fields

* Migrate permissions from a JSON column to three normalized columns

* Remove the audit comment

* Use target level constants in authorization

* Log authorization membership failures

* Rename admin to sysadmin

* Adds the Property System Architecture v2 API endpoints

* Adds permission checks to the create field endpoint

* Add target access checks to value endpoints

* Add default branches for object_type and target_type and extra guards for cursor client4 methods

* Fix vet API mismatch

* Fix error checks

* Fix linter

* Add merge semantics for property patch logic and API endpoint

* Fix i18n

* Fix duplicated patch elements and early return on bad cursor

* Update docs to use enums

* Fix i18n sorting

* Update app layer to return model.AppError

* Adds a limit to the number of property values that can be patched in the same request

* Require target_type filter when searching property fields

* Add objectType validation as part of field.IsValid()

* Fix linter

* Fix test with bad objecttpye

* Fix test grouping

---------

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>

* MM-67968: Flatten view model — remove icon, subviews, typed board props (#35726)

* feat(views): flatten view model by removing icon, subview, and board props

Simplifies the View data model as part of MM-67968: removes Icon, Subview,
and ViewBoardProps types; renames ViewTypeBoard to ViewTypeKanban; replaces
typed Props with StringInterface (map[string]any); adds migration 000167
to drop the Icon column from the Views table.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* feat(api): update views OpenAPI spec to reflect flattened model

Removes ViewBoardProps, Subview, and icon from the View and ViewPatch
schemas. Changes type enum from board to kanban. Replaces typed props
with a free-form StringInterface object. Aligns with MM-67968.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* refactor(views): simplify store by dropping dbView and marshalViewProps

StringInterface already implements driver.Valuer and sql.Scanner, so the
manual JSON marshal/unmarshal and the dbView intermediate struct were
redundant. model.View now scans directly from the database. Also removes
the dead ViewMaxLinkedProperties constant and wraps the Commit() error in
UpdateSortOrder.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* fix(api): allow arbitrary JSON in view props OpenAPI schema

The props field was restricted to string values via
additionalProperties: { type: string }, conflicting with the Go model's
StringInterface (map[string]any). Changed to additionalProperties: true
in View, ViewPatch, and inline POST schemas.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* Adds basic implementation of the generic redux store for PSAv2 (#35512)

* Adds basic implementation of the generic redux store for PSAv2

* Add created_by and updated_by to the test fixtures

* Make target_id, target_type and object_type mandatory

* Wrap getPropertyFieldsByIds and getPropertyValuesForTargetByFieldIds with createSelector

* Address PR comments

---------

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>

* Adds websocket messages for the PSAv2 API events (#35696)

* Adds uniqueness mechanisms to the property fields

After adding ObjectType, this commit ensures that both the PSAv1 and
PSAv2 schemas are supported, and enforces property uniqueness through
both database indexes and a logical check when creating new property
fields.

* Adds uniqueness check to property updates

Updates are covered on this commit and we refactor as well the SQL
code to use the squirrel builder and work better with the conditional
addition of the `existingID` piece of the query.

* Add translations to error messages

* Add the permissions to the migrations, model and update the store calls

* Adds the property field and property group app layer

* Adds authorization helpers for property fields and values

* Make sure that users cannot lock themselves out of property fields

* Migrate permissions from a JSON column to three normalized columns

* Remove the audit comment

* Use target level constants in authorization

* Log authorization membership failures

* Rename admin to sysadmin

* Adds the Property System Architecture v2 API endpoints

* Adds permission checks to the create field endpoint

* Add target access checks to value endpoints

* Add default branches for object_type and target_type and extra guards for cursor client4 methods

* Fix vet API mismatch

* Fix error checks

* Fix linter

* Add merge semantics for property patch logic and API endpoint

* Fix i18n

* Fix duplicated patch elements and early return on bad cursor

* Update docs to use enums

* Fix i18n sorting

* Update app layer to return model.AppError

* Adds a limit to the number of property values that can be patched in the same request

* Adds websocket messages for the PSAv2 API events

* Add IsPSAv2 helper to the property field for clarity

* Add guard against nil returns on field deletion

* Add docs to the websocket endpoints

---------

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>

* migrations: consolidate views migrations and reorder after master

- Merged 000165 (create Views) with 000167 (drop Icon) since Icon was never needed
- Renumbered branch migrations 159-166 → 160-167 so master's 000159 (deduplicate_policy_names) runs first
- Regenerated migrations.list

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add API endpoint to retrieve posts for a specific view (#35604)

Automatic Merge

* Apply fixes after merge

* Return a more specific error from getting multiple fields

* Prevent getting broadcast params on field deletion if not needed

* Remove duplicated migration code

* Update property conflict code to always use master

* Adds nil guard when iterating on property fields

* Check that permission level is valid before getting rejected by the database

* Validate correctness on TargetID for PSAv2 fields

* Avoid PSAv1 using permissions or protected

* Fix test data after validation change

* Fix flaky search test

* Adds more posts for filter use cases to properly test exclusions

---------

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
Co-authored-by: Julien Tant <julien@craftyx.fr>
Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Julien Tant <785518+JulienTant@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 10:36:35 +01:00
Pablo Vélez
95e33dbc72
MM-63848: Enforce unique names for parent access control policies (#35676)
* MM-63848: Enforce unique names for parent access control policies

* Revert accidental package-lock.json change

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix translation file

* Fix lint shadows, migration overflow, and unique constraint fallback

* Remove pre-check, combine migrations, fix overflow

* Combine migrations using regular CREATE INDEX

* add missing translation

* kip revision bump on policy name-only changes and add test to cover this scenario

* MM-63848: Fix tx commit on name-only update, unique test names

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-03-25 05:12:13 -05:00
David Krauser
7425c6817b
[MM-67741] Scope role_updated WS events to affected team/channel (#35497)
With this change, we now scope role_updated websocket events to users that need to receive them. Built-in and unowned role broadcast globally, team-scheme roles emit one event per team using the role, channel-scheme roles emit one event per channel using the role.

To efficiently find a role's owning scheme, a schemeid column is added to the roles table. The ID is set when the scheme creates its related roles.
2026-03-16 14:36:55 -04:00
Ben Cooke
76b3528c2b
[MM-67231] Etag fixes for autotranslations (#35196)
Some checks are pending
API / build (push) Waiting to run
Server CI / Compute Go Version (push) Waiting to run
Server CI / Check mocks (push) Blocked by required conditions
Server CI / Check go mod tidy (push) Blocked by required conditions
Server CI / check-style (push) Blocked by required conditions
Server CI / Check serialization methods for hot structs (push) Blocked by required conditions
Server CI / Vet API (push) Blocked by required conditions
Server CI / Check migration files (push) Blocked by required conditions
Server CI / Generate email templates (push) Blocked by required conditions
Server CI / Check store layers (push) Blocked by required conditions
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres with binary parameters (push) Blocked by required conditions
Server CI / Postgres (push) Blocked by required conditions
Server CI / Postgres (FIPS) (push) Blocked by required conditions
Server CI / Generate Test Coverage (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
2026-02-09 18:32:26 -05:00
Ben Cooke
9ac02ecfdd
Update translation primary key to include objectType (#35040) 2026-02-05 15:00:08 -05:00
Daniel Espino García
1273632d1a
Add endpoint to update channel member autotranslations (#35072)
* Add endpoint to update channel member autotranslations

* Add several improvements and remove unneeded functions

* Add user id to audit record

* Ensure autotranslation is defined

* Update texts

* Fix merge

* Add new column for channel member autotranslations (#35111)

* Minor renamings

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Ben Cooke <benkcooke@gmail.com>
2026-02-05 13:43:50 +01:00
Ben Cooke
a1c85007e1
Autotranslations MVP (#34696)
---------

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Nick Misasi <nick.misasi@mattermost.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Matthew Birtch <mattbirtch@gmail.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-01-26 17:05:34 -05:00
Nick Misasi
8e4cadbc88
[MM-66359] Recaps MVP (#34337)
* initial commit for POC of Plugin Bridge

* Updates

* POC for plugin bridge

* Updates from collaboration

* Fixes

* Refactor Plugin Bridge to use HTTP/REST instead of RPC

- Remove ExecuteBridgeCall hook and Context.SourcePluginId
- Implement HTTP-based bridge using existing PluginHTTP infrastructure
- Add CallPlugin API method with endpoint parameter instead of method name
- Update CallPluginBridge to construct HTTP POST requests
- Add proper headers: Mattermost-User-Id, Mattermost-Plugin-ID
- Use 'com.mattermost.server' as plugin ID for core server calls
- Update ai.go to use REST endpoint /inter-plugin/v1/completion
- Add comprehensive spec documentation in server/spec.md
- Add MIGRATION_GUIDE.md for plugin developers
- Fix 401/404 issues by setting correct headers and URL paths

* Improve Plugin Bridge security and architecture

- Create ServeInternalPluginRequest for internal plugin calls (core + plugin-to-plugin)
- Move header-setting logic from CallPluginBridge to ServeInternalPluginRequest
- Improve separation of concerns: business logic vs HTTP transport
- Add security documentation explaining header protection

Security Improvements:
- ServeInternalPluginRequest is NOT exposed as HTTP route (internal only)
- Headers (Mattermost-User-Id, Mattermost-Plugin-ID) are set by trusted server code
- External requests cannot spoof these headers (stripped by servePluginRequest)
- Core calls use 'com.mattermost.server' as plugin ID for authorization
- Plugin-to-plugin calls use real plugin ID (enforced by server)

Backward Compatibility:
- Keep ServeInterPluginRequest for existing API.PluginHTTP callers (deprecated)
- All tests pass

Docs:
- Update spec.md with security model explanation
- Update MIGRATION_GUIDE.md with correct header usage examples

* Space

* cursor please stop creating markdown files

* Fix style

* Fix i18n, linter

* REMOVE MARKDOWN

* Remove CallPlugin method from plugin API interface

Per review feedback, this method is no longer needed.

Co-authored-by: Nick Misasi <nickmisasi@users.noreply.github.com>

* Remove CallPlugin method implementation from PluginAPI

Co-authored-by: Nick Misasi <nickmisasi@users.noreply.github.com>

* fixes

* Add AI OpenAPI spec

* fix openapi spec

* Use agents client (#34225)

* Use agents client

* Remove default agent

* Fixes

* fix: modify system prompts to ensure JSON is being returned

* Base implementation for recaps working

* small fixes

* Adjustments

* remove webapp changes

* Add feature flags for rewrites and ai bridge, clean up

* Remove comments that aren't helpful

* Fix i18n

* Remove rewrites

* Fix tests

* Fix i18n

* adjust i18n again

* Add back translations

* Remove leftover mock code

* remove model file

* Changes from PR review

* Make the real substitutions

* Include a basic invokation of the client with noop to ensure build works

* more fix

* Remove unneeded change

* Updates from review

* Fixes

* Remove some logic from rewrites to clean up branch

* Use v1.5.0 of agents plugin

* A bunch more additions for general UX flow

* Add missing files

* Add mocks

* Fixes for vet-api, i18n, build, types, etc

* One more linter fix

* Fix i18n and some tests

* Refactors and cleanup in backend code

* remove rogue markdown file

* fixes after refactors from backend

* Add back renamed files, and add tests

* More self code review

* More fixes

* More refactors

* Fix call stack exceeded bug

* Include read messages if there are no unreads

* Fix test failure: use correct error message key for recap permission denied

The getRecapAndCheckOwnership function was using strings.ToLower(callerName)
to generate error keys, which caused 'GetRecap' to become 'getrecap' instead
of the expected 'get'. Changed to use the correct static key that matches
the en.json localization file.

Fixes TestGetRecap/get_recap_by_non-owner test failure.

Co-authored-by: Nick Misasi <nickmisasi@users.noreply.github.com>

* Consolidate permission errors down to a single string

* Fixes for i18n, worktrees making this difficult

* Fix i18n

* Fix i18n once and for all (for real) (final)

* Fix duplicate getAgents method in client4.ts

* Remove duplicate ai state from initial_state.ts

* Fix types

* Fix tests

* Fix return type of GetAgents and GetServices

* Add tests for recaps components

* Fix types

* Update i18n

* Fixes

* Fixes

* More cleanup

* Revert random file

* Use undefined

* fix linter

* Address feedback

* Missed a git add

* Fixes

* Fix i18n

* Remove fallback

* Fixes for PR

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Nick Misasi <nickmisasi@users.noreply.github.com>
Co-authored-by: Christopher Speller <crspeller@gmail.com>
Co-authored-by: Felipe Martin <me@fmartingr.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-01-13 11:59:22 -05:00
Ibrahim Serdar Acikgoz
084006c0ea
[MM-61758] Burn on read feature (#34703)
Some checks are pending
API / build (push) Waiting to run
Server CI / Compute Go Version (push) Waiting to run
Server CI / Check mocks (push) Blocked by required conditions
Server CI / Check go mod tidy (push) Blocked by required conditions
Server CI / check-style (push) Blocked by required conditions
Server CI / Check serialization methods for hot structs (push) Blocked by required conditions
Server CI / Vet API (push) Blocked by required conditions
Server CI / Check migration files (push) Blocked by required conditions
Server CI / Generate email templates (push) Blocked by required conditions
Server CI / Check store layers (push) Blocked by required conditions
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres with binary parameters (push) Blocked by required conditions
Server CI / Postgres (push) Blocked by required conditions
Server CI / Postgres (FIPS) (push) Blocked by required conditions
Server CI / Generate Test Coverage (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
* Add read receipt store for burn on read message types

* update mocks

* fix invalidation target

* have consistent case on index creation

* Add temporary posts table

* add mock

* add transaction support

* reflect review comments

* wip: Add reveal endpoint

* user check error id instead

* wip: Add ws events and cleanup for burn on read posts

* add burn endpoint for explicitly burning messages

* add translations

* Added logic to associate files of BoR post with the post

* Added test

* fixes

* disable pinning posts and review comments

* MM-66594 - Burn on read UI integration (#34647)

* MM-66244 - add BoR visual components to message editor

* MM-66246 - BoR visual indicator for sender and receiver

* MM-66607 - bor - add timer countdown and autodeletion

* add the system console max time to live config

* use the max expire at and create global scheduler to register bor messages

* use seconds for BoR config values in BE

* implement the read by text shown in the tooltip logic

* unestack the posts from same receiver and BoR  and fix styling

* avoid opening reply RHS

* remove unused dispatchers

* persis the BoR label in the drafts

* move expiration value to metadata

* adjust unit tests to metadata insted of props

* code clean up and some performance improvements; add period grace for deletion too

* adjust migration serie number

* hide bor messages when config is off

* performance improvements on post component and code clean up

* keep bor existing post functionality if config is disabled

* Add read receipt store for burn on read message types

* Add temporary posts table

* add transaction support

* reflect review comments

* wip: Add reveal endpoint

* user check error id instead

* wip: Add ws events and cleanup for burn on read posts

* avoid reacting to unrevealed bor messages

* adjust migration number

* Add read receipt store for burn on read message types

* have consistent case on index creation

* Add temporary posts table

* add mock

* add transaction support

* reflect review comments

* wip: Add reveal endpoint

* user check error id instead

* wip: Add ws events and cleanup for burn on read posts

* add burn endpoint for explicitly burning messages

* adjust post reveal and type with backend changes

* use real config values, adjust icon usage and style

* adjust the delete from from sender and receiver

* improve self deleting logic by placing in badge, use burn endpoint

* adjust websocket events handling for the read by sender label information

* adjust styling for concealed and error state

* update burn-on-read post event handling for improved recipient tracking and multi-device sync

* replace burn_on_read with type in database migrations and model

* remove burn_on_read metadata from PostMetadata and related structures

* Added logic to associate files of BoR post with the post

* Added test

* adjust migration name and fix linter

* Add read receipt store for burn on read message types

* update mocks

* have consistent case on index creation

* Add temporary posts table

* add mock

* add transaction support

* reflect review comments

* wip: Add reveal endpoint

* user check error id instead

* wip: Add ws events and cleanup for burn on read posts

* add burn endpoint for explicitly burning messages

* Added logic to associate files of BoR post with the post

* Added test

* disable pinning posts and review comments

* show attachment on bor reveal

* remove unused translation

* Enhance burn-on-read post handling and refine previous post ID retrieval logic

* adjust the returning chunk to work with bor messages

* read temp post from master db

* read from master

* show the copy link button to the sender

* revert unnecessary check

* restore correct json tag

* remove unused error handling  and clarify burn-on-read comment

* improve type safety and use proper selectors

* eliminate code duplication in deletion handler

* optimize performance and add documentation

* delete bor message for sender once all receivers reveal it

* add burn on read to scheduled posts

* add feature enable check

* use master to avoid  all read recipients race condition

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Ibrahim Serdar Acikgoz <serdaracikgoz86@gmail.com>
Co-authored-by: Harshil Sharma <harshilsharma63@gmail.com>

* squash migrations into single file

* add configuration for the scheduler

* don't run messagehasbeenposted hook

* remove parallel tests on burn on read

* add clean up for closing opened modals from previous tests

* simplify delete menu item rendering

* add cleanup step to close open modals after each test to prevent pollution

* streamline delete button visibility logic for Burn on Read posts

* improve reliability of closing post menu and modals by using body ESC key

---------

Co-authored-by: Harshil Sharma <harshilsharma63@gmail.com>
Co-authored-by: Pablo Vélez <pablovv2012@gmail.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2025-12-11 07:59:50 +01:00
Elias Nahum
1022cd44c0
MM-65756 Database Migrations, Indexes and Methods for Auto-Translation (#34047)
Some checks failed
API / build (push) Has been cancelled
Server CI / Compute Go Version (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / test (push) Has been cancelled
Web App CI / build (push) Has been cancelled
Server CI / Check mocks (push) Has been cancelled
Server CI / Check go mod tidy (push) Has been cancelled
Server CI / check-style (push) Has been cancelled
Server CI / Check serialization methods for hot structs (push) Has been cancelled
Server CI / Vet API (push) Has been cancelled
Server CI / Check migration files (push) Has been cancelled
Server CI / Generate email templates (push) Has been cancelled
Server CI / Check store layers (push) Has been cancelled
Server CI / Check mmctl docs (push) Has been cancelled
Server CI / Postgres with binary parameters (push) Has been cancelled
Server CI / Postgres (push) Has been cancelled
Server CI / Postgres (FIPS) (push) Has been cancelled
Server CI / Generate Test Coverage (push) Has been cancelled
Server CI / Run mmctl tests (push) Has been cancelled
Server CI / Run mmctl tests (FIPS) (push) Has been cancelled
Server CI / Build mattermost server app (push) Has been cancelled
* AutoTranslate config settings

* comment out Agents provider

* Add auto translate timeout config validation

* i18n messages for autotranslation config validation

* fix test

* validate url for libreTranslate

* Feedback review

* Admin Console UI for Auto-Translation

* fix admin console conditional section display

* i18n

* removed unintentional change

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* update admin.general.localization.autoTranslateProviderDescription newline

* fix lint

* Fix types

* UX feedback review

* fix typo in i18n

* Fix AutoTranslation feature flag

* feedback review

* Fix test default values

* feedback review

* re-add isHidden property to feature discovery

* Database Migrations, Indexes and Methods for Auto-Translation

* i18n

* fix retrylayer and storetest

* Fix search query

* fix lint

* remove the request.CTX and modify Translation model

* fix lint and external url

* Add settings to playwright

* Add empty as a valid value for the Provider

* Update jsonb queries

* Fix queries and add model methods

* fix go lint

* go lint fix 2

* fix db migrations

* feedback review + store cache

* increase migration number

* cleanup autotranslation store cache

* use NULL as objectType for posts

* fix bad merge

* fix tests

* add missing i18n

* Switch prop bags column to boolean

* fix lint

* fix tests

* Remove database search

* use Builder methods

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: BenCookie95 <benkcooke@gmail.com>
2025-11-22 09:32:01 +08:00
Ben Cooke
3aad6b0448
Add support for resource parameter with OAuth (#33743) 2025-11-11 15:24:42 -05:00
Ben Cooke
a79ac96b50
OAuth public client support through DCR and PKCE support for public/confidential clients (#33664)
* public client support along with PKCE for public/confidential clients

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2025-11-11 17:43:37 +00:00
Ben Cooke
a9c9953439
Authorization metadata endpoint and Dynamic Client Registration of Confidential OAuth Apps (#33642)
Some checks are pending
API / build (push) Waiting to run
Server CI / Compute Go Version (push) Waiting to run
Server CI / Check mocks (push) Blocked by required conditions
Server CI / Check go mod tidy (push) Blocked by required conditions
Server CI / check-style (push) Blocked by required conditions
Server CI / Check serialization methods for hot structs (push) Blocked by required conditions
Server CI / Vet API (push) Blocked by required conditions
Server CI / Check migration files (push) Blocked by required conditions
Server CI / Generate email templates (push) Blocked by required conditions
Server CI / Check store layers (push) Blocked by required conditions
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres with binary parameters (push) Blocked by required conditions
Server CI / Postgres (push) Blocked by required conditions
Server CI / Postgres (FIPS) (push) Blocked by required conditions
Server CI / Generate Test Coverage (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Waiting to run
Web App CI / check-types (push) Waiting to run
Web App CI / test (push) Waiting to run
Web App CI / build (push) Waiting to run
* initial DCR and metadata implementation

* check for duplicate registrations

* tests and other cleanup

* dcr fixes

* tidy up unused DCR fields

* remove initial access token support

* remove duplicate client checks

* remove unused store function

* remove restrictive redirect url checks

* create some constants for endpoints

* surface support for implicit grant and add system console setting

* fix frontend issues with DCR clients

* rate limiting the DCR endpoint

* lint

* lint and cleanup

* remove storage of grants, responses and methods. Just enforce in the code

* fix lint and tests

* docs and test

* accidentally removed comments

* fix mock

* translations

* do not advertise public client capability

* validate supplied token_endpoint_auth_method

* fix pr comments

* updates

* add metadata endpoint to docs

* add definition

* lint

* fix client4

* fix client methods

* fix client again

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2025-11-11 14:27:18 +00:00
Harshil Sharma
3265054ad5
Migrate content flagging settings to database (#33989)
Some checks failed
API / build (push) Waiting to run
Server CI / Compute Go Version (push) Waiting to run
Server CI / Check mocks (push) Blocked by required conditions
Server CI / Check go mod tidy (push) Blocked by required conditions
Server CI / check-style (push) Blocked by required conditions
Server CI / Check serialization methods for hot structs (push) Blocked by required conditions
Server CI / Vet API (push) Blocked by required conditions
Server CI / Check migration files (push) Blocked by required conditions
Server CI / Generate email templates (push) Blocked by required conditions
Server CI / Check store layers (push) Blocked by required conditions
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres with binary parameters (push) Blocked by required conditions
Server CI / Postgres (push) Blocked by required conditions
Server CI / Postgres (FIPS) (push) Blocked by required conditions
Server CI / Generate Test Coverage (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Waiting to run
Web App CI / check-types (push) Waiting to run
Web App CI / test (push) Waiting to run
Web App CI / build (push) Waiting to run
Migration-assist Sync / Check if migration-assist have been synced (push) Has been cancelled
* lint fix

* CI

* added new migration mocks

* Used setup for tests

* some comment

* Removed unnecesseery nil check

* Form validation

* WIP tests

* WIP tests

* WIP tests

* fix: mock content flagging config selector with correct reasons format

Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <aider@aider.chat>

* fix: add mock for getContentFlaggingConfig in flag post modal test

Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <aider@aider.chat>

* Updated error code order in API docs

* removed empty files

* Added tests

* lint fixes

* minor tweak

* lint fix

* type fix

* fixed test

* nit

* test enhancements

* API WIP

* API WIP

* creating values

* creating content flagging channel and properties

* Able to save properties

* Added another property field

* WIP

* WIP

* Added validations

* Added data validations and hidden post if confifgured to

* lint fixes

* Added API spec

* Added some tests

* Added tests for getContentReviewBot

* test: add comprehensive tests for getContentReviewChannels function

* Added more app layer tests

* Added TestCanFlagPost

* test: Add comprehensive tests for FlagPost function

* Added all app layer tests

* Removed a file that was reamoved downstream

* test: add content flagging test file

* test: add comprehensive tests for FlagContentRequest.IsValid method

* Added model tests

* test: add comprehensive tests for SqlPropertyValueStore.CreateMany

* test: add comprehensive tests for flagPost() API function

* Added API tests

* linter fix

* WIP

* sent post flagging confirmation message

* fixed i18n nissues

* fixed i18n nissues

* CI

* WIP

* WIP

* Added API call

* test: add test for Client4.flagPost API call in FlagPostModal

* fix: remove userEvent.setup() from flag post modal test

* test: wrap submit button click in act for proper state updates

* Updated tests

* lint fix

* Updated test

* fix: reset contentFlaggingGroupId for test isolation in content flagging tests

* removed cached group ID

* removed debug log

* CI

* Updated to allow special characters in comments

* Handled empty comment

* Created getContentFlaggingFields API

* created getPostPropertyValues API

* Used finally

* WIP

* Created useContentFlaggingFields hook

* WIP

* WIP

* Added option to retain data for reviewers

* Displayed deleted post's preview

* DIsplayed all properties

* Adding field name i18n

* WIP - managing i18n able texts

* Finished displaying all fields

* Manual cleanup

* lint fixes

* team role filter logic fix

* Fixed tests

* created new API to fetch flagged posts

* lint fix

* Added new client methods

* test: add comprehensive tests for content flagging APIs

* Added new API tests

* fixed openapi spec

* Fixed DataSpillageReport tests

* Fixed PostMarkdown test

* Fixed PostPreviewPropertyRenderer test

* Added metadata to card renderer

* test fixes

* Added no comment placeholder

* Added view detail button

* Created RemoveFlaggedMessageConfirmationModal modal

* Added key and remove flag request modal

* IMplemented delete flagged post

* Handled edge cases of deleting flagged post

* keep message

* UI integration

* Added WS event for post report update and handled deleted files of flagged post

* Added error handling in keep/remove forms

* i18n fixes

* Fixed test

* Updated OpenAPI specs

* fixed types

* fixed types

* refactoring

* refactor: improve test mocking for data spillage report component

* test mock updates

* Fixed tests

* Updated reducer

* not resetting mocks

* Added migrations for content flagging tables

* Created new structure

* review fixes

* Used correct ot name

* WIP

* review fixes

* review fixes

* Added new property translations

* CI

* CI

* CI

* Improved test

* fixed test

* CI

* New UI component

* WIP

* Updated settings APIs

* cached DB data

* used cached reviewer data

* Updated tests

* Lint fixes

* test: add tests for saveContentFlaggingSettings and getContentFlaggingSettings APIs

* test fix

* test: add tests for SaveContentFlaggingConfig and GetContentFlaggingConfigReviewerIDs

* Updated tests

* test: add content flagging test for local cache layer

* test: add comprehensive tests for content flagging store cache

* Updated tests

* lint fix

* Updated mobile text

* Added content flagging SQL store mocks

* Added API specs for new APIs

* fixed tests

* feat: add TestContentFlaggingStore function for content flagging store testing

* feat: add comprehensive tests for content flagging store

* Added SQL store tests

* test: add content flagging test for local cache layer

* test: add tests for content flagging store caching

* Added cache layer tests

* Updated tests

* Fixed

* Handled JSON error

* fixes

* fixes

* Fixed retry layer test

* fixerdf i18n

* Fixed test

* CI

* building index concurrently

* CI

* fixed a test

* CI

* cleanup

* Integrate flag post api (#33798)

* WIP

* WIP

* Added API call

* test: add test for Client4.flagPost API call in FlagPostModal

* fix: remove userEvent.setup() from flag post modal test

* test: wrap submit button click in act for proper state updates

* Updated tests

* lint fix

* CI

* Updated to allow special characters in comments

* Handled empty comment

* Used finally

* CI

* Fixed test

* Spillage card integration (#33832)

* Created getContentFlaggingFields API

* created getPostPropertyValues API

* WIP

* Created useContentFlaggingFields hook

* WIP

* WIP

* Added option to retain data for reviewers

* Displayed deleted post's preview

* DIsplayed all properties

* Adding field name i18n

* WIP - managing i18n able texts

* Finished displaying all fields

* Manual cleanup

* lint fixes

* team role filter logic fix

* Fixed tests

* created new API to fetch flagged posts

* lint fix

* Added new client methods

* test: add comprehensive tests for content flagging APIs

* Added new API tests

* fixed openapi spec

* Fixed DataSpillageReport tests

* Fixed PostMarkdown test

* Fixed PostPreviewPropertyRenderer test

* Added metadata to card renderer

* test fixes

* Added no comment placeholder

* Fixed test

* refactor: improve test mocking for data spillage report component

* test mock updates

* Updated reducer

* not resetting mocks

* WIP

* review fixes

* CI

* Fixed

* fixes

* Content flagging actions implementation (#33852)

* Added view detail button

* Created RemoveFlaggedMessageConfirmationModal modal

* Added key and remove flag request modal

* IMplemented delete flagged post

* Handled edge cases of deleting flagged post

* keep message

* UI integration

* Added WS event for post report update and handled deleted files of flagged post

* Added error handling in keep/remove forms

* i18n fixes

* Updated OpenAPI specs

* fixed types

* fixed types

* refactoring

* Fixed tests

* review fixes

* Added new property translations

* Improved test

* fixed test

* CI

* fixes

* CI

* fixed a test

* CI

* Review fixes

---------

Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <aider@aider.chat>
2025-10-13 12:24:01 +05:30
Agniva De Sarker
9dd8c056e7
MM-63368: Remove MySQL (#33458)
https://mattermost.atlassian.net/browse/MM-63368

```release-note
Remove MySQL support from the codebase entirely.
```
2025-07-22 20:40:55 +05:30
catalintomai
85391de22a
MM-57326: [Shared Channels] Message priority, acknowledgement and persistent notifications need to be synced (#30736) 2025-06-16 02:30:21 +02:00
catalintomai
fa1c77d9b0
MM-52600: [Shared Channels] Shared channels do not sync channel membership (#30976) 2025-06-15 10:07:56 +02:00
catalintomai
c46ed6c681
MM-62751: [Shared Channels] Allow remote users to be discoverable in the create DM/GM modal (#30918) 2025-06-13 16:51:12 +02:00
Devin Binnie
25a4839a9e
Automatic channel category sorting (#30866)
* Automatic channel category sorting

* Fix types

* AIed

* Fix issue where categories are updated for all users

* Move all logic to server, clean up

* PR feedback

* Fix lint

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2025-06-11 14:29:36 -04:00
Ibrahim Serdar Acikgoz
1cf2f08108
[MM-64437] Hotfix on attribute view creation error (#31225) 2025-05-30 11:35:31 +02:00
Ibrahim Serdar Acikgoz
a344b3225b
[MM-61756] Attribute Based Access Control - Phase 1 (#30785)
Attribute Based Access Control - Base
* MM-63662

* MM-63919

* MM-63954

* MM-63955 

* MM-63425

* MM-63426

* MM-63458

* MM-63459

* MM-63603

* MM-63845

* MM-64146

* MM-64199

* MM-64201

* MM-64233

* MM-64247

* MM-64268

---------

Co-authored-by: Harshil Sharma <harshilsharma63@gmail.com>
Co-authored-by: Pablo Andrés Vélez Vidal <pablovv2012@gmail.com>
Co-authored-by: abhijit-singh <abhijitsingh0702@gmail.com>
Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com>
2025-05-15 11:33:08 +02:00
Agniva De Sarker
131cf039bb
MM-63756: Added index to sidebarchannels table (#30724)
The (s SqlChannelStore) getSidebarCategoriesT gets called quite frequently.
- Team switch
- WS reconnect
- Category created
- Category updated
- Category deleted

Of these 1 and 2 are probably the most commonly called sources. Based on that,
the sidebarChannels table is not that well-optimized. Even though
the query time might be reasonable, without an index, it has to churn a lot of
DB CPU for a sequential scan.

We add a new index to optimize this.

CREATE INDEX idx_sidebarchannels_categoryid ON sidebarchannels(categoryid);

```
Before:
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=40854.18..40854.19 rows=4 width=193) (actual time=251.635..251.646 rows=204 loops=1)
   Sort Key: sidebarcategories.sortorder, sidebarchannels.sortorder
   Sort Method: quicksort  Memory: 65kB
   Buffers: shared hit=1203 read=23668
   ->  Nested Loop  (cost=8.87..40854.14 rows=4 width=193) (actual time=251.345..251.455 rows=204 loops=1)
         Buffers: shared hit=1203 read=23668
         ->  Nested Loop  (cost=0.41..9.47 rows=1 width=54) (actual time=0.068..0.074 rows=1 loops=1)
               Buffers: shared hit=5
               ->  Seq Scan on teams  (cost=0.00..1.03 rows=1 width=27) (actual time=0.024..0.026 rows=1 loops=1)
                     Filter: (((id)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text) AND (deleteat = 0))
                     Rows Removed by Filter: 1
                     Buffers: shared hit=1
               ->  Index Scan using teammembers_pkey on teammembers  (cost=0.41..8.43 rows=1 width=27) (actual time=0.039..0.043 rows=1 loops=1)
                     Index Cond: (((teamid)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text) AND ((userid)::text = 'tc3p1yqw67d8idcp3g98awexqe'::text))
                     Filter: (deleteat = 0)
                     Buffers: shared hit=4
         ->  Hash Right Join  (cost=8.45..40844.62 rows=4 width=193) (actual time=251.274..251.361 rows=204 loops=1)
               Hash Cond: ((sidebarchannels.categoryid)::text = (sidebarcategories.id)::text)
               Buffers: shared hit=1198 read=23668
               ->  Seq Scan on sidebarchannels  (cost=0.00..37514.77 rows=1265277 width=100) (actual time=0.043..99.345 rows=1265444 loops=1)
                     Buffers: shared hit=1194 read=23668
               ->  Hash  (cost=8.44..8.44 rows=1 width=158) (actual time=0.047..0.047 rows=6 loops=1)
                     Buckets: 1024  Batches: 1  Memory Usage: 10kB
                     Buffers: shared hit=4
                     ->  Index Scan using idx_sidebarcategories_userid_teamid on sidebarcategories  (cost=0.42..8.44 rows=1 width=158) (actual time=0.029..0.037 rows=6 loops=1)
                           Index Cond: (((userid)::text = 'tc3p1yqw67d8idcp3g98awexqe'::text) AND ((teamid)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text))
                           Buffers: shared hit=4
 Planning:
   Buffers: shared hit=9
 Planning Time: 1.215 ms
 Execution Time: 251.755 ms
(31 rows)

After:
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=1544.53..1544.54 rows=4 width=192) (actual time=0.834..0.859 rows=204 loops=1)
   Sort Key: sidebarcategories.sortorder, sidebarchannels.sortorder
   Sort Method: quicksort  Memory: 65kB
   Buffers: shared hit=58
   ->  Nested Loop Left Join  (cost=8.53..1544.49 rows=4 width=192) (actual time=0.066..0.252 rows=204 loops=1)
         Buffers: shared hit=58
         ->  Nested Loop  (cost=0.83..17.93 rows=1 width=157) (actual time=0.042..0.098 rows=6 loops=1)
               Buffers: shared hit=34
               ->  Nested Loop  (cost=0.42..9.48 rows=1 width=157) (actual time=0.030..0.049 rows=6 loops=1)
                     Buffers: shared hit=10
                     ->  Index Scan using idx_sidebarcategories_userid_teamid on sidebarcategories  (cost=0.42..8.44 rows=1 width=157) (actual time=0.018..0.022 rows=6 loops=1)
                           Index Cond: (((userid)::text = 'tc3p1yqw67d8idcp3g98awexqe'::text) AND ((teamid)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text))
                           Buffers: shared hit=4
                     ->  Seq Scan on teams  (cost=0.00..1.03 rows=1 width=27) (actual time=0.002..0.003 rows=1 loops=6)
                           Filter: (((id)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text) AND (deleteat = 0))
                           Rows Removed by Filter: 1
                           Buffers: shared hit=6
               ->  Index Scan using teammembers_pkey on teammembers  (cost=0.41..8.43 rows=1 width=27) (actual time=0.007..0.007 rows=1 loops=6)
                     Index Cond: (((teamid)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text) AND ((userid)::text = 'tc3p1yqw67d8idcp3g98awexqe'::text))
                     Filter: (deleteat = 0)
                     Buffers: shared hit=24
         ->  Bitmap Heap Scan on sidebarchannels  (cost=7.69..1522.35 rows=421 width=100) (actual time=0.012..0.017 rows=34 loops=6)
               Recheck Cond: ((categoryid)::text = (sidebarcategories.id)::text)
               Heap Blocks: exact=6
               Buffers: shared hit=24
               ->  Bitmap Index Scan on idx_sidebarchannels_categoryid  (cost=0.00..7.58 rows=421 width=0) (actual time=0.010..0.010 rows=34 loops=6)
                     Index Cond: ((categoryid)::text = (sidebarcategories.id)::text)
                     Buffers: shared hit=18
 Planning:
   Buffers: shared hit=18
 Planning Time: 0.543 ms
 Execution Time: 0.968 ms
(32 rows)
```

I have also looked at potentially re-ordering the JOINs to make
sidebarchannels and sidebarcategories JOIN earlier, but that didn't give
a major benefit.

Also looked at adding a compound index with (categoryid, sortorder) to improve
sorting performance, but that didn't give a major benefit from what the single
column index already gives.

The `completePopulatingCategoryChannelsT` query also partially benefits
from this. But the Postgres optimizer sometimes selects the index on categoryId
and sometimes on ChannelId, both giving equivalent performance. So there's no major
improvement there, but at the same time, no regression as well.

```
Original:
[bigdb] # EXPLAIN (ANALYZE, BUFFERS) SELECT Id FROM ChannelMembers LEFT JOIN Channels ON Channels.Id=ChannelMembers.ChannelId WHERE (ChannelMembers.UserId = 'tc3p1yqw67d8idcp3g98awexqe' AND Channels.Type IN ('D'
                                                                                                                                                                                                                ,'G') AND Channels.DeleteAt = 0 AND NOT EXISTS ( SELECT 1 FROM SidebarChannels JOIN SidebarCategories on SidebarChannels.CategoryId=SidebarCategories.Id WHERE (SidebarChannels.ChannelId = ChannelMembers.ChannelI
                                                                                                                                                                                                                                                                                                                                                                                d AND SidebarCategories.UserId = 'tc3p1yqw67d8idcp3g98awexqe' AND SidebarCategories.TeamId = '3ee5y5ok6jgxicrmqstdnghmfr') )) ORDER BY DisplayName ASC;
                                                                                            QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=5864.68..5865.84 rows=463 width=40) (actual time=9.008..9.022 rows=39 loops=1)
   Sort Key: channels.displayname
   Sort Method: quicksort  Memory: 27kB
   Buffers: shared hit=2112
   ->  Nested Loop Anti Join  (cost=1.96..5844.18 rows=463 width=40) (actual time=0.188..8.932 rows=39 loops=1)
         Buffers: shared hit=2112
         ->  Nested Loop  (cost=0.99..3476.66 rows=463 width=67) (actual time=0.159..7.952 rows=39 loops=1)
               Buffers: shared hit=1956
               ->  Index Only Scan using idx_channelmembers_user_id_channel_id_last_viewed_at on channelmembers  (cost=0.56..40.78 rows=470 width=27) (actual time=0.036..0.467 rows=437 loops=1)
                     Index Cond: (userid = 'tc3p1yqw67d8idcp3g98awexqe'::text)
                     Heap Fetches: 45
                     Buffers: shared hit=208
               ->  Memoize  (cost=0.43..7.69 rows=1 width=40) (actual time=0.016..0.016 rows=0 loops=437)
                     Cache Key: channelmembers.channelid
                     Cache Mode: logical
                     Hits: 0  Misses: 437  Evictions: 0  Overflows: 0  Memory Usage: 42kB
                     Buffers: shared hit=1748
                     ->  Index Scan using channels_pkey on channels  (cost=0.42..7.68 rows=1 width=40) (actual time=0.015..0.015 rows=0 loops=437)
                           Index Cond: ((id)::text = (channelmembers.channelid)::text)
                           Filter: ((type = ANY ('{D,G}'::channel_type[])) AND (deleteat = 0))
                           Rows Removed by Filter: 1
                           Buffers: shared hit=1748
         ->  Nested Loop  (cost=0.97..5.10 rows=1 width=27) (actual time=0.023..0.023 rows=0 loops=39)
               Buffers: shared hit=156
               ->  Index Only Scan using sidebarchannels_pkey on sidebarchannels  (cost=0.55..4.56 rows=1 width=92) (actual time=0.022..0.022 rows=0 loops=39)
                     Index Cond: (channelid = (channelmembers.channelid)::text)
                     Heap Fetches: 0
                     Buffers: shared hit=156
               ->  Index Scan using sidebarcategories_pkey on sidebarcategories  (cost=0.42..0.48 rows=1 width=65) (never executed)
                     Index Cond: ((id)::text = (sidebarchannels.categoryid)::text)
                     Filter: (((userid)::text = 'tc3p1yqw67d8idcp3g98awexqe'::text) AND ((teamid)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text))
 Planning:
   Buffers: shared hit=48 dirtied=1
 Planning Time: 2.222 ms
 Execution Time: 9.142 ms
(35 rows)

New:
[bigdb] # EXPLAIN (ANALYZE, BUFFERS) SELECT Id FROM ChannelMembers LEFT JOIN Channels ON Channels.Id=ChannelMembers.ChannelId WHERE (ChannelMembers.UserId = 'tc3p1yqw67d8idcp3g98awexqe' AND Channels.Type IN ('D'
                                                                                                                                                                                                                ,'G') AND Channels.DeleteAt = 0 AND NOT EXISTS ( SELECT 1 FROM SidebarChannels JOIN SidebarCategories on SidebarChannels.CategoryId=SidebarCategories.Id WHERE (SidebarChannels.ChannelId = ChannelMembers.ChannelId AND SidebarCategories.UserId = 'tc3p1yqw67d8idcp3g98awexqe' AND SidebarCategories.TeamId = '3ee5y5ok6jgxicrmqstdnghmfr') )) ORDER BY DisplayName ASC;
                                                                                            QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=5059.95..5061.11 rows=463 width=40) (actual time=12.072..12.086 rows=39 loops=1)
   Sort Key: channels.displayname
   Sort Method: quicksort  Memory: 27kB
   Buffers: shared hit=1984
   ->  Nested Loop Anti Join  (cost=9.10..5039.45 rows=463 width=40) (actual time=0.751..12.009 rows=39 loops=1)
         Join Filter: ((sidebarchannels.channelid)::text = (channelmembers.channelid)::text)
         Rows Removed by Join Filter: 7839
         Buffers: shared hit=1984
         ->  Nested Loop  (cost=0.99..3476.66 rows=463 width=67) (actual time=0.161..7.579 rows=39 loops=1)
               Buffers: shared hit=1956
               ->  Index Only Scan using idx_channelmembers_user_id_channel_id_last_viewed_at on channelmembers  (cost=0.56..40.78 rows=470 width=27) (actual time=0.036..0.449 rows=437 loops=1)
                     Index Cond: (userid = 'tc3p1yqw67d8idcp3g98awexqe'::text)
                     Heap Fetches: 45
                     Buffers: shared hit=208
               ->  Memoize  (cost=0.43..7.69 rows=1 width=40) (actual time=0.016..0.016 rows=0 loops=437)
                     Cache Key: channelmembers.channelid
                     Cache Mode: logical
                     Hits: 0  Misses: 437  Evictions: 0  Overflows: 0  Memory Usage: 42kB
                     Buffers: shared hit=1748
                     ->  Index Scan using channels_pkey on channels  (cost=0.42..7.68 rows=1 width=40) (actual time=0.014..0.014 rows=0 loops=437)
                           Index Cond: ((id)::text = (channelmembers.channelid)::text)
                           Filter: ((type = ANY ('{D,G}'::channel_type[])) AND (deleteat = 0))
                           Rows Removed by Filter: 1
                           Buffers: shared hit=1748
         ->  Materialize  (cost=8.11..1535.03 rows=4 width=27) (actual time=0.003..0.046 rows=201 loops=39)
               Buffers: shared hit=28
               ->  Nested Loop  (cost=8.11..1535.01 rows=4 width=27) (actual time=0.099..0.383 rows=201 loops=1)
                     Buffers: shared hit=28
                     ->  Index Scan using idx_sidebarcategories_userid_teamid on sidebarcategories  (cost=0.42..8.44 rows=1 width=65) (actual time=0.047..0.057 rows=6 loops=1)
                           Index Cond: (((userid)::text = 'tc3p1yqw67d8idcp3g98awexqe'::text) AND ((teamid)::text = '3ee5y5ok6jgxicrmqstdnghmfr'::text))
                           Buffers: shared hit=4
                     ->  Bitmap Heap Scan on sidebarchannels  (cost=7.69..1522.35 rows=421 width=92) (actual time=0.028..0.040 rows=34 loops=6)
                           Recheck Cond: ((categoryid)::text = (sidebarcategories.id)::text)
                           Heap Blocks: exact=6
                           Buffers: shared hit=24
                           ->  Bitmap Index Scan on idx_sidebarchannels_categoryid  (cost=0.00..7.58 rows=421 width=0) (actual time=0.023..0.023 rows=34 loops=6)
                                 Index Cond: ((categoryid)::text = (sidebarcategories.id)::text)
                                 Buffers: shared hit=18
 Planning:
   Buffers: shared hit=51
 Planning Time: 2.240 ms
 Execution Time: 12.210 ms
(42 rows)
```

Analysis on MySQL for completion:
```
Before:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Sort: SidebarCategories.SortOrder, SidebarChannels.SortOrder  (actual time=277.675..277.675 rows=4 loops=1)
    -> Stream results  (cost=138558.36 rows=1287808) (actual time=242.506..277.650 rows=4 loops=1)
        -> Left hash join (<hash>(SidebarChannels.CategoryId)=<hash>(SidebarCategories.Id)), extra conditions: (SidebarChannels.CategoryId = SidebarCategories.Id)  (cost=138558.36 rows=1287808) (actual time=242.498..277.626 rows=4 loops=1)
            -> Index lookup on SidebarCategories using idx_sidebarcategories_userid_teamid (UserId='qdggj9pyobgkjpj8htwzizks1r', TeamId='xmh7bupzajnudqf3h4mm76qapy')  (cost=1.40 rows=4) (actual time=0.092..0.094 rows=4 loops=1)
            -> Hash
                -> Table scan on SidebarChannels  (cost=8394.55 rows=321952) (actual time=0.123..106.334 rows=300002 loops=1)
 |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

After:
----------------------------------------------------------------+
| -> Sort: SidebarCategories.SortOrder, SidebarChannels.SortOrder  (actual time=0.739..0.742 rows=4 loops=1)
    -> Stream results  (cost=6.80 rows=7) (actual time=0.468..0.703 rows=4 loops=1)
        -> Nested loop left join  (cost=6.80 rows=7) (actual time=0.456..0.673 rows=4 loops=1)
            -> Index lookup on SidebarCategories using idx_sidebarcategories_userid_teamid (UserId='qdggj9pyobgkjpj8htwzizks1r', TeamId='xmh7bupzajnudqf3h4mm76qapy')  (cost=4.38 rows=4) (actual time=0.302..0.313 rows=4 loops=1)
            -> Index lookup on SidebarChannels using idx_sidebarchannels_categoryid (CategoryId=SidebarCategories.Id)  (cost=0.48 rows=2) (actual time=0.085..0.087 rows=0 loops=4)
 |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
```

Timing wise, it takes around 2s to add the index on a table with 1.2M rows
for Postgres. And it takes around 5s on MySQL on a table with 300K rows.
It looks like it takes longer on MySQL, but since both migrations are
non-locking, it should be fine.

https://mattermost.atlassian.net/browse/MM-63756
```release-note
NONE
```
2025-04-24 12:11:28 +05:30
Ibrahim Serdar Acikgoz
10b1f4c5ac
[MM-63428] add access control policy store (#30597) 2025-04-02 13:39:28 +02:00
Harshil Sharma
6e738f489f
Channel banner sql migrations (#30274)
* Adde MySQL and Postgres migrations

* Replaced select * with column names

* removed all * from channel SQL store

* cleanup

* Fixed a duplicate column

* cleanup

* Added migrations and store support

* WIP

* used channelname slice in a missed place

* Handled patch

* Added app level tests

* Added API layer tests

* Added API layer tests

* WIP

* converted to query builder

* cleanupo

* added not null and default constraints

* Fixed test

* fixed file name

* review fixes

* review fixes

* updated migration file

* fixed text

* Review fixes
2025-02-25 14:52:15 +05:30
Julien Tant
632a60b332
[MM-62553]+[MM-62554] Property Architecture: cursor based pagination (#30119)
* refactor: Replace pagination with cursor-based pagination for custom profile attributes

* remove pagination loop on property value retrieval for CPA

* add migrations to optimize pagination on property fields and values

* adapt test to remove pagination check

* update migrations list

* postgres: drop index concurrently

* concurrent index manipulation must be done outside of a Tx

* fix: Correct SQL index drop syntax from "OM" to "ON" in migration files

* test: Add CountForGroup test cases for property field store

* refactor: Add CountForGroup method to PropertyFieldStore interface and implementations

* Fix style and i18n

* feat: Add optional deleted property field filtering to CountForGroup method

* refactor: Update CountForGroup to support optional deleted property fields

* test: Add comprehensive tests for CountForGroup with includeDeleted parameter

* adapt test + gen layers

* rename property service method and set the includeDelete to false

* refactor: Remove redundant constant and use CustomProfileAttributesFieldLimit directly

* fix tests

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2025-02-13 15:23:50 +00:00
Agniva De Sarker
ae9e6174e5
[AI assisted]: Improve system console statistics performance (#29899)
```release-note
NONE
```

Co-authored-by: Matthew Birtch <mattbirtch@gmail.com>
2025-02-04 21:54:01 +05:30
Miguel de la Cruz
ecdce71fc4
Adds the main Property System Architecture components (#29644)
* Adds the main Property System Architecture components

This change adds the necessary migrations for the Property Groups,
Fields and Values tables to be created, the store layer and a Property
Service that can be used from the app layer.

* Update property field type to use user instead of person

* Update PropertyFields to allow for unique nondeleted fields and remove redundant indexes

* Update PropertyValues to allow for unique nondeleted fields and remove redundant indexes

* Use StringMap instead of the map[string]any on property fields

* Add i18n strings

* Revert "Use StringMap instead of the map[string]any on property fields"

This reverts commit e2735ab0f8.

* Cast JSON binary data to string and add todo note for StringMap use

* Add mocks to the retrylayer tests

* Cast JSON binary data to string in property value store

* Check for binary parameter instead of casting to string for JSON data

* Check property field type is one of the allowed ones

* Avoid reusing err variable to be explicit about the returned value

* Merge Property System Migrations into one file

* Adds NOT NULL to timestamps at the DB level

* Update stores to use tableSelectQuery instead of a slice var

* Update PropertyField model translations to be more explicit and avoid repetition

* Update PropertyValue model translations to be more explicit and avoid repetition

* Use ExecBuilder instead of ToSql&Exec

* Update property field errors to add context

* Ensure PerPage is greater than zero

* Update store errors to give more context

* Use ExecBuilder in the property stores where possible

* Add an on conflict suffix to the group register to avoid race conditions

* Remove badly used translation string

* Remove unused get in register group method

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2025-01-13 11:41:44 +00:00
Harshil Sharma
e281b3f37e
Feature scheduled messages (#28932)
* Create scheduled post api (#27920)

* Added migration files for Postgres

* Added migrations for MySQL

* Added store method

* Added API and store tests

* Renamed migration after syncing with master

* Added app layer tests

* API is ready

* API is ready

* API is ready

* Renamed migration after syncing with master

* Updated migration list

* Fixed retry layer tests

* Allowed posts with empty messages

* Review fixes

* Reverted an incorrect change

* Renamed migration and fixed ID assignment

* CI

* Send post button changes (#28019)

* added Split button

* WIP

* Added core menu options

* WIP

* WIP

* WIP

* Handled displaying error in creating scheduled post

* lint fixes

* webapp i18n fix

* Review fixes

* Fixed a webapp test

* A few more fixes

* Removed a duplicate comment

* Scheduled post job (#28088)

* Added the job function

* Added query for fetching scheduled posts for pricessing

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* Reafactoring of scheduled post job

* Lint fixes

* Updated i18n files

* FInishing touches

* Added tests for GetScheduledPosts

* Added tests for PermanentlyDeleteScheduledPosts

* Updated all layer

* Some changes as discussed with team

* Added tests for UpdatedScheduledPost

* Code review refactoring

* Added job test

* MM-60120 - Custom time selection (#28120)

* Added a common date time picker modal and used it for post reminder

* Added a common date time picker modal and used it for post reminderggp

* Added modal for custom schedule time and fixed TZ issue

* WIP

* Removed event from useSubmit hook

* Removed event from useSubmit hook

* Added timezone handling

* fixed type error

* Updated i18n strings

* Minor cleanup

* updated snapshots

* review fixes

* Handled event

* Supported for having a DM thread open in RHS while in a regular channel

* Review fixes

* MM-60136 - Scheduled messages tab (#28133)

* WIP

* WIP

* Created Tabs and Tab wrapper with added styling

* Added API to get scheduled posts

* WIP

* Displated scheduled post count

* i18n fix

* Added tests

* Handled asetting active tab absed on URL:

* Reverted unintended change

* Added API to client ad OpenAPI specs

* Renamed file

* Adding fileinfo to schedule posts

* Partial review fixes

* Made get scheduled post API return posts by teamID

* review fixes

* Moved scheduled post redux code to MM-redux package

* Usedd selector factory

* WIP:

* WIP:

* Lint fix

* Fixed an incorrect openapi spec file

* Removed redundent permission check

* Clreaed scheduled post data on logout

* Removed unused i18n string:

* lint fix

* Render scheduled posts (#28208)

* WIP

* WIP

* Created Tabs and Tab wrapper with added styling

* Added API to get scheduled posts

* WIP

* Displated scheduled post count

* i18n fix

* Added tests

* Handled asetting active tab absed on URL:

* Reverted unintended change

* Added API to client ad OpenAPI specs

* Renamed file

* Created common component for draft list item

* WIP

* WIP

* Adding fileinfo to schedule posts

* Basic rendering

* Added count badge to tabs

* WIP

* Made the Drafts LHS iteam appear if no drafts exist but scheduled posts do

* Fixed icon size

* Partial review fixes

* Made get scheduled post API return posts by teamID

* Handled initial vs team switch load

* Displayed scheduled date in panel header

* Added error message and error indiocator

* WIP

* review fixes

* WIP Adding error reason tag

* Added error codes

* Moved scheduled post redux code to MM-redux package

* Usedd selector factory

* WIP:

* WIP:

* Lint fix

* Fixed an incorrect openapi spec file

* Removed redundent permission check

* Clreaed scheduled post data on logout

* Removed unused i18n string:

* lint fix

* Opened rescheduling modal

* Updated graphic for empty state of schduled post list

* Added delete scheduled post option and modal

* Badge and timezone fix

* WIP:

* Added send now confirmation modal

* lint

* Webapp i18n fix

* Fixed webapp test

* Fixed a bug where DM/GM scheduled posts weren't immideatly showing up in UI

* Minor fixes

* WIP

* Review fixes

* Review fixes

* Optimisations

* Fixed reducer name

* Moment optimizatin

* Updated route check

* MM-60144 - added API to update a scheduled post (#28248)

* WIP

* Added api and ap layer for update scheduled post ̛̦̄

* Added API to OpenAI specs, Go client and TS client

* removed permissio check

* Added tests

* Fixed tests

* Added PreUpdate method on scheduled post model

* MM-60131 - Reschedule post integration (#28281)

* Handled rescheduling post in webapp

* Added error handling

* MM-60146 - Delete scheduled post api (#28265)

* WIP

* Added api and ap layer for update scheduled post ̛̦̄

* Added API to OpenAI specs, Go client and TS client

* removed permissio check

* Added tests

* Fixed tests

* Added PreUpdate method on scheduled post model

* Added delete scheduled post API

* Added API to Go client and OpenAPI specs

* Added API to TS client

* Added tests

* CI

* Rmeoved two incorrect code comments

* MM-60653 - Integrated delete scheduled post API (#28296)

* Integrated delete scheduled apost API

* Lint fix

* Review fixes

* Excluded draft checks from scheduled posts (#28370)

* Excluded draft checks from scheduled posts

* Added a removed todo

* MM-60125 - Scheduled post channel indicator (#28320)

* Integrated delete scheduled apost API

* Lint fix

* Added state for storing scheduled posts by channel ID

* Refactored redux store to store scheudled posts by ID, thens tore IDs everywhere

* Refactored redux store to store scheudled posts by ID, thens tore IDs everywhere

* WIP

* Added scheduled post indiocator

* Handled single and multiple scheudled posts

* Review fixes

* Fixed styling and handled center channel, RHS and threads view

* Lint fix

* i18n fix

* Fixed a cycling dependency

* Lint fix

* Added some more comments

* Updated styling

* Review fixes

* Added common component for remote user time and scheduled post indicator

* Updated scheduled post count

* Minor change

* Moved CSS code around

* Fixed a bug where files in scheduled post didn't show up until refresh (#28359)

---------

Co-authored-by: Daniel Espino García <larkox@gmail.com>

* Scheduled post config (#28485)

* Added config

* Added config on server and webapp side

* Added config check in server and webapp

* Added license check

* Added license check

* Added placeholder help text

* Added license check to job

* Fixed job test

* Review fixes

* Updated English text

* Review fixes

* MM-60118 - Added index on ScheduledPosts table (#28579)

* Added index

* Updated indexes

* Scheduled posts misc fixes (#28625)

* Added detailed logging for scheduled post job

* Limited scheduled posts processing to 24 hours

* Marked old scheduled posts as unable to send

* Added t5ests

* converted some logs to trace level

* Fixed a bug causing error message to show up on deleting a scheduled post in a deleted thread (#28630)

* Fixed scheduled posts link in RHS (#28659)

* Fixed scheduled posts link in RHS

* Review fixes

* Fix permission name in scheduled posts by team (#28580)

* Fix permission name

* fix wording

---------

Co-authored-by: Mattermost Build <build@mattermost.com>

* FIxed width of generic modal header to fix browser channel modal (#28639)

* Only consider error-free scheduled posts for indicator in channel and RHS (#28683)

* Show only errro free scheudled posts in post box indicator

* Fixed a bug to handle no scheduled posts

* Fixed draft and scheudled post UI in mobile view (#28680)

* MM-60873 and MM-60872 - Fixed a bug with updating scheduled posts (#28656)

* Fixed a bug with updating scheduled posts

* Better selectors

* MOved shceuled post message length validation to app layer

* MM-60732 - Scheduled posts channel link now takes you to the first scheduled post in channel/thread in list (#28768)

* Ordered scheudle dposts by schgeudled at nad create at

* Ordered in client

* Added scroll to target

* Removed classname prop

* Fixed tests

* Added doc

* Import fix

* MM-60961 - Fixed a bug where API used incoming create at date for scheduled post (#28703)

* Fixed a bug where API used incoming create at date for scheduled post

* Stopped sending created at value for scheduled post

* MM-60785 - Fixed a bug where scheduled posts of channel we are no longer member of didn't show up (#28637)

* Fixed a bug where scheduled posts of channel we are no longer member of didn't show up

* Added a comment

* CI

* Used data loader to optimise laoding missing channels

* Minor refactoring

* MM-60963 - Added common checks for post and scheduled posts (#28713)

* Added commen checks for post and scheuled posts

* Sanitised scheduled posts

* Fixed tests

* Splitted post checks into app and context functions

* Added checks on scheduiled posts job as well:

* i18n fix

* Fixed a test

* Renamed a func

* removed duplicate check

* Scheduled posts UI fixes (#28828)

* Fixed send button and time picker borders

* Fixed center alignment of time picker

* Removed on for today and tomorrow

* Lint fix

* Date time modal hover state fix

* Badge fix

* Fixed a mnerge issue

* Scheduled Post send now and add schedule on draft (#28851)

* Added send now option on scheduled posts

* Minor refactoring

* WIP

* WIP

* WIP

* Lint fix

* i18n fix

* Snapshot update

* Review fixes

* Scheduled post inline editing (#28893)

* Added send now option on scheduled posts

* Minor refactoring

* WIP

* WIP

* WIP

* Lint fix

* i18n fix

* Snapshot update

* Displayed editing component in scheduled post

* Added handling for updating scheduled post

* Handle events

* Fixed escape key issue in scheudled post editing

* Fixes

* Displayed error message for editing error

* Don't show mention warning

* Handled dev mode (#28918)

* MInor fixes

* client fix

* Fixes

* CI

* Removed dev mode behaviour temperorily (#29008)

---------

Co-authored-by: Daniel Espino García <larkox@gmail.com>
Co-authored-by: Eva Sarafianou <eva.sarafianou@gmail.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2024-11-04 11:39:35 +05:30
Julien Tant
1909206e16
[MM-59069] Make sure OTP are actual One Time Password (#28074)
Automatic Merge
2024-09-17 00:44:32 +02:00
Miguel de la Cruz
f8202309ce
Adds logical deletes to shared channel remotes and remote clusters (#28159)
* Adds logical deletes to shared channel remotes and remote clusters

Instead of physically deleting the shared channel remote and remote
clusters records when a channel is unshared, a remote uninvited or a
remote cluster is deleted, now those have a logical `DeleteAt` field
that is set.

This allows us to safely restore shared channels between two remote
clusters (as of now resetting the cursor without backfilling their
contents) and to know which connections were established in the past
and now are severed.

* Delete the index in remoteclusters before adding the new column

* Fix bad error check
2024-09-12 13:55:11 +02:00
Miguel de la Cruz
cd99c4068d
Removes the backslash in migrations.list (#27882)
The use of the backslash was causing issues between different versions
of make.
2024-08-09 11:17:15 +02:00
Miguel de la Cruz
59873a2a50
Adds default team to the remote cluster entity (#27863)
* Adds default team to the remote cluster entity

A new DefaultTeamId field is added to the RemoteCluster entity and its
endpoints, and used when receiving channel invites to choose in which
team to create a new channel.

This will be later extended with the ability for the system admin to
manually accept invites, choosing which team to create the channel on
each. This use case will be triggered when the DefaultTeamId field is
empty, which now simply chooses the first team it finds in the
database as a fallback.

* Fix migrations list

* Fixes channelinvite test case

* Fix i18n

* Fix migration list
2024-08-08 16:36:27 +02:00
Scott Bishel
99881b819a
MM-58548 Remove manage_team permissions from System Console Ancillary permissions (#27395)
* remove manage team permissions from sysconsole_write_user_management_chanels and sysconsole_write_user_management_groups

* update migrations, add unit tests

* run migrations-extract

* make updating ancillary permissions a post

* update file names

* add new api to doc, update body to just be []string

* revert moving ancillary permissions to post

* fix queries after final testing

* Update channel.go

* Update channel.go

* Update 000124_remove_manage_team_permission.up.sql

* Update 000124_remove_manage_team_permission.up.sql

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2024-07-09 08:21:29 -06:00
Scott Bishel
71c25fb316
MM-58525 Fix upload file permissions (#27298)
* tie create_post and upload_file permissions together

* update tests

* update file name

* update migration to do in batches

* Update 000122_remove_upload_file_permission.up.sql

* fix formatting

* simplify migrations, fix regex issue

* update file names for recent merge

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2024-06-24 10:47:52 -06:00