We were redirecting any logging happening via the Go standard logger
to our own mlog instance. The issue is that all those logs were happening
at LvlStdLog level which is higher than LvlDebug.
LvlStdLog is at 10, and LvlDebug is at 5. So unless a customer
sets the log level specifically to "stdlog" or sets up advanced
logging to specifically log for that level, no standard logs will
ever get logged.
We fix this by logging it at warn level. The reason for warn
is that mostly external libraries use this facility to log
out-of-band errors that could not be returned using standard
error returns.
I saw another plugin error which was logged similarly. This
was never surfaced before due to this bug.
https://mattermost.atlassian.net/browse/MM-62926
```release-note
NONE
```
* 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>
* do not error on exportFile error
* add tests for local and s3 storage exporting with missing file
* linting
* fix attachment path validation in mmctl
* Prompt Team Admin before joining private channel
* fix and implement prompt when team admin joins via channel link
* update premission check and unit tests
* remove comment
* clean up some code
* update check to fix E2E tests
* Audit calls to searchPosts API
* Update server/public/model/post_search_results.go
Co-authored-by: Ben Schumacher <ben.schumacher@mattermost.com>
* Update server/public/model/post_search_results.go
* Update server/public/model/post_search_results.go
---------
Co-authored-by: Ben Schumacher <ben.schumacher@mattermost.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
We add a new field delete_at in the channels template.
This field is then searched in the SearchChannels function.
Also added tests to verify that archived channels are searched
properly, and also indexed correctly.
https://mattermost.atlassian.net/browse/MM-62295
```release-note
- Now archived channels are searchable with ES/OS if TeamSettings.ExperimentalViewArchivedChannels is enabled.
- If there are old channels which were archived before a bulk index was run, users would need to purge indexes, and do bulk index again. Because those old archived channels are removed from the index when a bulk index is run.
```
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>
* Fix flakyness in channel bookmark tests
* Use existing util to initialize client
* Update server/channels/api4/apitestlib.go
Co-authored-by: Ben Schumacher <ben.schumacher@mattermost.com>
* Remove redundant close
---------
Co-authored-by: Ben Schumacher <ben.schumacher@mattermost.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
* Adds Custom Profile Attributes feature license and API endpoints check
* Fix linter
* Remove the specific license feature and fallback to checking for license presence
* Add translation
* Update the checks and tests to enable endpoints only for Enterprise licenses
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
* fix for deleting non-bulk export files and directories
* add job worker setup and running to helper_test.go
* add infrastructure for e2e testing of workers; test ExportDelete
* linting
* use retention days in test instead of magic number
* SELECT * to query builder
* execBuilder, manual column name and one more select * remaining instance
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
There are several steps that a server runs through inside (*Server).Start
after ch.initPlugins() till the signal handler is reached which handles
the server shutdown procedure.
The issue arises when the server is shutdown after ch.initPlugins() completes
but before (*Server).Start finishes. In that case, the plugins are all started
but they won't be shut down cleanly.
To fix this edge-case, we set up an intermediate signal handler, which
attaches itself as soon as ch.initPlugins is finished, allowing us to run
the cleanup code in case the shutdown happens before (*Server).Start finishes.
And when we do reach the main signal handler, we don't need this intermediate
handler any more. So we just reset the handlers and use the main signal handler
which takes care of shutting down the whole server.
Note: This is still not 100% bug-proof because ch.initPlugins() will initialize
_all_ plugins, and the shutdown can happen just after one plugin is initialized.
To handle that case will require the need to set up signal handlers after every
plugin init which feels like overkill to me.
A sample flow diagram to visualize better:
Edge-case
server.Start()
|
ch.initPlugins()
|
<ctrl-c>
|
execute signal handler, os.Exit(1)
Happy-path
server.Start()
|
ch.initPlugins()
|
server.Start() finished
|
reset old signal handler
|
setup main signal handler
|
server runs on as usual until shutdown
https://mattermost.atlassian.net/browse/MM-49353
```release-note
NONE
```
* 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>
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>
* MM-61865: Add mobile client content load network metrics
* added new common label
* renaming from MobileClientContentLoad to MobileClientNetworkRequests
* content_load_group => network_request_group
* refactor more NetworkRequest-* changes
* replace contentLoadGroup to networkRequestGroup
* new metrics elapsedTime
* Refactor urlCount to totalRequests
* add averageSpeed metric
* replace contentLoadGroup with networkRequestGroup
* use h.Labels vs commonLabels for network_request_group
* add agent
* add effective latency metrics
* add total parallel requests & total sequential
* mocks generated by mockery
* did a bit of cleanup and sorting
* formatting
* updated the AcceptedNetworkRequestGroups
* cleanup and sorting
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