* Adds a mechanism to delete CPA values for a given user
This requires improving the Property Value service to enable delete
all values for a given target, so a new method was created that allows
to delete filtering by targetType and targetID (required) and
optionally for a specific groupID in case the caller wants to affect
all values for a target (useful in case you remove a post for example
and want to delete all values pointing to that post regardless of the
feature they belong to) or only those that belong to a specific
feature.
* Fix property value tests
* Fix after merge and update method name
* Fix linter
---------
Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
Co-authored-by: Mattermost Build <build@mattermost.com>
* MM-62157: Avoid SELECT * in user_store.go
- Replace raw SQL query "SELECT * FROM Users" with query builder in Update method
- Replace raw SQL query "SELECT * from Users" with query builder in ClearAllCustomRoleAssignments
- Change Select("*") to Select("data.*") in GetUserReport method
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* MM-62157: Avoid more instances of SELECT * in user_store.go
- Replace raw SQL query "Users.*, cm.ChannelId" with usersQuery in getUsersInGroupChannels
- Replace "Users.*" with getUsersColumns() in GetUserReport method
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Adds a groupID filter to the property service methods
This allows the property service caller to directly ensure that a
given call is only going to affect a field or value that belongs to a
given group, instead of (for example) retrieving a property value
before deleting it by id to ensure that the value belongs to a
specific property group. The groupID filter is optional and has no
effect if called with the empty string value.
The changes also remove references to input sanitization on trimming
the whitespace for the CPA field names and validate at the API level
the input for the field patch endpoint.
* Fix linter
---------
Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
Co-authored-by: Mattermost Build <build@mattermost.com>
* MM-62162: Replace SELECT * in user_access_token_store.go
- Replaced all SELECT * queries with explicit column selection
- Used query builder instead of raw SQL strings for all queries
- Added reusable userAccessTokensSelectQuery in the store constructor
- Added comprehensive test for pagination and IsActive flag
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix code formatting in user_access_token_store test file
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* MM-62162: Update UserAccessToken Search method to use explicit column names
- Fixed "ambiguous column" errors by explicitly naming columns with table qualifiers
- Added test for the Search functionality
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* MM-62162: Update UserAccessToken Search method to use explicit column names
- Fixed "ambiguous column" errors by explicitly naming columns with table qualifiers
- Maintained exact semantics of original query's LIKE filters
- Refactored to use query builder instead of raw SQL
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* MM-62162: Update UserAccessToken Search method to use reusable query
- Modified userAccessTokensSelectQuery to use fully qualified column names
- Updated Search method to use the existing query builder
- Fixed "ambiguous column" errors by using full column qualifiers
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* MM-62162: Remove unnecessary comment in user_access_token_store.go
Removed redundant comment in Search method explaining the use of qualified column names, as the code is self-documenting.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* MM-62162: Use t.Cleanup() for token cleanup in userAccessTokenPagination test
* MM-62162: Handle error in Cleanup function
* linting
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
* MM-62154: Avoid SELECT * in webhook_store.go
- Defined column list functions for both IncomingWebhooks and OutgoingWebhooks tables
- Converted all uses of SELECT * to use the column list functions
- Used the QueryBuilder pattern for SQL queries for better consistency and readability
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* MM-62154: Improve webhook store implementation using query builders
- Refactored webhook store to follow session_store.go pattern
- Added select query builders in the constructor
- Used pre-built queries throughout the store implementation for better maintainability and performance
- Removed redundant incomingWebhookColumns() and outgoingWebhookColumns() functions
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* MM-62154: Fix whitespace style issues in webhook_store.go
- Ran gofmt to remove trailing whitespace
- Ensures consistent code formatting
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* MM-62154: Remove unnecessary int(0) casting
- Simplified DeleteAt=0 condition by removing redundant int casting
- Maintains same behavior while making code cleaner
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
* MM-62160: Avoid SELECT * in user_terms_of_service.go
- Added userTermsOfServiceSelectQuery in the constructor
- Replaced raw SQL query with query builder pattern
- Used explicit column selection instead of SELECT *
- Made the implementation more resilient to schema changes
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* MM-62160: Also avoid SELECT * in terms_of_service_store.go
- Added termsOfServiceSelectQuery field to store struct
- Replaced SELECT * with explicit column selection
- Updated GetLatest and Get methods to use the query builder pattern
- Made the implementation more resilient to schema changes
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
* MM-62155: Avoid SELECT * in team_store.go
- Added explicit column lists for all SELECT queries
- Created teamSelectQuery for reused queries
- Replaced raw SQL queries with query builder pattern
* Refactor getTeamMembersWithSchemeSelectQuery to use teamMembersQuery builder
Instead of duplicating TeamMembers columns, use the existing builder to avoid redundancy.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Remove redundant comments from getTeamMembersWithSchemeSelectQuery
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
We used < which meant we missed sending
reminders created for that timestamp, because
the job runs on that exact time.
Using <= to fix that.
https://mattermost.atlassian.net/browse/MM-63545
```release-note
NONE
```
* MM-62159: Avoid SELECT * in channel_store_categories.go
- Added sidebarCategorySelectQuery field to SqlChannelStore struct
- Replaced SELECT * with explicit column selection in GetSidebarCategory and getSidebarCategoriesT functions
- Updated raw SQL query in addChannelToFavoritesCategoryT to use explicit column selection
- Made the implementation more resilient to schema changes
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* use sc alias, simplify
* MM-62159: Fix ambiguous ID column in sidebar category queries
- Modified sidebarCategorySelectQuery initialization to explicitly use "sc" table alias for all columns
- Prevents "Column 'Id' in field list is ambiguous" error when joining with other tables
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* MM-62159: Consistently use table aliases in sidebar categories queries
- Added 'sc' table alias to all sidebar category queries
- Ensures consistency and avoids ambiguous column errors in future joins
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* MM-62159: Replace 'sc' alias with full 'SidebarCategories' table name
- Replaced all instances of the 'sc' alias with the full table name 'SidebarCategories'
- Updated the SidebarCategories query builder to use the full table name
- Removed commented-out debug printf statement
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
When a search term is a fully quoted string, we want to avoid
stemming if it is supported by the search backend.
For Postgres, it does provide a feature by which if we use the
"simple" search config, then no stemming is performed and an exact
match with the word is done without having to resort
to LIKE queries.
Unfortunately, for ES/OS this is not an option because
the message field is a text field, which means ES/OS will analyze it,
stem it and store it in its root form. Therefore, no exact match
can be possible with ES/OS.
The only solution here is to have yet another keyword field
for message which will store it in its raw form. But this
will effectively double the disk storage for post indices
and not a good design choice.
Ref: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html#avoid-term-query-text-fieldshttps://mattermost.atlassian.net/browse/MM-60790
```release-note
NONE
```
* re-arrange the tests to run only on DB
```release-note
NONE
```
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
* Update Go version to v1.23.7
* Bump golangci-lint to a version supporting Go 1.23
* Fix golangci-lint warnings
Several rules from gosimple, revive and staticcheck linters were
failing:
- Redefinition of built-in identifiers (max, min, new, recover...)
- Use of printf-like functions with simple strings
- Check for nil slices, when len already takes it into account
* Trigger Build
* Trigger Build
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
* ClaimJob now returns newly claimed job
* internal code affected by change
* test changes required
* two branches: for mysql, use transaction; for postgres, use returning
* two branches: for mysql, use transaction; for postgres, use returning
* use same millis value for LastActivityAt and StartAt
* blank commit
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
* MM-62161: Replace SELECT * in session_store.go
- Replaced all SELECT * queries with explicit column selection
- Used query builder instead of raw SQL strings where possible
- Added reusable sessionSelectQuery in the store constructor
- Added comprehensive test for GetSessionsWithActiveDeviceIds
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix variable shadowing issues in session_store.go
Resolved variable shadowing by reassigning to the existing error variables instead of declaring new ones in scoped blocks.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix code formatting in session_store test file
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Updates the property service and store method signatures
Getters can now receive a `groupID` that narrows down the query if
present, so it's not necessary to check for the group ID on the
returning values from the outside layers.
The Search methods now receive the `groupID` and the `targetID`
explicitly as parameters, incentivizing the use of the indexes that
the underlying tables have on the searches.
* Fix tests
---------
Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
Co-authored-by: Mattermost Build <build@mattermost.com>
* MM-63205 Revert emoji store methods to return empty arrays instead of nil
* Update tests for getEmojiList
* Add case to TestGetEmojisByNames
* Update tests for searchEmoji and autocompleteEmoji
* Bump Go version to 1.23.6
* Update CodeQL Github action as well
* Use server's Go version for CodeQL action
Co-authored-by: Antonis Stamatiou <stamatiou.antonis@gmail.com>
* Empty commit to trigger CI
* Bump golangci-lint to a version supporting Go 1.23
* Fix golangci-lint warnings
Several rules from gosimple, revive and staticcheck linters were
failing:
- Redefinition of built-in identifiers (max, min, new, recover...)
- Use of printf-like functions with simple strings
- Check for nil slices, when len already takes it into account
---------
Co-authored-by: Antonis Stamatiou <stamatiou.antonis@gmail.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
* Adde MySQL and Postgres migrations
* Replaced select * with column names
* removed all * from channel SQL store
* cleanup
* Fixed a duplicate column
* cleanup
* Added migrations and store support
* WIP
* used channelname slice in a missed place
* Handled patch
* Added app level tests
* Added API layer tests
* Added API layer tests
* WIP
* converted to query builder
* cleanupo
* added not null and default constraints
* Fixed test
* fixed file name
* review fixes
* review fixes
* updated migration file
* fixed text
* Review fixes
* Adde MySQL and Postgres migrations
* Replaced select * with column names
* removed all * from channel SQL store
* cleanup
* Fixed a duplicate column
* cleanup
* used channelname slice in a missed place
* WIP
* converted to query builder
* cleanupo
* Review fixes
* refactor: Replace pagination with cursor-based pagination for custom profile attributes
* remove pagination loop on property value retrieval for CPA
* add migrations to optimize pagination on property fields and values
* adapt test to remove pagination check
* update migrations list
* postgres: drop index concurrently
* concurrent index manipulation must be done outside of a Tx
* fix: Correct SQL index drop syntax from "OM" to "ON" in migration files
* test: Add CountForGroup test cases for property field store
* refactor: Add CountForGroup method to PropertyFieldStore interface and implementations
* Fix style and i18n
* feat: Add optional deleted property field filtering to CountForGroup method
* refactor: Update CountForGroup to support optional deleted property fields
* test: Add comprehensive tests for CountForGroup with includeDeleted parameter
* adapt test + gen layers
* rename property service method and set the includeDelete to false
* refactor: Remove redundant constant and use CustomProfileAttributesFieldLimit directly
* fix tests
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
* 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>
* Revert "Revert "[MM-62142] Avoid SELECT * in status_store.go (#29610)" (#29985)"
This reverts commit d345e92136.
* add tests for StatusGet and StatusGetByIds
* handle NULL columns in the Status Store
* simplify status store
* more builder simplifications and tests
* expose GetQueryPlaceholder
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
* add SelectBuilderCtx; change the few calls where it's appropriate to use
* tests (wip)
* tests improved
* use SelectCtx's own WithTimeout
* improve tests based on PR feedback
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
* refactor: Move property value sanitization to model layer
* feat: Add value sanitization for custom profile attributes
* refactor: Update custom profile attributes to use json.RawMessage
* refactor: Update patchCustomProfileAttribute to handle json.RawMessage directly
* refactor: Refactor custom profile attributes handler with improved validation
* refactor: Rename `patchCustomProfileAttribute` to `patchCPAValues`
* refactor: Replace ReturnJSON with json.NewEncoder and add error logging
* feat: Add encoding/json import to property_value.go
* refactor: Update property value tests to use json.RawMessage
* fix: Convert string value to json.RawMessage in property value test
* fix: Convert string literals to json.RawMessage in property value tests
* fix: Add missing encoding/json import in custom_profile_attributes.go
* fix: Preserve JSON RawMessage type in listCPAValues function
* fix: Update custom profile attributes test to use json.RawMessage
* feat: Add json import to custom_profile_attributes_test.go
* refactor: Update ListCPAValues and PatchCPAValues to use json.RawMessage
* refactor: Rename `actualValue` to `updatedValue` in custom profile attributes test
* refactor: Improve user permission and audit logging for custom profile attributes patch
* refactor: Optimize CPA field lookup by using ListCPAFields() and map
* fix: Correct user ID reference in custom profile attributes patch endpoint
* refactor: Change patchCPAValues to use map[string]json.RawMessage for results
* refactor: format and fix tests
* test: Add comprehensive unit tests for sanitizePropertyValue function
* test: Add test case for invalid property value type
* feat: Use `model.NewId()` to generate valid IDs in custom profile attributes tests
* refactor: Replace hardcoded IDs with dynamic variables in custom profile attributes test
* refactor: restore variable name
* refactor: drop undesired changes
* chore: refresh app layers
* feat: Update API definition to support string or string array values for custom profile attributes
* test: Add test cases for multiselect custom profile attribute values
* test: Add tests for multiselect custom profile attribute values
* test: Isolate array value test in separate t.Run
* test: Add test case for multiselect array values in custom profile attributes
* refactor: Move array value test from TestCreateCPAField to TestPatchCPAValue
* test: Update custom profile attributes test assertions
* test: add test case for handling array values in GetCPAValue
* test: Add array value tests for property value store
* refactor(store): no need to convert to json the rawmessage
* chore: lint
* i18n
* use model to interface with sqlx
* fix: Allow empty strings for text, date, and select profile attributes
* refactor: Filter out empty strings in multiselect and multiuser fields
* refactor: Update multiuser field sanitization to validate and error on invalid IDs
* refactor: Simplify sanitizePropertyValue function with reduced code duplication
* fix: Allow empty user ID in custom profile attribute sanitization
* refactor: Convert comment-based subtests to nested t.Run in TestSanitizePropertyValue
* refactor: Convert comment-based subtests to nested t.Run tests in TestSanitizePropertyValue
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
* Step 1: Migrate any SELECT * queries written as strings into builder queries.
* Step 2: Migrate any instances of SELECT * into explicitly enumerating the needed columns
* revert `GetByName` to read from master as opposed to master.
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
* SELECT * to query builder
* execBuilder, manual column name and one more select * remaining instance
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
* migrate Token Store GetByToken query to SQLBuilder
* explicitly enumerate columns, factor out query into constructor
* fix syntax error
* fix error handling
* spread args... instead of passing the array as a single param
* fix MySQL by casing columns correctly
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Jesse Hallam <jesse.hallam@gmail.com>
Within the Users and Groups store, converge on just naming the `Users`
table instead of sometimes aliasing it and sometimes not. This makes an
informal, but unambiguous interface when sharing logic between stores,
and simplifies the next step of refactoring away from `Users.*` queries.
Relates-to: MM-62158