Commit graph

30 commits

Author SHA1 Message Date
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
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
Ibrahim Serdar Acikgoz
85dc085197
[MM-68535] Invalidate channel cache after policy assignment (#36292) 2026-04-28 20:50:29 +00:00
Doug Lauder
3888a69479
MM-68158: Fix shared channel remote display and notify UI on invite completion (#35908)
Some checks are pending
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 (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 / 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
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
* MM-68158: Fix shared channel remote display and add WebSocket notification

  Fix getSharedChannelRemotes API handler passing ChannelId instead of
  RemoteId to GetRemoteCluster, which always failed the lookup. Add
  RemoteId to SharedChannelRemoteStatus model and store query.

  Add shared_channel_remote_updated WebSocket event published from the
  onInvite callback so the UI refreshes its cached remote names when the
  async invite completes, instead of showing the generic "Shared with
  trusted organizations" fallback.

* Improved unit tests per review comments
2026-04-03 02:06:01 -04: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
Felipe Martin
1be8a68dd7
feat: pluginapi: filewillbedownloaded / sendtoastmessage (#34596)
* feat: filewillbedonwloaded hook

* feat: error popup

* chore: make generated pluginapi

* tests

* feat: different errors for different download types

* feat: allow toast positions

* fix: avoid using deprecated i18n function

* feat: add plugin API to show toasts

* feat: downloadType parameter

* tests: updated tests

* chore: make check-style

* chore: i18n

* chore: missing fields in tests

* chore: sorted i18n for webapp

* chore: run mmjstool

* test: fixed webapp tests with new changes

* test: missing mocks

* fix: ensure one-file attachments (previews) are handler properly as thumbnails

* chore: lint

* test: added new logic to tests

* chore: lint

* Add SendToastMessage API and FileWillBeDownloaded hook

- Introduced SendToastMessage method for sending toast notifications to users with customizable options.
- Added FileWillBeDownloaded hook to handle file download requests, allowing plugins to control access to files.
- Updated related types and constants for file download handling.
- Enhanced PluginSettings to include HookTimeoutSeconds for better timeout management.

* Update webapp/channels/src/components/single_image_view/single_image_view.tsx

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

* chore: copilot reviews

* test: head requests

* chore: linted the webapp

* tests: fixed path

* test: fixed mocked args

* allow sending message to a connection directly

* fix: hook thread safety

* chore: formatting

* chore: remove configuration from system console

* chore: release version

* chore: update signature

* chore: update release version

* chore: addressed comments

* fix: update file rejection handling to use 403 Forbidden status and include rejection reason header

* Fix nil pointer panic in runFileWillBeDownloadedHook

The atomic.Value in runFileWillBeDownloadedHook can be nil if no
plugins implement the FileWillBeDownloaded hook. This causes a panic
when trying to assert the nil interface to string.

This fix adds a nil check before the type assertion, defaulting to
an empty string (which allows the download) when no hooks have run.

Fixes:
- TestUploadDataMultipart/success panic
- TestUploadDataMultipart/resume_success panic

* test: move the logout test last

* chore: restored accidential deletion

* chore: lint

* chore: make generated

* refactor: move websocket events to new package

* chore: go vet

* chore: missing mock

* chore: revert incorrect fmt

* chore: import ordering

* chore: npm i18n-extract

* chore: update constants.tsx from master

* chore: make i18n-extract

* revert: conflict merge

* fix: add missing isFileRejected prop to SingleImageView tests

* fix: mock fetch in SingleImageView tests for async thumbnail check

The component now performs an async fetch to check thumbnail availability
before rendering. Tests need to mock fetch and use waitFor to handle
the async state updates.

* refactor: move hook logic to app layer

* chore: update version to 11.5

* Scope file download rejection toast to the requesting connection

Thread the Connection-Id header through RunFileWillBeDownloadedHook and
sendFileDownloadRejectedEvent so the WebSocket event is sent only to the
connection that initiated the download, instead of all connections for
the user.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-16 17:10:39 +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
Harrison Healey
777867dc36
Define types for WebSocket messages and migrate WebSocket actions to TS (#34603)
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 TS definitions for every WebSocket event

* Remove unused WebSocket events

* Add a few extra fields to POSTED events

* Stop reusing WS event types as Redux actions

* Remove now-unused WS event types from mattermost-redux

* Rename some types to be clearer

* Use new WebSocketEvents and WebSocketMessage type everywhere

* Reorganize and export named types for WS messages

* Use new types in websocket_actions.jsx the best we can

* Rename websocket_actions.jsx to websocket_actions.tsx

* Migrate websocket_actions.tsx to TypeScript

* Break up websocket_messages.ts and group together WebSocketMessages types

* Rename websocket_actions.tsx to websocket_actions.ts
2026-01-23 14:29:40 -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
Harshil Sharma
c21ef29f02
Flag post API (#33765)
* Added enable/disable setting and feature flag

* added rest of notifgication settings

* Added backend for content flagging setting and populated notification values from server side defaults

* WIP user selector

* Added common reviewers UI

* Added additonal reviewers section

* WIP

* WIP

* Team table base

* Added search in teams

* Added search in teams

* Added additional settings section

* WIP

* Inbtegrated reviewers settings

* WIP

* WIP

* Added server side validation

* cleanup

* cleanup

* [skip ci]

* Some refactoring

* type fixes

* lint fix

* test: add content flagging settings test file

* test: add comprehensive unit tests for content flagging settings

* enhanced tests

* test: add test file for content flagging additional settings

* test: add comprehensive unit tests for ContentFlaggingAdditionalSettingsSection

* Added additoonal settings test

* test: add empty test file for team reviewers section

* test: add comprehensive unit tests for TeamReviewersSection component

* test: update tests to handle async data fetching in team reviewers section

* test: add empty test file for content reviewers component

* feat: add comprehensive unit tests for ContentFlaggingContentReviewers component

* Added ContentFlaggingContentReviewersContentFlaggingContentReviewers test

* test: add notification settings test file for content flagging

* test: add comprehensive unit tests for content flagging notification settings

* Added ContentFlaggingNotificationSettingsSection tests

* test: add user profile pill test file

* test: add comprehensive unit tests for UserProfilePill component

* refactor: Replace enzyme shallow with renderWithContext in user_profile_pill tests

* Added UserProfilePill tests

* test: add empty test file for content reviewers team option

* test: add comprehensive unit tests for TeamOptionComponent

* Added TeamOptionComponent tests

* test: add empty test file for reason_option component

* test: add comprehensive unit tests for ReasonOption component

* Added ReasonOption tests

* cleanup

* Fixed i18n error

* fixed e2e test lijnt issues

* Updated test cases

* Added snaoshot

* Updated snaoshot

* lint fix

* WIP

* lint fix

* Added post flagging properties setup

* review fixes

* updated snapshot

* CI

* Added base APIs

* Fetched team status data on load and team switch

* WIP

* Review fixes

* wip

* WIP

* Removed an test, updated comment

* CI

* Added tests

* Added tests

* Lint fix

* Added API specs

* Fixed types

* CI fixes

* API tests

* lint fixes

* Set env variable so API routes are regiustered

* Test update

* term renaming and disabling API tests on MySQL

* typo

* Updated store type definition

* Minor tweaks

* Added tests

* Removed error in app startup when content flaghging setup fails

* Updated sync condition:

* Flag message modal basE

* added post preview

* displaying options

* Adde comment input

* Updated tests and docs

* finction rename

* WIP

* Updated tests

* refactor

* lint fix

* MOved to data migration

* 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

* Updated test

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

* removed cached group ID

* removed debug log

* review fixes

* Used correct ot name

* CI

* Updated mobile text

* Handled JSON error

* fixerdf i18n

* CI

* 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

---------

Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <aider@aider.chat>
2025-10-02 20:24:29 +05:30
Ben Schumacher
9add320011
[MM-64654] Migrate to modern Go features (#31820) 2025-07-18 12:54:51 +02:00
Miguel de la Cruz
f85a8c61a4
Adds websocket messages to Custom Profile Attributes (#30163)
* Adds websocket messages to Custom Profile Attributes

The app layer now fires a websocket event as part of the operations
over Custom Profile Attribute fields and values. It updates as well
the Patch method for CPA values so all the changes are commited as
part of the same transaction.

To be able to do this last operation, the change adds methods to
upsert CPA values in both the store and the property service.

* Fix i18n strings

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
2025-02-13 11:21:46 +00:00
Agniva De Sarker
cb75a20c54
MM-61904: Make reliable websockets work in HA (#29489)
We do a cluster request to get the active and dead queues
from other nodes in the cluster to sync any missing
information.

We check the dead queue in the other nodes to see
if there's been any message loss or not. Accordingly,
we send just the active queue or both active and dead queues.

There's still an edge case that is left out where
a client could have potentially connected and reconnected
to multiple nodes leaving multiple active queues
in multiple nodes. We don't handle this scenario
because then potentially we need to create
a slice of sendQueueSize * number_of_nodes. And then
this can happen again, leading to an infinite increase
in sendQueueSize.

We leave this edge-case to Redis, acknowledging
a limitation in our architecture.

In this PR, when there's no message loss, we just
take the active queue from the last node it connected
to.

And if there's message loss where the client's
seqNum is within the last node's dead queue, we also
handle that.

But if there's severe message loss where the client's
seqNum falls within the dead queue of another node, then
we just send the data from that node to reconstruct the
data as much as possible. It could be possible to set
a new connection ID in this case, but this involves
more data transfer always from all nodes and recomputing
the state in the requestor node.

https://mattermost.atlassian.net/browse/MM-61904

```release-note
NONE
```

Co-authored-by: Mattermost Build <build@mattermost.com>
2025-01-17 11:11:32 +05:30
Pablo Vélez
fbee99e870
MM-60124-emit and read create scheduled post WS event (#28844)
* MM-60124-emit and read create scheduled post WS event

* fix unit test; reorder get team id logic; use userid for ws events

* MM-60145 - ws events on update scheduled posts (#28871)

* MM-60145 - ws events on update scheduled posts

* MM-60147 - ws events on delete scheduled posts (#28872)

* MM-60147 - ws events on delete scheduled posts

* remove unnecessary channelID

* remove unnecesary memoization
2024-11-05 14:24:50 +01:00
Agniva De Sarker
762e3dfc08
MM-59846: Removing some deprecated ws events for v10 (#27773)
These WS events are no longer used in the code. Can be
removed as part of v10.

https://mattermost.atlassian.net/browse/MM-59846
```release-note
NONE
```
2024-07-30 13:06:13 +05:30
Ben Schumacher
423809e0d0
Using correct type for websocket events (#26825) 2024-04-22 11:06:58 +02:00
Devin Binnie
8589476229
[MM-57067][MM-57006][MM-57328] Acknowledge websocket POSTED events that may result in a notification on the web client (#26604)
* Acknowledge POSTED events that may result in a notification

* Remove temporary metrics

* Add Desktop App support

* Merge'd

* Add some tests

* PR feedback

* Rework window is focused check

* Oops

* Move mentions/followers ACK to posted ACK broadcast hook

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2024-04-11 20:18:14 +00:00
Ben Schumacher
1e0de8f559
[MM-57356] Make use of go1.21 features (#26620) 2024-04-04 13:44:03 +02:00
Elias Nahum
7e9cd04a8b
Channel Bookmarks (#25449)
* create ChannelBookmarks table

* ChannelBookmark model

* channel bookamrks Store layer

* add GetBookmarksForAllChannelByIdSince

* add channel bookmarks to test store

* Add channel bookmarks to app layer

* remove index for createAt in channel bookmarks migrations

* remove createAt from select channel bookmark query and enable store delete bookmark test

* update reponse of UpdateBookmark

* rename db migration files

* channel bookmarks store update sort order

* channel bookmarks app layer update sort order

* fix lint & tests

* Fix lint and introduce util functions to insert / remove from slice

* remove model etag

* i18n

* defer remove file info after test run

* Fix tests passing the request context

* fix migrations

* fix TestRetry

* Add bookmark permissions (#25560)

* Adds channel bookmarks permissions

* Fix linter

* Remove unnecessary empty lines

* Remove scss change as it's not necessary anymore

* Fix mock store

* Fix mock store and add role entry

* Fix test

* Adds cypress test and update permissions migration to update admin roles

* Adds channel bookmarks roles to default admin roles

* Adds bookmark permissions to default role permissions constant in webapp

* Update mmctl test

* Update permission test after normalising the roles

* fix store tests

* fix app layer tests

* Add new bookmark endpoint (#25624)

* Adds channel bookmarks api scaffold and create endpoint

* Applies review comments to the API docs

* Adds websocket test to create channel bookmark

---------

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

* MM-54426 exclude Channel Bookmarks files from data retention (#25656)

* Augment channel APIs to include bookmarks (#25567)

* update files docs for server 9.4

* Adds update channel bookmark endpoint (#25653)

* Adds update channel bookmark sort order endpoint (#25686)

* Adds update channel bookmark endpoint

* Updates edit app method to return the right deleted bookmark and adds tests

* Adds the update channel bookmark sort order endpoint

* Fix repeated test after merge

* Assign right permissions to each test

* Update store and app layer to return specific errors and add tests

* Adds delete channel bookmark endpoint (#25693)

* Updates edit app method to return the right deleted bookmark and adds tests

* Fix repeated test after merge

* Updates edit app method to return the right deleted bookmark and adds tests

* Adds delete channel bookmark endpoint

* Adds list channel bookmarks endpoint (#25700)

* Add channel moderation to bookmarks (#25716)

* fix migrations index

* fix getChannelsForTeamForUser

* fix getChannelsForTeamForUser

* fix bad merge client4

* fix file api with bookmark permission

* add ChannelBookmarks feature flag

* add missing translations

* Set DB column for type as enum

* use custom type for bookmark query using sqlx

* use transaction when saving bookmark

* return NewErrNotFound instead of Sql.ErrNoRows

* use squirrel for IN query

* add a limit of 1K for records in GetBookmarksForAllChannelByIdSince

* UpdateSortOrder with one single query instead of multiple updates

* fix shadow declaration

* fix channel bookmarks permission string definition in admin console

* fix another shadow declaration

* Fix model conversion

* add SplitSliceInChunks

* remove include bookmarks in channels api

* Cap amount of bookmarks per channel

* add etag back to get channels

* feedback review

* update file info when replacing a bookmark file

* return 501 not implemented when the license is not available

* add detail message when getting channel member on bookmark api

* start audit before permission check on create bookmark api

* use require.Eventuallyf for testing WS events

* remove unnecessary log in app layer

* use require instead of assert to avoid panics

* enforce limit when querying bookmarks since

* prevent to create/update bookmark if file is already attached

* fix lint

* delete file when a bookmark is deleted

* Dot allow to set a fileId and a url at the same time to a bookmark

* fix query to delete a file that belongs to a bookmark

* do not patch the bookmark type

* Server side FeatureFlag check (#26145)

* use ff in server, set ff to false

* turn on FF for unit tests

* defer unset FF for unit tests

* turn ff on for testing

* only allow attaching files that were uploaded for bookmark

* Set feature flag off as default

* fix lint

* update email templates as PR failed

* revert templates

* force the assignment of ID when creating a bookmark

* Fix unit tests

---------

Co-authored-by: Miguel de la Cruz <miguel@mcrx.me>
Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Caleb Roseland <caleb@calebroseland.com>
Co-authored-by: Scott Bishel <scott.bishel@mattermost.com>
2024-03-12 08:36:05 -06:00
Agniva De Sarker
e0b5b951f1
MM-56060: Create base scaffolding for websocket pub-sub (#25654)
We create a new websocket action called "presence" which
can contain the active_channel and the active_team for a given
client connection.

On the client side, for every channel or team switch, we send
out this message.

https://mattermost.atlassian.net/browse/MM-56060

```release-note
NONE
```
2023-12-12 08:49:09 +05:30
Ben Schumacher
51e73b681b
[MM-40638] Type all of the websocket event names as a new type WebsocketEventType (#25454)
Co-authored-by: Sudheer Tripathi <sudheer@clearglass.com>
Co-authored-by: Sudheer Tripathi <31629433+sudheer121@users.noreply.github.com>
Co-authored-by: Sudheer Tripathi <tripathisudheer604@gmail.com>
2023-11-22 11:09:48 +01:00
Harrison Healey
ef66f7beab
MM-54238 Add WebSocket broadcast hook and don't broadcast when other users were mentioned (#24641)
* MM-54238 Initial implementation

* MM-54238 Move websocket hook into app package

* MM-54238 Add tests for mentions in posted websocket messages

* Fix styling

* Fix other styling

* Idiomatic ID naming for new code

* Fix more styles

* Separate hooks to add mentions and followers

* Improved error handling for invalid types in hooks

* Rename HasChanges to ShouldProcess

* Pass broadcast hooks through hubStart

* Add test helper for asserting json unmarshaling

* Fix missing arguments in tests

* Ensure broadcast hooks are sent across the cluster and not to users

* Ensure tests actually cover following a post

* Fix code broken by merge

* Go vet again...

* Deep copy event before processing it with hooks

* Replace RemoveBroadcastHooks with WithoutBroadcastHooks

* Address feedback

* Add helper to fix type information for hook args

* Wrap WebSocketEvent and simplify BroadcastHook

* Address feedback

* Address feedback
2023-11-08 16:17:07 -05:00
Agniva De Sarker
3563e56a77
MM-54998: Optimize JSON marshalling in websocket broadcast (#25286)
Marshalling a json.RawMessage is not zero overhead. Instead,
it compacts the raw message which starts to have an overhead
at scale.

https://github.com/golang/go/issues/33422

Since we have full control over the message constructed, we
can simply write the byte slice into the network stream.
This gives considerable performance boost.

```
goos: linux
goarch: amd64
pkg: github.com/mattermost/mattermost/server/public/model
cpu: Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz
             │   old.txt    │              new_2.txt              │
             │    sec/op    │   sec/op     vs base                │
EncodeJSON-8   1640.5n ± 2%   289.6n ± 1%  -82.35% (p=0.000 n=10)

             │  old.txt   │             new_2.txt             │
             │    B/op    │    B/op     vs base               │
EncodeJSON-8   528.0 ± 0%   503.0 ± 0%  -4.73% (p=0.000 n=10)

             │  old.txt   │             new_2.txt              │
             │ allocs/op  │ allocs/op   vs base                │
EncodeJSON-8   5.000 ± 0%   4.000 ± 0%  -20.00% (p=0.000 n=10)
```

P.S. No concerns over changing the model API because we are
still using 0.x

https://mattermost.atlassian.net/browse/MM-54998

```release-note
Improve websocket event marshalling performance
```
2023-11-08 12:15:24 +05:30
Daniel Espino García
e9b3afecc2
Mark category as read (#24003)
* Mark category as read

* Fix lint and test

* Fix tests

* Fix test and remove wrong aria

* Address server issues and add mark as read for unreads

* Missing changes

* Fix tests

* fix tests

* Add confirmation popup to mark as read category

* Always use viewMultipleChannels and other fixes

* Remove unneeded code

* Fix test

* Address feedback

* Address feedback

* Fix tests

* Fix test

* Fix tests

* Update aria-haspopup depending on the number of channels to mark as viewed

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2023-08-14 10:01:02 +02:00
Agniva De Sarker
29bd0c9357
Revert "MM-42810: Introduce a channel hook for a websocket event (#23812)" (#24107)
Automatic Merge
2023-07-24 19:16:57 +03:00
Agniva De Sarker
b20ef95b91
MM-42810: Introduce a channel hook for a websocket event (#23812)
Sometimes a broad distinction of just a channelID or a userID
is not enough to efficiently send a websocket event to users.

In several cases, depending on the user and channel, we might
need to modify the message. Therefore, we introduce the
concept of a channel hook that will get executed if the scope
is set to a channel. This hook can be populated at the app layer
to perform any application specific logic to the event.

Care must be taken to avoid race conditions as the passed event
is not deep copied. It is left to the user to treat it carefully.

For this issue, the main problem was that since we don't know
which users have permissions to which channels, we had to go through
_all_ members of a channel to figure that out. This was redundant
since a large portion of those users might not even be connected
at that time.

We solve this with the channel hook where we push this check
to be performed later while actually sending the event. This
reduces the computation to be done only for _connected_ users
rather than _all_ users of a channel.

The next iteration of this should be to use websocket subscriptions
to monitor exactly which users are on that channel to even
trim down that list. That is a larger initiative to be taken later.

Tested locally with a channel of 50 users. Here are rough results:
```
With PR:
patchPost 97ms
createPost 90ms

Master:
patchPost 306ms
createPost - 298ms
```

https://mattermost.atlassian.net/browse/MM-42810

```release-note
Improve  performance while sending messages
with permalinks to channels with large number of users.
```
2023-07-15 08:14:16 +05:30
Agniva De Sarker
d9a28c1244
MM-52532: Fix golangci warnings for public module (#23918)
https://mattermost.atlassian.net/browse/MM-52532

```release-note
NONE
```
2023-06-30 20:12:56 +05:30
Vishal
9399ce8637
[MM-47751][MM-48102] MPA: Send Persistent Notifications (#21619)
* MM-46410: adds urgency on mention counts

We have introduced priority for posts in
https://github.com/mattermost/mattermost-webapp/pull/10951.
We do need to color the mention badges in the webapp with a prominent
color when a mention is posted in an urgent message.
A thread has urgent mentions if the root post is marked as urgent, and
the replies contain mentions to the user viewing the thread.

This PR adds two columns, urgentmentioncount, and isurgent, in
channelmembers, and threads tables respectively.
Furthermore when asking for team/thread mention counts, we also return
urgent mention counts for the user.

* Adds PostAcknowledgements table and apis

* job init and fetch mentions

* add-migrations

* delete-expired

* send-notifications

* Fetches post priority in batches

* stop-notifications

* stop-notification-on-reply

* MM-47750: Adds PostAcknowledgements table and apis

- Adds post acknowledgement api/app/store methods to be able to save and
delete post acknowledgements by users.
- Adds wesbsocket events for acknowledgement created/deleted
- Returns post acknowledgements in the post's metadata

* add-license-check

* add-pagination

* delete on channel and team

* validate guests

* add configs

* move create priority post check from app to api

* Add desktop notifications

* check status

* use config in job

* add IsUrgent check

* Add last-sent-at

* validate max recipients

* Update lastSentAt

* Validate min. recipient

* send email notification only once

* remove email notifications

* use latest time from config to run job

* Add notifications counter

* publish events to mentioned users only

* pickup license updates in scheduler

* don't allow post owner to stop notifications

* follow normal notifications behaviour

* Validates persistent notifications interval

* move logic of handling valid and expired posts into sql

* Adds persistent notifications in the webapp

---------

Co-authored-by: koox00 <3829551+koox00@users.noreply.github.com>
Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2023-05-18 23:44:12 +05:30
Jesse Hallam
bb02b35048
Expose public/ API as submodule (#23345)
* model -> public/model

* plugin -> public/plugin

* public/model/utils -> public/utils

* platform/shared/mlog -> public/shared/mlog

* platform/shared/i18n -> public/shared/i18n

* platform/shared/markdown -> public/shared/markdown

* platform/services/timezones -> public/shared/timezones

* channels/einterfaces -> einterfaces

* expose public/ submodule

* go mod tidy

* .github: cache-dependency-path, setup-go-work

* modules-tidy for public/ too

* remove old gomodtidy
2023-05-10 13:07:02 -03:00
Renamed from server/model/websocket_message.go (Browse further)