Commit Graph
3464 Commits
Author SHA1 Message Date
cursor[bot] d5ddd9e726 [MM-70313] Detect CJK analyzer plugins reported under a prefixed component name (#38132) 2026-08-26 06:57:53 -03:00
Ben Schumacher e22a25ab85 [MM-65738] Clarify main logger shutdown timeout diagnostic (#38101)
The shutdown error only said "Error shutting down main logger" with no
hint at the cause, which is confusing when the real reason is an
unreachable log target (e.g. a remote TCP endpoint) blocking the
flush. Point the operator at the connection error logs for the
affected target instead.
2026-08-26 09:51:39 +02:00
Andre Vasconcelos f21b0299d3 Bumping prepackaged Boards version to 9.4.0 (#38131) 2026-08-25 21:59:54 +03:00
David Krauser c3a5a087d7 [MM-70086] Compare user attributes against channel attributes in access rules (#37755) 2026-08-25 09:55:41 -04:00
Andre Vasconcelos e7360779e0 Adding Dataminr v2.0.0 as a prepackaged plugin (#38111) 2026-08-25 12:34:50 +03:00
cursor[bot] 4608b02451 [MM-70291] Add Global Relay custom EML header setting (#38010) 2026-08-24 21:02:27 -04:00
Jesse Hallam 2021503fd7 Log file IDs instead of filenames during file upload and content extraction (#37987) 2026-08-24 18:04:23 -03:00
Jesse Hallam 84414404a1 Fix nil context panic in TestDoSetupSessionAttributesProperties (#38123)
UpdatePropertyFields panics when passed a nil context because
RequestContextWithMaster dereferences it. Use SystemCallerContext
to match the other sub-tests in the same function.
2026-08-24 20:56:59 +00:00
5d5d4e2752 [MM-70389] Add Android to the user_agent_platform session attribute values (#38059)
* [MM-70389] Add Android to the user_agent_platform session attribute

uasurfer has no Android platform, so Android devices were reported as
Linux and "Android" was missing from the user_agent_platform select
list, leaving no way to write a permission policy rule that matches
Android sessions.

Derive the platform name "Android" when the parsed OS is Android (or the
Mattermost Mobile user agent is not iOS) and add the matching option to
the seeded session attribute schema.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* [MM-70389] Cover the Android platform value end to end

Add a drift guard tying the platform names the server derives to the
options the user_agent_platform select offers, a session attribute test
proving an Android session stores "Android", and a migration test
proving a newly declared option reaches an already-seeded field without
regenerating the IDs of the options around it.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* [MM-70389] Trim comments and tighten the platform drift guard

Assert getPlatformName's own output against the schema options so a
platform name returned directly, rather than looked up in platformNames,
cannot drift out of the select either.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
2026-08-24 12:42:36 -04:00
a3e171f730 [MM-70224] Migrate property field reads to request context (#37636)
* Migrate property field reads to request context

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

* Preserve nil property service request context behavior

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

* Use explicit session attributes system context

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

* Use non-nil property contexts for internal calls

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

* Thread request context through content flagging lookups

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

* Update content flagging helper tests for request context

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

* Thread request context through content flagging values

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

* Fix build: remove unused context imports left after request.CTX migration

Migrating PropertyFieldStore to request.CTX removed the last
context.Context usage from the store.go interface, leaving an unused
"context" import in store.go and in the generated retrylayer/timerlayer
files (regenerated via `make store-layers`, with layer_generators now
stripping the context import when it's unused). Also drop the same
now-unused import in localcachelayer/main_test.go.

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

* Remove context import directly from store layer templates

Store no longer has any context.Context methods after the request.CTX
migration, so drop the hardcoded "context" import from the
retry/timer layer templates instead of stripping it at generation
time.

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

* Remove deprecated store.WithMaster/sqlstore.WithMaster helpers

request.CTX is now used everywhere, so the deprecated
context.Context-based WithMaster helpers and their wrapper in
sqlstore have no remaining callers; inline the logic into
RequestContextWithMaster instead.

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

* Fix TestDoSetupSessionAttributesProperties nil-context panic

Two subtests still constructed the pre-seed field state via
UpdatePropertyFields(nil, ...), which was the old system-caller
sentinel. isSystemCaller now requires an explicit SystemCallerContext
marker, so a bare nil rctx falls through into validateUpdate and
panics in RequestContextWithMaster. Use SystemCallerContext(th.Context)
like the rest of the suite already does.

* ci trigger

* ci trigger

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 10:35:12 +02:00
c5835cd2b1 [MM-70290] Run app migrations locked to the master DB (#38084)
* [MM-70290] Run app migrations locked to the master DB

App migrations write rows and then read them back within the same
function. Those read-backs resolve to GetReplica(), so on a licensed
server with read replicas configured a replica that has not yet caught
up returns zero rows and doAppMigrations aborts startup via mlog.Fatal.

Reported after a 10.11.12 -> 11.7.8 upgrade on Aurora PostgreSQL with a
reader endpoint, crashing on the Managed Category Properties Setup
migration. Restarting is not a reliable workaround: the done flag is
written before the failing read, so the short-circuit path re-runs the
same replica read and a node can crash-loop while lag persists.

Wrapping doAppMigrations in LockToMaster/UnlockFromMaster covers every
read in both migration loops, including SqlPropertyGroupStore.Get and
SearchPropertyFields, which take no context and so cannot be fixed by
per-call-site routing. This mirrors the existing bulk import fix in
app/import.go, which locks to master for the same reason while the
server is serving live traffic.

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

* Expect LockToMaster in the setup-functions store mock

doAppMigrations now locks the store to master, and it runs from
NewServer, so every helper that builds a server on the mock store hit
an unexpected-call panic. Registering both calls in
GetMockStoreForSetupFunctions covers the app, app/email, app/platform
and api4 helpers, which all share this mock.

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

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-08-22 01:34:01 +02:00
Alejandro García Montoro 8311321858 MM-70307: Update dependencies (#38086)
* Update dependencies

* Fix Opensearch client API changes

* Some more OS client fixes
2026-08-21 15:59:19 +02:00
Alejandro García MontoroandMattermost Build 6ac8899d93 MM-70307: Bump Go version to v1.26.7 (#38046)
* Bump Go version to v1.26.7

* Fix digest

* Update glibc to v16 in runtime image as well

* Trigger E2E tests

* MM-70307: Fix FIPS E2E test failure due to short PostgreSQL password

OpenSSL FIPS requires HMAC keys to be at least 14 bytes (112 bits). The
password 'mostest' (6 bytes) triggers a panic in lib/pq's SCRAM-SHA-256
authentication when the server runs under go-msft-fips with the
glibc-openssl-fips:16 image. Replace it with 'mostest_password' (16
bytes) in all E2E test PostgreSQL connection strings and container
configs. LDAP admin passwords are unaffected (different protocol).

* Revert "MM-70307: Fix FIPS E2E test failure due to short PostgreSQL password"

This reverts commit d31b0eb5e8.

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2026-08-21 12:52:52 +02:00
Alejandro García Montoro 752e5d1755 MM-70307: Change Postgres test password to mostest_password (#38060)
* Change test password to mostest_password

This makes the password compliant with the 112 bits minimum length
requirement. Otherwise, FIPS-compliant OpenSSL implementations will
panic when trying to connect from `lib/pq` with a shorter password.

* Simplify test templates' POSTGRES_PASSWORD values

* make generated

* Modify missing "mostest" strings
2026-08-20 22:18:06 +00:00
Jesse Hallam bfc2637d21 Precompute multibyte mention keywords once per post (#38038) 2026-08-20 17:16:19 -03:00
62056e5a7c MM-70071: Automatically select hosted push notification server based on license (#37802)
* MM-70071: Automatically select hosted push notification server based on license

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* test: fix mock-store fallout from push endpoint license listener

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* MM-70071: address review feedback on push endpoint sync

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ci: retrigger enterprise tests against updated companion branch

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ci: retrigger flaky artifact build

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* MM-70071: revert any hosted push endpoint to test on entitlement loss

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* MM-70071: add nil-safe License.HasMHPNS entitlement check

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* MM-70071: drop preview-tree docs for auto-selected push server

Monorepo MDX is still unpublished; this belongs in mattermost/docs.

Co-authored-by: Cursor <cursoragent@cursor.com>

* MM-70071: stub InitEmailBatching on guest-invite email mocks

License teardown now SaveConfigs the push endpoint, which fires the existing email-batching config listener.

Co-authored-by: Cursor <cursoragent@cursor.com>

* MM-70071: don't re-init email batching on push-server license sync

License teardown SaveConfigs the push endpoint, which fired the existing
email-batching listener and panicked tests that mock EmailService.
Re-init batching only when EnableEmailBatching changes, and stub the
remaining invite mock used during helper cleanup.

Co-authored-by: Nick Misasi <nick13misasi@gmail.com>

* MM-70071: re-init email batching when the interval setting changes

Keep EmailBatchingInterval live at runtime; only ignore unrelated
config writes such as the push-server license sync.

Co-authored-by: Nick Misasi <nick13misasi@gmail.com>

* MM-70071: isolate mock tests from push endpoint sync

Use custom push endpoints in shared mock fixtures so unrelated tests do not need config-listener expectations.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-08-20 16:11:21 +00:00
95cabdfb3b Graduate theme and onboarding settings to Site Configuration > Customization (#38027)
* [MM-57808][MM-57809][MM-57811] Graduate theme settings to Site Configuration > Customization

Move ThemeSettings.EnableThemeSelection, ThemeSettings.AllowCustomThemes, and
ThemeSettings.DefaultTheme out of System Console > Experimental > Features and
into Site Configuration > Customization, alongside the other branding settings.

The config keys, defaults, license gating, and the AllowCustomThemes dependency
on EnableThemeSelection are unchanged; only the System Console page and the
access classification move. The access tags become site_customization, so the
settings are now governed by sysconsole_{read,write}_site_customization rather
than sysconsole_{read,write}_experimental_features.

i18n ids move from admin.experimental.* to the Customization page's
admin.customization.* convention, and the documentation entries move from the
experimental configuration settings page to the site configuration settings
page.

* [MM-57812][MM-57813] Graduate tutorial and onboarding settings to Site Configuration > Customization

Move ServiceSettings.EnableTutorial and ServiceSettings.EnableOnboardingFlow out
of System Console > Experimental > Features and into Site Configuration >
Customization, next to the desktop app landing page setting that also governs a
user's first-run experience.

The config keys and defaults are unchanged; only the System Console page and the
access classification move. The access tags become site_customization, so the
settings are now governed by sysconsole_{read,write}_site_customization rather
than sysconsole_{read,write}_experimental_features.

i18n ids move from admin.experimental.* to the Customization page's
admin.customization.* convention, and the documentation entries move from the
experimental configuration settings page to the site configuration settings
page.

* [MM-57810] Surface ThemeSettings.AllowedThemes in Site Configuration > Customization

ThemeSettings.AllowedThemes has always existed in the server config and has
always been honoured by the theme picker, but it was never represented in the
System Console schema — not under Experimental > Features and not anywhere else.
Add it to Site Configuration > Customization alongside the theme settings it
constrains.

The server model is []string, so this uses the existing `type: 'text'` with
`multiple: true` widget, the same one ServiceSettings.DCRRedirectURIAllowlist
uses for its []string. The admin console joins the array with commas for display
and splits it back into an array on save, which matches how the client config
already serialises the value, so no behaviour or serialisation changes. The
setting picks up an access tag of site_customization, where it previously had
none, and the documentation entry moves from the self-hosted-only section of the
experimental configuration settings page to the site configuration settings page.

Also add a test asserting the graduated settings are present on Customization,
absent from Experimental > Features, and that AllowedThemes round-trips as a
string array.

* Add runtime-effect tests for graduated theme and onboarding settings

Expand coverage for the graduated Customization settings so that they are
verified to affect their features, not just to save:

- ThemeSettings.AllowedThemes: premade theme chooser only renders the
  allow-listed themes (theme enforcement on/off).
- ServiceSettings.EnableOnboardingFlow: onboarding task list is gated on
  the config value.
- ServiceSettings.EnableTutorial: the Channels tour tip is gated on the
  config value.
- EnableTutorial/EnableOnboardingFlow (and the theme bools) round-trip
  their value through the admin console schema.

Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com>
2026-08-19 20:58:18 +00:00
4c6c5a063f Graduate Enable Channel Viewed WebSocket Messages to Environment > Web Server (#38026)
* [MM-57806] Graduate Enable Channel Viewed WebSocket Messages

Move ServiceSettings.EnableChannelViewedMessages out of System Console >
Experimental > Features and into Environment > Web Server, alongside the
other ServiceSettings transport and performance knobs it belongs with.

The access tag changes from experimental_features to environment_web_server,
so the setting is now governed by sysconsole_read/write_environment_web_server.
write_restrictable and cloud_restrictable are preserved, the default remains
true, and the client config continues to publish the value. No runtime
behavior changes.

The i18n ids move from the admin.experimental.* namespace to the
admin.service.* namespace used by the rest of the Web Server page.

* [MM-57806] Document channel viewed WebSocket messages under Environment

Move the Enable Channel Viewed WebSocket Messages entry from the
experimental configuration settings page to the Web Server section of the
environment configuration settings page, matching its new System Console
location, and reformat it to the two-column table style used there.

* [MM-57806] Cover the new location of the channel viewed setting

Assert that the setting is defined on the Environment > Web Server page,
that it is gated on write access to the Web Server console resource rather
than to Experimental Features, and that searching the admin console for
"channel_viewed" resolves to environment/web_server.

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
2026-08-19 15:51:58 -03:00
cursor[bot] 19ffbc9c75 [MM-69643] Fail server startup when the AppsEnabled feature flag is enabled (#37968) 2026-08-19 08:54:00 -03:00
a7c6862497 [MM-70221] Use request loggers in store methods (#37648)
* Use request loggers in store methods

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

* Document request logger guidance

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

* Fix missed rctx args in scheduled post tests after master merge

go vet caught call sites the build alone didn't: test files with
stale ScheduledPostStore signatures missing the new rctx parameter.

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

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-08-19 13:08:45 +02:00
Harshil Sharma fb87397dba Data spillage exposure radius report generation (#37809)
* WIP:

* WIP:

* Added API integration

* Removed some unneeded functions and cleaned up unnecessery comments

* CI

* Test improvements

* Coderabit fixes

* Report data updates

* Handled commas and few other chaaracters in channel name

* Data spillage exposure radius UI integration (#37820)

* UI implementation and integration of exposure report APIs

* Minor cleanup

* Coderabit fixes

* Allowed generating exposure report irrespective of status

* Used the new button component

* fixed lint error
2026-08-19 09:16:03 +00:00
6941f56901 [MM-70252] Return 400 for malformed date filters in logs query API (#37970)
* [MM-70252] Reject malformed date filters in logs query API

The POST /api/v4/logs/query endpoint parsed date_from/date_to with a fixed
layout and swallowed parse errors, silently dropping the bound instead of
signalling the caller. A malformed date_from became the zero time and a
malformed date_to became now, so the request returned HTTP 200 with an
unfiltered result set.

Add LogFilter.IsValid, which rejects a non-empty bound that cannot be parsed
with the shared LogFilterDateLayout while keeping empty strings meaning
"unbounded", and call it from queryLogs so a bad filter returns 400 naming the
offending field and the expected layout.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* [MM-70252] Add tests for logs query date filter validation

Add a unit test for LogFilter.IsValid covering empty (unbounded), valid, and
malformed bounds, and an api4 integration test that drives POST /logs/query
through the real router to assert malformed date_from/date_to return 400 with
the offending field id while empty and valid bounds return 200.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* [MM-70252] Harden logs query date filter tests

Address test-quality review: exercise the DateTo validation branch with a valid
non-empty DateFrom, move fallible checks out of the require.Eventually condition
to avoid a cross-goroutine failure, and make each api4 subtest self-contained by
polling for the expected messages via a shared helper so valid-bounds also
verifies filtering still returns records.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* [MM-70252] Retrigger CI/CodeRabbit after invalid public-module feedback

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* [MM-70252] Note shared LogFilterDateLayout usage in date filter

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* [MM-70252] Add Client4.QueryLogs to simplify logs query date filter tests

* Address PR feedback: 2 answered, 1 resolved, 0 declined

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
Co-authored-by: Ben Schumacher <ben.schumacher@mattermost.com>
2026-08-19 09:05:10 +02:00
Jesse Hallam ede2edab4d Enforce snake_case for mlog field keys (#37998)
* introduce mlogFieldNaming

* apply vet-fix changes

* Cover every keyed mlog constructor in the analyzer fixture

* clarify end result in comment

* Check mlog field keys on explicitly instantiated constructors
2026-08-18 18:09:41 -04:00
Jesse Hallam 925a09a5f2 Remove dead Email login button color settings (#38021)
* [MM-57557] Remove dead Email login button color settings from the server

EmailSettings.LoginButtonColor, LoginButtonBorderColor and LoginButtonTextColor
were plumbed into the client config as EmailLoginButtonColor /
EmailLoginButtonBorderColor / EmailLoginButtonTextColor, but no client — web or
mobile — ever consumed them, so the email login button was never colored by
these values.

Remove the fields from the config struct and its defaults, drop the three client
config props, and update the config fixtures that carried them.

Also fixes MM-57556 and MM-57804, and follows the same removal already done for
the AD/LDAP (MM-70140) and SAML (MM-70141) equivalents.

* [MM-57557] Remove Email login button colors from the webapp and docs

Drop the three Email Login Button Color settings from the Admin Console
Experimental Features section along with their en.json strings, remove the
matching ClientConfig and AdminConfig EmailSettings entries to stay in sync with
the server model, and delete the corresponding documentation entries.

The experimental settings doc's jq example referenced
EmailSettings.LoginButtonColor, which no longer exists; point it at
EmailSettings.EmailBatchingBufferSize instead.
2026-08-18 17:36:03 -04:00
Jesse Hallam 0bff02c814 Graduate user typing settings to Site Configuration > Posts (#38023)
* [MM-57814][MM-57815] Graduate user typing settings to Site Configuration > Posts

Move ServiceSettings.EnableUserTypingMessages and
ServiceSettings.TimeBetweenUserTypingUpdatesMilliseconds out of
System Console > Experimental > Features into the Performance & Limits
section of System Console > Site Configuration > Posts, and reclassify
their access tags from experimental_features to site_posts (preserving
write_restrictable and cloud_restrictable).

The two settings stay adjacent, and the timeout remains disabled while
typing messages are off. The timeout label now states its unit, since
"User Typing Timeout" alone did not convey milliseconds. The i18n ids
move from admin.experimental.* to the Posts page's admin.posts.*
convention; the "E.g.: 5000" placeholder previously shared with the
experimental user status and profile fetching poll interval is now
defined once per setting.

No config keys, defaults, or runtime behavior change.

* [MM-57814][MM-57815] Assert user typing settings are searchable under Posts

Searching the System Console for "typing" now also matches
Site Configuration > Posts, guarding the new location of the user typing
settings. Experimental Features still matches on unrelated help text
about typing a tilde to trigger channel autocomplete.

* [MM-57814][MM-57815] Move user typing settings docs out of Experimental

Document "Enable user typing messages" and "User typing timeout" in the
Posts section of the site configuration settings guide, and drop them
from the experimental configuration settings guide.
2026-08-18 16:32:00 -03:00
Scott Bishel 78d120399f MM-68396: Remove deprecated dialog date/datetime fields for v12.0 (#37759)
* Drop top-level min_date/max_date/time_interval and allow_manual_time_entry;
require datetime_config (and manual_time_entry). Update docs, tests, and e2e fixtures accordingly.

* update important-upgrade-notes.rst per Doc Impact Analysis
2026-08-18 10:58:59 -06:00
44d12bef80 [MM-66243] Omit sanitized last_viewed_at/last_update_at instead of returning -1 for other users (#37505)
* Omit sanitized channel member timestamps from JSON

The channel member sanitization introduced in #33835 replaced other
users' LastViewedAt and LastUpdateAt with -1, which clients decode as
Dec 31 1969. Serialize the sanitized sentinel as an absent field instead
so the API no longer returns an invalid timestamp for other users.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Add tests and API docs for omitted sanitized member timestamps

Verify at the JSON layer that last_viewed_at and last_update_at are
omitted for other users' memberships (across the channel and user
endpoints) while remaining present for the requester, including a
legitimate zero timestamp. Document the omission in the API spec.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Strengthen sanitized-timestamp test coverage

Cover the NDJSON streaming branch of getChannelMembersForUser and the
getChannelMembersForTeamForUser endpoint, assert the requester's own
timestamps are valid (not the sentinel), use the sanitizedTimestamp
constant, and note the ChannelMemberForExport marshaling footgun.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Marshal team data via a typed struct in ChannelMemberWithTeamData

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Avoid shadowing err in ChannelMemberWithTeamData.MarshalJSON

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Use omitzero tags to omit sanitized member timestamps

Replace the custom ChannelMember/ChannelMemberWithTeamData MarshalJSON
round-trip with the Go 1.24 omitzero tag on LastViewedAt/LastUpdateAt.
SanitizeForCurrentUser now zeroes another user's timestamps so they are
omitted from API responses, per reviewer feedback.

* Give current user a real last_viewed_at in sanitization test

With omitzero, a zero last_viewed_at is legitimately omitted. Have user2
post an unread message and the current user view the channel so the
current-user assertions verify a genuine timestamp survives sanitization.

* Use -1 sentinel for sanitized member timestamps with single-pass marshal

A last_viewed_at of 0 legitimately means "never viewed", so it cannot
double as the sanitization sentinel. Restore the -1 sentinel and omit it
during serialization via shadowing pointer fields, avoiding the previous
marshal/unmarshal/marshal round-trip.

* Clarify ChannelMember.MarshalJSON doc comment per review feedback

* Address PR feedback: 0 answered, 4 resolved, 0 declined

- Simplify sanitizedTimestamp and SanitizeForCurrentUser doc comments per review
- Document that new ChannelMemberWithTeamData fields must be added to MarshalJSON
- Add round-trip test guarding against fields dropped by MarshalJSON

* Address PR feedback: remove round-trip MarshalJSON test

The round-trip test did not guard against forgetting to add a new field to
MarshalJSON, since the same field would also be missing from the test.

* Address PR feedback: assert legitimate zero last_update_at is serialized

* Mark sanitized channel member timestamp fields as nullable in OpenAPI spec

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-08-18 16:46:56 +00:00
6938cabac6 [MM-69646] Disallow MoveThreadsEnabled feature flag (fail server startup) (#37966)
* [MM-69646] Disallow MoveThreadsEnabled feature flag

Reject the MoveThreadsEnabled feature flag during config validation so the
server fails to start while it is enabled. The feature is being retired in
favor of Wrangler and will be removed later.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* [MM-69646] Cover nil FeatureFlags guard in config validation test

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Move MoveThreadsEnabled comment into isValid method body

Keep isValid's doc comment generic since it will validate more flag
combinations in the future, and place the MoveThreadsEnabled-specific
rationale next to the actual flag check.

* [MM-69646] Update TestMoveThread for retired MoveThreadsEnabled flag

Config.IsValid now rejects enabling MoveThreadsEnabled, so the
move-thread API stays disabled. Replace the enabled-path suite with
assertions that the flag cannot be turned on and MoveThread returns 501.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* [MM-69646] Stop forcing MoveThreadsEnabled in e2e environments

E2E was setting MM_FEATUREFLAGS_MOVETHREADSENABLED=true, which now fails
Config.IsValid and prevents the test server from starting. Remove the
override and skip Cypress move-thread specs that require the retired flag.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* [MM-69646] Skip TestMoveThread instead of asserting disabled flag

Mirror the E2E describe.skip approach: retain the original TestMoveThread
body and skip it at the top, since MoveThreadsEnabled is retired and
rejected by Config.IsValid.

* [MM-69646] Park cursor away from post dot menu in edit_file_attachment specs

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Jesse Hallam <jesse@mattermost.com>
2026-08-18 16:11:16 +00:00
Jesse Hallam eb3966e30b Remove atmos/camo image proxy support (#37284) 2026-08-18 11:25:17 +00:00
Jesse Hallam 0912a75c9c Bump minimum supported Postgres version to v15 (#37285) 2026-08-18 11:23:20 +00:00
Jesse Hallam dc6ab54f82 MM-67510 Drop deprecated autotranslation column from ChannelMembers (#37496) 2026-08-18 11:03:05 +00:00
Jesse Hallam 95fc4743df Drop RHEL 7/8 support: switch build image to golang-bookworm (#37229) 2026-08-18 10:59:32 +00:00
Jesse Hallam 54939d47c0 [MM-68249] Drop support for OpenSearch v1.x (#37283) 2026-08-18 07:41:05 -03:00
Felipe MartinandCursor f112b9a715 Remove deprecated built-in Slack import API and CLI (#37999)
The webapp Slack import path was deprecated in v6.0 in favor of mmetl
and Mattermost bulk import; remove the leftover API, importer package,
CLI command, and import_team permission.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-18 08:41:14 +02:00
2b40a0bdae MM-67868: Remove deprecated Slack compatibility type aliases (#37163)
Remove the deprecated backward-compatibility aliases introduced in #35445:
SlackAttachment, SlackAttachmentField, ParseSlackAttachment, and
StringifySlackFieldValue. Plugins should now use the MessageAttachment
equivalents directly.

SlackCompatibleBool is retained as it is still actively used.


Claude-Session: https://claude.ai/code/session_01KnMUsaSbm4HQsNEEtH5zp8

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-08-17 10:11:17 +00:00
Ben SchumacherandClaude ea183fab48 [MM-67157] Remove format parameter requirement from client license endpoint (#37167)
* MM-67157: Remove unused format flag from /license/client endpoint

The `format` query parameter on the `/license/client` (and local
variant) endpoint was effectively dead: it was required but only ever
accepted the single value `old`, returning an error otherwise. This
mirrors the earlier removal of the same flag from `/config/client`,
where the server now ignores the parameter while clients continue to
send `format=old` for compatibility with pre-v11 servers.

The server no longer inspects the `format` parameter, so requests with
no format, `format=old`, or any other value all succeed. The unused
i18n string and the parameter/response documentation in the OpenAPI
spec are removed accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Audz4JLNQN5SJxcPwyQBd

* MM-67157: document format=old retention in webapp client

Mirror the getClientConfig comment so the format=old query param on
getClientLicenseOld is not mistakenly removed; clients keep sending it
for compatibility with pre-v11 servers even though current servers now
ignore it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Audz4JLNQN5SJxcPwyQBd

* MM-67157: stop sending format=old from webapp client

Now that the server ignores the format parameter on /license/client,
drop format=old from the @mattermost/client getClientLicenseOld call and
update the e2e intercepts/helpers that matched the old query string.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Audz4JLNQN5SJxcPwyQBd

* Drop unneeded wildcard from license/client cy.intercept path

The format query param is gone from GET /license/client requests, so
the trailing * used to match it is no longer needed.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-17 08:43:18 +02:00
2945359dcc [MM-69895] Delete bot access tokens when permanently deleting a bot (#37907)
* [MM-69895] Delete bot access tokens on permanent bot deletion

App.PermanentDeleteBot removed the bot and user rows but left the
bot's UserAccessToken rows (and their sessions) orphaned, since the
UserAccessTokens table has no FK cascade to Users. Call
UserAccessToken().DeleteAllForUser to match PermanentDeleteUser.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* [MM-69895] Strengthen bot access token deletion regression test

Assert specific not-found errors, cover sessions for every bot token,
and add a control bot to prove deletion is scoped to the deleted bot.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* [MM-69895] Assert not-found status on deleted bot tokens

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* [MM-69895] Clear session cache when permanently deleting a bot

Deleting the access token rows via DeleteAllForUser is plain SQL and never
clears the in-memory session cache, so the bot's tokens kept authenticating
after PermanentDeleteBot. Mirror PermanentDeleteUser: delete sessions, delete
tokens, then clear the session cache (which also broadcasts to the cluster).

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
2026-08-15 06:58:58 +00:00
44c0490c7c Prevent system-owned bots from being disabled (#37200)
* Prevent system-owned bots from being disabled

System-owned bots (system-bot, content-review) could be disabled either
directly via the API or via the owner-deactivation path when
DisableBotsWhenOwnerIsDeactivated=true. Once disabled, they never
self-healed, silently breaking post reminders, reports, and channel
notifications.

- Add model.ProtectedBotUsernames and remove the dead
  BotWarnMetricBotUsername constant.
- Guard UpdateBotActive so protected bots cannot be disabled (403),
  covering both the API and disableUserBots paths.
- Auto-heal the system bot in GetOrCreateSystemOwnedBot by fetching
  including deleted and re-enabling if disabled.
- Hide the Edit and Disable controls for protected bots in the System
  Console bot list.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Strengthen tests for protected system bots

- Parameterize the app-layer guard test over both protected usernames
  (system-bot and content-review).
- Assert the underlying user is also reactivated by the auto-heal path.
- Drive the owner-deactivation test through the real UpdateActive path and
  add a non-protected bot to prove the batch keeps disabling other bots.
- Add an API-layer test asserting a 403 when disabling the system bot.
- Make the webapp recovery test click Enable and assert the action fires.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Address CodeRabbit feedback on protected bot reactivation

- Add reactivateProtectedBot to bypass active-user limit checks when
  auto-healing or re-enabling disabled system-owned bots
- Fail closed on bot store lookup errors in UpdateBotActive before
  mutating user state

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Fix govet shadow lint in reactivateProtectedBot

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Update unknown bot test for bot-first lookup in UpdateBotActive

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Address PR feedback: DRY protected bot reactivation, range over ProtectedBotUsernames, label system bots as Managed by Mattermost

* Refactor UpdateActive to share inner updateActive with protected bot reactivation

* Address PR feedback: remove user-limit bypass for bot activation

Bot accounts are excluded from the active-user/license counts (User().Count
defaults to IncludeBotAccounts=false), so the dedicated bypass path was guarding
a case that cannot occur. Revert the UpdateActive/updateActive split and the
protected-bot branch in UpdateBotActive; bot (re)activation goes through the
normal UpdateActive path again.

* Replace hardcoded webapp protected-bot list with server-driven system_owned field

Addresses marianunez's review comment: the webapp kept its own copy of the
protected bot usernames (system-bot, content-review), duplicating
model.ProtectedBotUsernames and risking silent drift if a new system-owned
bot is added server-side without updating the client list.

model.Bot now computes IsSystemOwned() from ProtectedBotUsernames and
serializes it as system_owned via a custom MarshalJSON, so the webapp reads
it directly off the bot instead of matching usernames itself.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
Co-authored-by: Ben Schumacher <ben.schumacher@mattermost.com>
2026-08-15 08:12:58 +02:00
Nate Schlossberg 1578db0729 Fix repeating 400s for post_persistent_notifications and delete_expired_posts jobs (#37874) 2026-08-14 09:02:49 -07:00
989d83c637 MM-69403 filter job websocket updates by permission (#37650)
* MM-69403 filter job websocket updates by permission

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

* Fix websocket event deep copy test setup

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

* Move job read permission mapping out of public model

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

* Address job websocket permission review findings

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

* Remove shared job read permission helper

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

* Remove extra generic job permission mappings

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

* Document cached websocket manage system lookup

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

* Fail closed on job_updated permission filtering during mixed-version rollouts

RequiredPermissions is silently dropped by nodes running a version that
predates it, so keep setting ContainsSensitiveData as a sysadmin-only
fallback for those nodes instead of broadcasting the unfiltered job.
ShouldSendEvent on upgraded nodes ignores ContainsSensitiveData whenever
RequiredPermissions is present.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>
2026-08-14 17:37:42 +02:00
Bill Gardner bc6a0c1ebf MM-69881: Add a size limit to the local image proxy's direct image fetch (#37848)
* MM-69881: Cap image size buffered by the local image proxy's direct fetch

ServeImage now accepts an optional max byte count.

* Log only the host, not the full URL, when discarding an oversized image

* Clarify ServeImage doc comment: make maxBytes=0 behavior explicit
2026-08-14 10:27:29 -04:00
6e85747816 MM-70100: Adjust Slack import user handling based on import type (#37818)
* MM-70095: Adjust Slack import user handling based on import type

See MM-70095.

* MM-70095: Add test coverage for non-admin import save failure on email conflict

Ensures the non-admin account-creation fallback path doesn't report success when the underlying save is rejected.

* MM-70095: Assert Save is invoked in email-conflict save-failure test

Explicitly verify the mocked Save call is exercised rather than relying on its return value alone.

* MM-70095: Fix non-admin Slack import user handling

* MM-70095: Fix non-admin Slack import user handling

* MM-70100: Clarify Slack import log message for matching account emails

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

---------

Co-authored-by: Bill Gardner <billg@wavearts.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 10:24:37 -04:00
Devin Binnieandcoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> 9a9bbe28bd [MM-70188] Convert the platform, os, browser user agent session attributes to select fields (#37969)
* [MM-70188] Convert the platform, os, browser user agent session attributes to select fields

* Update server/public/model/session_attributes.go

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

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-08-14 08:47:09 -04:00
M-ZubairAhmed a234862de7 [MM-69816] Update prepackaged Calls to v1.12.3 (#37985) 2026-08-14 17:51:05 +05:30
4f8b9d8195 [MM-69641] Promote EnableExportDirectDownload to a Cloud-only configuration setting (#37477)
* promote EnableExportDirectDownload to a Cloud-only configuration setting

Replace the FeatureFlags.EnableExportDirectDownload feature flag with a
FileSettings.EnableCloudExportDirectDownload configuration setting, gated
to Mattermost Cloud environments.

The /exportlink slash command and the export generate-presigned-url API
now require FileSettings.EnableCloudExportDirectDownload to be enabled and
a Cloud license. Operators previously enabling the feature via
MM_FEATUREFLAGS_ENABLEEXPORTDIRECTDOWNLOAD should transition to
MM_FILESETTINGS_ENABLECLOUDEXPORTDIRECTDOWNLOAD.

* add tests for Cloud-only export direct download gating

Cover the new EnableCloudExportDirectDownload + Cloud-license gate on
GeneratePresignURLForExport (app) and the generate-presigned-url API
(api4).

* add EnableCloudExportDirectDownload to FileSettings type

* gate export direct download on Cloud alone, without a configuration setting

* Use a bounded HTTP client in export presigned-URL tests

http.Get has no total timeout; if MinIO accepts the connection but
stalls, these tests can hang until the suite timeout.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
2026-08-14 11:32:19 +00:00
Bill GardnerandMattermost Build 22eaa8b03b [MM-69889] Improve handling of RelayState in SAML flow (#37837)
* [MM-69889] Improve handling of RelayState in SAML flow

RelayState was base64-decoded and trusted without any integrity check,
letting its contents be tampered with client-side. Sign relayProps with
an HMAC key (generated once, cached, stored like AsymmetricSigningKey)
before handing it to the IdP, and verify the signature before trusting
any of its fields on the way back.

* Add short expiry to signed RelayState

Bound the signed RelayState's validity to 5 minutes to restrict the
window in which a captured, unmodified RelayState could be replayed.

* [MM-69889] Use maps.Copy in SignSamlRelayState

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2026-08-14 09:36:17 +02:00
Edgar Bellot MicóandBill Gardner 663ad3dae9 MM-70072: Update team admin assignment during team join (#37922)
* MM-70072: Update team admin assignment during team join

* Assert SchemeUser in team rejoin test case

* MM-70072: Fix team admin assignment in bulk import path

* Preserve computed admin status through scheme role sync in bulk import

---------

Co-authored-by: Bill Gardner <billg@wavearts.com>
2026-08-13 14:22:06 -04:00
Nick MisasiandCursor Agent 9dfbaeca99 Add weekly recurring scheduled posts (#37746)
* Add weekly recurring scheduled posts.

Extend scheduled posts so users can schedule weekly repeats and keep the series healthy across sends, reschedules, and UI updates instead of falling back to one-shot behavior.

Made-with: Cursor

* Add Playwright coverage for recurring scheduled posts.

Cover weekly recurring scheduled messages in the scheduled-messages spec so the recurring UI and reschedule flow stay protected without adding a separate test surface.

Made-with: Cursor

* Fix recurring scheduled post CI failures.

Resolve the initial lint and formatting issues and renumber the new scheduled-post migration so it no longer collides with master during Postgres-backed test setup.

Made-with: Cursor

* Sync recurring scheduled post translation files.

Regenerate the affected English translation catalogs so the recurring scheduled post strings match the source extraction order expected by CI.

Made-with: Cursor

* Fix recurring scheduled post review follow-ups.

Preserve overdue cleanup behavior during weekly catch-up, defer delete websocket events until deletion succeeds, and address the remaining migration and UI review nits.

Made-with: Cursor

* Address recurring scheduled post review feedback

Made-with: Cursor

* Fix recurring scheduled post CI checks

Made-with: Cursor

* Make pending scheduled post keyset cursor index-scannable

EXPLAIN ANALYZE on a 5M-row ScheduledPosts table showed the pure OR-form
cursor forced Postgres to scan idx_scheduledposts_pending_scheduled_at_id
from the top on every page (~383ms/page, ~2M rows filtered). Keeping the
ScheduledAt <= beforeTime bound outside the tie-break restores the index
boundary (~0.12ms/page). Adds storetest coverage for cursor pagination.

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Address code quality review findings for recurring scheduled posts

Server:
- Replace silent-fallback AdvanceWeeklyScheduledNextOccurrence with
  error-returning ScheduledPost.ComputeNextScheduledAt; a recurring post
  whose timezone fails to load is now routed through the failed-post path
  instead of being reposted every job run or silently deleted
- Add ScheduledPost.IsRecurring and partition batches in
  processScheduledPostBatch; advance/delete now run independently so a
  store failure in one path can't cause reposts in the other
- Drop dead generality in UpdateRecurringScheduledPosts (only ScheduledAt
  varies per row; ErrorCode/ProcessedAt are constants)
- Simplify redundant repeat-type condition in GetPendingScheduledPosts

Webapp:
- Add shared isRecurringScheduledPost helper, replacing six scattered
  repeat_type === 'weekly' literals
- Recurrence timezone is now simply the scheduler's current timezone;
  removes initialRepeatTimezone/effectiveTimezone plumbing and the
  modal-label/picker timezone mismatch
- Single enforcement point for hiding send-now on recurring posts
- Use canonical getTeamIdByChannelId at both SCHEDULED_POST_UPDATED
  dispatch sites; rewrite errorsByTeamId update case as remove-then-add
  and add reducer tests

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Simplify recurring scheduled post code per review

- End a recurring series when its channel no longer exists instead of
  advancing it forever (matches the one-shot channel-not-found handling)
- Collapse the errorsByTeamId SCHEDULED_POST_UPDATED case into the
  identical SINGLE_SCHEDULED_POST_RECEIVED case (a scheduled post's team
  can't change) and combine duplicate byId cases; preserves state
  references on no-op updates
- Drop no-op timezone conversions in ComputeNextScheduledAt
- Remove redundant checkbox aria-label (label htmlFor already names it)
- Schedule new job tests in the past instead of sleeping a real second
- Remove redundant test assignment and e2e positional boolean

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Remove slop from recurring scheduled post changes

- Drop the business-rule CHECK constraint from the recurrence migration;
  no other migration enforces model-layer validation in the database,
  and BaseIsValid plus the job's failure handling already own it
- Fold the standalone repeat-validation test file into the existing
  TestScheduledPostBaseIsValid, matching its conventions
- Revert unrelated benchmark modernization in utils_test.go
- Drop an unneeded cast, unused fixture fields, and naming/assertion
  inconsistencies in tests

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Regenerate ScheduledPostStore mock with mockery ordering

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Address CodeRabbit review feedback

- Reject the host-dependent 'Local' value for RepeatTimezone; recurring
  schedules need a fixed zone (UTC or IANA name)
- Hide reschedule for deactivated DMs, matching send-now eligibility

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Resolve scheduled post team bucket from existing state when channel is unloaded

An admin can reschedule before fetchMissingChannels resolves, in which case
deriving the team from the channel returns undefined and the update was
misfiled under directChannels. getScheduledPostTeamId falls back to the
byTeamId bucket that already holds the post.

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Retrigger CI after transient enterprise npm network failure

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Clear hover/focus before asserting scheduled post header details in e2e

The drafts panel hides its timestamp/tag info section while hovered or
focus-within; after the reschedule modal closes, focus returns to the row
and the 'Repeats weekly' tag assertion saw a hidden element.

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Move recurrence columns into baseColumns and dispatch ComputeNextScheduledAt on repeat type

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Preserve recurrence when scheduled post updates omit repeat fields

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Disallow file attachments on recurring scheduled posts

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Stop pinning the channel indicator for recurring-only scheduled posts

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Re-home nullable-Type comment onto baseColumns

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Gate recurring scheduled posts behind a default-off feature flag

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Move presence-preservation rationale to the copy site

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Extract draftHasAttachments helper and require allowRecurring at single-caller layers

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Return null from the indicator selector when nothing should show

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Gate only recurrence transitions and preserve existing series in the modal

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Avoid err shadowing in scheduled post update handler

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Disable the repeat weekly checkbox with a tooltip when the message has attachments

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Return an explicit disposition from postScheduledPost

The batch loop inferred 'channel permanently gone' from the one return
path with a nil error and an error code set - an invariant a future
change could silently break, deleting recurring series by accident.
postScheduledPost now returns posted/failed/unsendable explicitly, the
switch refuses to delete on an unhandled disposition, and a test pins
that both recurring and one-shot posts in a nonexistent channel are
permanently deleted.

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Fix Repeat weekly attachments tooltip centering on the modal row (#37927)

Shrink-wrap the repeat checkbox row so WithTooltip anchors to the
control/label instead of the full modal body width.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-08-13 07:27:23 -04:00
Ben SchumacherandCursor Agent 0eb2ec5a17 [MM-70226] Migrate role GetByName to request context (#37634)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-08-13 06:33:28 +00:00
Ben SchumacherandClaude Sonnet 4.6 2df50ab1fb [MM-69911] Include PAT token ID in server and audit logs for request traceability (#37910)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-13 08:00:48 +02:00