From a3e171f730781dc87e5eb0f36d556f9eb39fc22a Mon Sep 17 00:00:00 2001 From: Ben Schumacher Date: Mon, 24 Aug 2026 10:35:12 +0200 Subject: [PATCH] [MM-70224] Migrate property field reads to request context (#37636) * Migrate property field reads to request context Co-authored-by: Ben Schumacher * Preserve nil property service request context behavior Co-authored-by: Ben Schumacher * Use explicit session attributes system context Co-authored-by: Ben Schumacher * Use non-nil property contexts for internal calls Co-authored-by: Ben Schumacher * Thread request context through content flagging lookups Co-authored-by: Ben Schumacher * Update content flagging helper tests for request context Co-authored-by: Ben Schumacher * Thread request context through content flagging values Co-authored-by: Ben Schumacher * 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 * 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 * 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 * 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 Co-authored-by: Ben Schumacher Co-authored-by: Mattermost Build Co-authored-by: Claude Sonnet 5 --- server/channels/api4/content_flagging.go | 6 +- server/channels/app/access_control.go | 4 +- server/channels/app/content_flagging.go | 66 ++++----- .../app/content_flagging_exposure_report.go | 6 +- .../channels/app/content_flagging_report.go | 6 +- .../app/content_flagging_report_test.go | 4 +- server/channels/app/content_flagging_test.go | 92 ++++++------ server/channels/app/migrations.go | 38 ++--- server/channels/app/migrations_test.go | 10 +- .../channels/app/properties/access_control.go | 42 +++--- .../access_control_attribute_validation.go | 32 ++--- .../channels/app/properties/property_field.go | 45 +++--- .../channels/app/properties/property_value.go | 41 +++--- .../app/properties/session_attributes.go | 21 ++- .../app/properties/session_attributes_test.go | 5 +- server/channels/app/session_attributes.go | 13 +- server/channels/store/context.go | 10 +- server/channels/store/context_test.go | 8 -- .../layer_generators/retry_layer.go.tmpl | 1 - .../layer_generators/timer_layer.go.tmpl | 1 - .../store/localcachelayer/main_test.go | 3 +- .../localcachelayer/property_field_layer.go | 6 +- .../property_field_layer_test.go | 19 +-- .../channels/store/retrylayer/retrylayer.go | 21 ++- server/channels/store/sqlstore/context.go | 8 -- .../channels/store/sqlstore/context_test.go | 12 -- .../store/sqlstore/property_field_store.go | 26 ++-- server/channels/store/store.go | 11 +- .../storetest/mocks/PropertyFieldStore.go | 93 ++++++------ .../store/storetest/property_field_store.go | 133 +++++++++--------- .../channels/store/timerlayer/timerlayer.go | 21 ++- 31 files changed, 388 insertions(+), 416 deletions(-) diff --git a/server/channels/api4/content_flagging.go b/server/channels/api4/content_flagging.go index b015151355e..867546b9f15 100644 --- a/server/channels/api4/content_flagging.go +++ b/server/channels/api4/content_flagging.go @@ -87,7 +87,7 @@ func requireFlaggedPost(c *Context, postId string) { return } - _, appErr := c.App.GetPostContentFlaggingPropertyValue(postId, app.ContentFlaggingPropertyNameStatus) + _, appErr := c.App.GetPostContentFlaggingPropertyValue(c.AppContext, postId, app.ContentFlaggingPropertyNameStatus) if appErr != nil { c.Err = appErr return @@ -252,7 +252,7 @@ func getContentFlaggingFields(c *Context, w http.ResponseWriter, r *http.Request return } - mappedFields, appErr := c.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := c.App.GetContentFlaggingMappedFields(c.AppContext, groupId) if appErr != nil { c.Err = appErr return @@ -300,7 +300,7 @@ func getPostPropertyValues(c *Context, w http.ResponseWriter, r *http.Request) { return } - propertyValues, appErr := c.App.GetPostContentFlaggingPropertyValues(postId) + propertyValues, appErr := c.App.GetPostContentFlaggingPropertyValues(c.AppContext, postId) if appErr != nil { c.Err = appErr return diff --git a/server/channels/app/access_control.go b/server/channels/app/access_control.go index 86404596b52..9f90d5a45ed 100644 --- a/server/channels/app/access_control.go +++ b/server/channels/app/access_control.go @@ -1710,7 +1710,7 @@ func (a *App) GetAccessControlPolicyAttributes(rctx request.CTX, channelID strin for fieldName := range attributes { // Read directly from the store so this security filter sees the raw // access_mode, unaffected by property read hooks for the request caller. - field, fieldErr := a.Srv().Store().PropertyField().GetFieldByNameForObjectType(rctx.Context(), cpaGroup.ID, "", model.PropertyFieldObjectTypeUser, fieldName) + field, fieldErr := a.Srv().Store().PropertyField().GetFieldByNameForObjectType(rctx, cpaGroup.ID, "", model.PropertyFieldObjectTypeUser, fieldName) if fieldErr != nil { delete(attributes, fieldName) continue @@ -2518,7 +2518,7 @@ func (a *App) BuildAccessControlSubjectForSession(rctx request.CTX, channelID st return nil, appErr } - attrs, appErr := a.GetSessionAttributes(rctx.Session().Id) + attrs, appErr := a.GetSessionAttributes(rctx, rctx.Session().Id) if appErr != nil { return nil, appErr } diff --git a/server/channels/app/content_flagging.go b/server/channels/app/content_flagging.go index a085e250f23..babfb50990d 100644 --- a/server/channels/app/content_flagging.go +++ b/server/channels/app/content_flagging.go @@ -101,12 +101,12 @@ func (a *App) FlagPost(rctx request.CTX, post *model.Post, teamId, reportingUser return appErr } - appErr = a.canFlagPost(groupId, post.Id, reportingUser.Locale) + appErr = a.canFlagPost(rctx, groupId, post.Id, reportingUser.Locale) if appErr != nil { return appErr } - mappedFields, appErr := a.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := a.GetContentFlaggingMappedFields(rctx, groupId) if appErr != nil { return appErr } @@ -247,7 +247,7 @@ func (a *App) ContentFlaggingGroupId() (string, *model.AppError) { return group.ID, nil } -func (a *App) GetPostContentFlaggingPropertyValue(postId, propertyFieldName string) (*model.PropertyValue, *model.AppError) { +func (a *App) GetPostContentFlaggingPropertyValue(rctx request.CTX, postId, propertyFieldName string) (*model.PropertyValue, *model.AppError) { groupId, err := a.ContentFlaggingGroupId() if err != nil { return nil, model.NewAppError("GetPostContentFlaggingPropertyValue", "app.data_spillage.get_group.error", nil, "", http.StatusInternalServerError).Wrap(err) @@ -255,13 +255,13 @@ func (a *App) GetPostContentFlaggingPropertyValue(postId, propertyFieldName stri // Content flagging fields carry no object type, so the empty object type is // their exact scope. - statusPropertyField, appErr := a.GetPropertyFieldByNameForObjectType(nil, groupId, "", "", propertyFieldName) + statusPropertyField, appErr := a.GetPropertyFieldByNameForObjectType(rctx, groupId, "", "", propertyFieldName) if appErr != nil { return nil, model.NewAppError("GetPostContentFlaggingPropertyValue", "app.data_spillage.get_status_property.app_error", nil, "", http.StatusInternalServerError).Wrap(appErr) } searchOptions := model.PropertyValueSearchOpts{TargetIDs: []string{postId}, PerPage: CONTENT_FLAGGING_MAX_PROPERTY_VALUES, FieldID: statusPropertyField.ID} - propertyValues, appErr := a.SearchPropertyValues(nil, groupId, searchOptions) + propertyValues, appErr := a.SearchPropertyValues(rctx, groupId, searchOptions) if appErr != nil { return nil, model.NewAppError("GetPostContentFlaggingPropertyValue", "app.data_spillage.search_status_property.app_error", nil, "", http.StatusInternalServerError).Wrap(appErr) } @@ -273,8 +273,8 @@ func (a *App) GetPostContentFlaggingPropertyValue(postId, propertyFieldName stri return propertyValues[0], nil } -func (a *App) canFlagPost(groupId, postId, userLocal string) *model.AppError { - status, appErr := a.GetPostContentFlaggingPropertyValue(postId, ContentFlaggingPropertyNameStatus) +func (a *App) canFlagPost(rctx request.CTX, groupId, postId, userLocal string) *model.AppError { + status, appErr := a.GetPostContentFlaggingPropertyValue(rctx, postId, ContentFlaggingPropertyNameStatus) if appErr != nil { if appErr.StatusCode == http.StatusNotFound { return nil @@ -299,8 +299,8 @@ func (a *App) canFlagPost(groupId, postId, userLocal string) *model.AppError { return model.NewAppError("canFlagPost", reason, nil, "", http.StatusBadRequest) } -func (a *App) CheckFlaggedPostActionable(where, postId string) (*model.PropertyValue, *model.AppError) { - status, appErr := a.GetPostContentFlaggingPropertyValue(postId, ContentFlaggingPropertyNameStatus) +func (a *App) CheckFlaggedPostActionable(rctx request.CTX, where, postId string) (*model.PropertyValue, *model.AppError) { + status, appErr := a.GetPostContentFlaggingPropertyValue(rctx, postId, ContentFlaggingPropertyNameStatus) if appErr != nil { return nil, appErr } @@ -313,8 +313,8 @@ func (a *App) CheckFlaggedPostActionable(where, postId string) (*model.PropertyV return status, nil } -func (a *App) GetContentFlaggingMappedFields(groupId string) (map[string]*model.PropertyField, *model.AppError) { - fields, appErr := a.SearchPropertyFields(nil, groupId, model.PropertyFieldSearchOpts{PerPage: CONTENT_FLAGGING_MAX_PROPERTY_FIELDS}) +func (a *App) GetContentFlaggingMappedFields(rctx request.CTX, groupId string) (map[string]*model.PropertyField, *model.AppError) { + fields, appErr := a.SearchPropertyFields(rctx, groupId, model.PropertyFieldSearchOpts{PerPage: CONTENT_FLAGGING_MAX_PROPERTY_FIELDS}) if appErr != nil { return nil, model.NewAppError("GetContentFlaggingMappedFields", "app.data_spillage.search_property_fields.app_error", nil, "", http.StatusInternalServerError).Wrap(appErr) } @@ -387,7 +387,7 @@ func (a *App) createContentReviewPost(rctx request.CTX, flaggedPostId, teamId, r FieldID: flaggedPostIdFieldId, Value: json.RawMessage(fmt.Sprintf(`"%s"`, flaggedPostId)), } - _, appErr = a.CreatePropertyValue(nil, propertyValue) + _, appErr = a.CreatePropertyValue(rctx, propertyValue) if appErr != nil { rctx.Logger().Error("Failed to create content review post property value in one of the channels", mlog.Err(appErr), mlog.String("channel_id", channel.Id), mlog.String("team_id", teamId), mlog.String("post_id", createdPost.Id)) } @@ -560,13 +560,13 @@ func (a *App) IsUserTeamContentReviewer(userId, teamId string) (bool, *model.App return slices.Contains(reviewers, userId), nil } -func (a *App) GetPostContentFlaggingPropertyValues(postId string) ([]*model.PropertyValue, *model.AppError) { +func (a *App) GetPostContentFlaggingPropertyValues(rctx request.CTX, postId string) ([]*model.PropertyValue, *model.AppError) { groupId, err := a.ContentFlaggingGroupId() if err != nil { return nil, model.NewAppError("GetPostContentFlaggingPropertyValues", "app.data_spillage.get_group.error", nil, "", http.StatusInternalServerError).Wrap(err) } - propertyValues, appErr := a.SearchPropertyValues(nil, groupId, model.PropertyValueSearchOpts{TargetIDs: []string{postId}, PerPage: CONTENT_FLAGGING_MAX_PROPERTY_VALUES}) + propertyValues, appErr := a.SearchPropertyValues(rctx, groupId, model.PropertyValueSearchOpts{TargetIDs: []string{postId}, PerPage: CONTENT_FLAGGING_MAX_PROPERTY_VALUES}) if appErr != nil { return nil, model.NewAppError("GetPostContentFlaggingPropertyValues", "app.data_spillage.search_property_values.app_error", nil, "", http.StatusInternalServerError).Wrap(appErr) } @@ -593,7 +593,7 @@ func (a *App) PermanentDeleteFlaggedPost(rctx request.CTX, actionRequest *model. // generating unsafe JSON values commentJsonValue := json.RawMessage(commentBytes) - status, appErr := a.CheckFlaggedPostActionable("PermanentlyRemoveFlaggedPost", flaggedPost.Id) + status, appErr := a.CheckFlaggedPostActionable(rctx, "PermanentlyRemoveFlaggedPost", flaggedPost.Id) if appErr != nil { return appErr } @@ -617,12 +617,12 @@ func (a *App) PermanentDeleteFlaggedPost(rctx request.CTX, actionRequest *model. return appErr } - mappedFields, appErr := a.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := a.GetContentFlaggingMappedFields(rctx, groupId) if appErr != nil { return appErr } - existingComment, appErr := a.GetPostContentFlaggingPropertyValue(flaggedPost.Id, contentFlaggingPropertyNameActorComment) + existingComment, appErr := a.GetPostContentFlaggingPropertyValue(rctx, flaggedPost.Id, contentFlaggingPropertyNameActorComment) if appErr != nil && appErr.StatusCode != http.StatusNotFound { return appErr } @@ -877,7 +877,7 @@ func (a *App) KeepFlaggedPost(rctx request.CTX, actionRequest *model.FlagContent // for keeping a flagged flaggedPost we need to- // 1. Undelete the flaggedPost if it was deleted, that's it - status, appErr := a.CheckFlaggedPostActionable("KeepFlaggedPost", flaggedPost.Id) + status, appErr := a.CheckFlaggedPostActionable(rctx, "KeepFlaggedPost", flaggedPost.Id) if appErr != nil { return appErr } @@ -887,12 +887,12 @@ func (a *App) KeepFlaggedPost(rctx request.CTX, actionRequest *model.FlagContent return model.NewAppError("KeepFlaggedPost", "app.data_spillage.get_group.error", nil, "", http.StatusInternalServerError).Wrap(err) } - mappedFields, appErr := a.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := a.GetContentFlaggingMappedFields(rctx, groupId) if appErr != nil { return appErr } - contentFlaggingManaged, appErr := a.GetPostContentFlaggingPropertyValue(flaggedPost.Id, contentFlaggingPropertyManageByContentFlagging) + contentFlaggingManaged, appErr := a.GetPostContentFlaggingPropertyValue(rctx, flaggedPost.Id, contentFlaggingPropertyManageByContentFlagging) if appErr != nil && appErr.StatusCode != http.StatusNotFound { return appErr } @@ -927,7 +927,7 @@ func (a *App) KeepFlaggedPost(rctx request.CTX, actionRequest *model.FlagContent // generating unsafe JSON values commentJsonValue := json.RawMessage(commentBytes) - existingComment, appErr := a.GetPostContentFlaggingPropertyValue(flaggedPost.Id, contentFlaggingPropertyNameActorComment) + existingComment, appErr := a.GetPostContentFlaggingPropertyValue(rctx, flaggedPost.Id, contentFlaggingPropertyNameActorComment) if appErr != nil && appErr.StatusCode != http.StatusNotFound { return appErr } @@ -958,13 +958,13 @@ func (a *App) KeepFlaggedPost(rctx request.CTX, actionRequest *model.FlagContent }) } - _, appErr = a.CreatePropertyValues(nil, propertyValues) + _, appErr = a.CreatePropertyValues(rctx, propertyValues) if appErr != nil { return model.NewAppError("KeepFlaggedPost", "app.data_spillage.create_property_values.app_error", nil, "", http.StatusInternalServerError).Wrap(appErr) } status.Value = json.RawMessage(fmt.Sprintf(`"%s"`, model.ContentFlaggingStatusRetained)) - _, appErr = a.UpdatePropertyValue(nil, groupId, status) + _, appErr = a.UpdatePropertyValue(rctx, groupId, status) if appErr != nil { return model.NewAppError("KeepFlaggedPost", "app.data_spillage.keep_post.status_update.app_error", nil, "", http.StatusInternalServerError).Wrap(appErr) } @@ -1147,7 +1147,7 @@ func (a *App) SearchReviewers(rctx request.CTX, term string, teamId string) ([]* } func (a *App) AssignFlaggedPostReviewer(rctx request.CTX, flaggedPostId, flaggedPostTeamId, reviewerId, assigneeId string) *model.AppError { - statusPropertyValue, appErr := a.GetPostContentFlaggingPropertyValue(flaggedPostId, ContentFlaggingPropertyNameStatus) + statusPropertyValue, appErr := a.GetPostContentFlaggingPropertyValue(rctx, flaggedPostId, ContentFlaggingPropertyNameStatus) if appErr != nil { return appErr } @@ -1159,7 +1159,7 @@ func (a *App) AssignFlaggedPostReviewer(rctx request.CTX, flaggedPostId, flagged return model.NewAppError("AssignFlaggedPostReviewer", "app.data_spillage.get_group.error", nil, "", http.StatusInternalServerError).Wrap(err) } - mappedFields, appErr := a.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := a.GetContentFlaggingMappedFields(rctx, groupId) if appErr != nil { return appErr } @@ -1263,8 +1263,8 @@ func (a *App) postKeepPostReviewerMessage(rctx request.CTX, flaggedPostId, actor return a.postReviewerMessage(rctx, message, contentFlaggingGroupId, flaggedPostId, nil, "") } -func (a *App) getReporterUserId(flaggedPostId, contentFlaggingGroupId string) (string, *model.AppError) { - mappedFields, appErr := a.GetContentFlaggingMappedFields(contentFlaggingGroupId) +func (a *App) getReporterUserId(rctx request.CTX, flaggedPostId, contentFlaggingGroupId string) (string, *model.AppError) { + mappedFields, appErr := a.GetContentFlaggingMappedFields(rctx, contentFlaggingGroupId) if appErr != nil { return "", appErr } @@ -1274,7 +1274,7 @@ func (a *App) getReporterUserId(flaggedPostId, contentFlaggingGroupId string) (s return "", model.NewAppError("getReporterUserId", "app.data_spillage.missing_reporting_user_id_field.app_error", nil, "", http.StatusInternalServerError) } - propertyValues, appErr := a.GetPostContentFlaggingPropertyValues(flaggedPostId) + propertyValues, appErr := a.GetPostContentFlaggingPropertyValues(rctx, flaggedPostId) if appErr != nil { return "", appErr } @@ -1321,7 +1321,7 @@ func (a *App) postContentReviewBotMessage(rctx request.CTX, message string, reci } func (a *App) postMessageToReporter(rctx request.CTX, contentFlaggingGroupId string, flaggedPost *model.Post, message string) (*model.Post, *model.AppError) { - userId, appErr := a.getReporterUserId(flaggedPost.Id, contentFlaggingGroupId) + userId, appErr := a.getReporterUserId(rctx, flaggedPost.Id, contentFlaggingGroupId) if appErr != nil { return nil, appErr } @@ -1330,7 +1330,7 @@ func (a *App) postMessageToReporter(rctx request.CTX, contentFlaggingGroupId str } func (a *App) postReviewerMessage(rctx request.CTX, message, contentFlaggingGroupId, flaggedPostId string, report *model.PostDeletionReport, reportFileName string) ([]*model.Post, *model.AppError) { - mappedFields, appErr := a.GetContentFlaggingMappedFields(contentFlaggingGroupId) + mappedFields, appErr := a.GetContentFlaggingMappedFields(rctx, contentFlaggingGroupId) if appErr != nil { return nil, appErr } @@ -1340,7 +1340,7 @@ func (a *App) postReviewerMessage(rctx request.CTX, message, contentFlaggingGrou return nil, model.NewAppError("postReviewerMessage", "app.data_spillage.missing_flagged_post_id_field.app_error", nil, "", http.StatusInternalServerError) } - postIds, appErr := a.getReviewerPostsForFlaggedPost(contentFlaggingGroupId, flaggedPostId, flaggedPostIdField.ID) + postIds, appErr := a.getReviewerPostsForFlaggedPost(rctx, contentFlaggingGroupId, flaggedPostId, flaggedPostIdField.ID) if appErr != nil { return nil, appErr } @@ -1414,7 +1414,7 @@ func (a *App) postReviewerMessage(rctx request.CTX, message, contentFlaggingGrou return createdPosts, nil } -func (a *App) getReviewerPostsForFlaggedPost(contentFlaggingGroupId, flaggedPostId, flaggedPostIdFieldId string) ([]string, *model.AppError) { +func (a *App) getReviewerPostsForFlaggedPost(rctx request.CTX, contentFlaggingGroupId, flaggedPostId, flaggedPostIdFieldId string) ([]string, *model.AppError) { searchOptions := model.PropertyValueSearchOpts{ TargetType: model.PropertyValueTargetTypePost, Value: json.RawMessage(fmt.Sprintf(`"%s"`, flaggedPostId)), @@ -1426,7 +1426,7 @@ func (a *App) getReviewerPostsForFlaggedPost(contentFlaggingGroupId, flaggedPost var propertyValues []*model.PropertyValue for { - batch, appErr := a.SearchPropertyValues(nil, contentFlaggingGroupId, searchOptions) + batch, appErr := a.SearchPropertyValues(rctx, contentFlaggingGroupId, searchOptions) if appErr != nil { return nil, model.NewAppError("getReviewerPostsForFlaggedPost", "app.data_spillage.search_reviewer_posts.app_error", nil, "", http.StatusInternalServerError).Wrap(appErr) } diff --git a/server/channels/app/content_flagging_exposure_report.go b/server/channels/app/content_flagging_exposure_report.go index 1ca2cfcd6e1..95d2688e806 100644 --- a/server/channels/app/content_flagging_exposure_report.go +++ b/server/channels/app/content_flagging_exposure_report.go @@ -41,7 +41,7 @@ func (a *App) ComputePostExposure(rctx request.CTX, postID string) (*model.PostE return nil, model.NewAppError("ComputePostExposure", "app.data_spillage.exposure.unsupported_channel_type.app_error", nil, "", http.StatusBadRequest) } - windowEnd, appErr := a.getPostFlagTime(post.Id) + windowEnd, appErr := a.getPostFlagTime(rctx, post.Id) if appErr != nil { return nil, appErr } @@ -131,8 +131,8 @@ func (a *App) ComputePostExposure(rctx request.CTX, postID string) (*model.PostE return report, nil } -func (a *App) getPostFlagTime(postID string) (int64, *model.AppError) { - value, appErr := a.GetPostContentFlaggingPropertyValue(postID, contentFlaggingPropertyNameReportingTime) +func (a *App) getPostFlagTime(rctx request.CTX, postID string) (int64, *model.AppError) { + value, appErr := a.GetPostContentFlaggingPropertyValue(rctx, postID, contentFlaggingPropertyNameReportingTime) if appErr != nil { if appErr.StatusCode == http.StatusNotFound { return 0, model.NewAppError("getPostFlagTime", "app.data_spillage.exposure.missing_reporting_time.app_error", nil, "", http.StatusInternalServerError) diff --git a/server/channels/app/content_flagging_report.go b/server/channels/app/content_flagging_report.go index a6ad1c5d298..4b4db2fab97 100644 --- a/server/channels/app/content_flagging_report.go +++ b/server/channels/app/content_flagging_report.go @@ -255,7 +255,7 @@ func buildPostYAML(post *model.Post, channel *model.Channel, team *model.Team, a func (a *App) buildContentReviewYAML(rctx request.CTX, post *model.Post, generatedByUserID, actorComment, pendingAction string) (model.FlaggedPostReportContentReview, *model.AppError) { out := model.FlaggedPostReportContentReview{} - values, appErr := a.GetPostContentFlaggingPropertyValues(post.Id) + values, appErr := a.GetPostContentFlaggingPropertyValues(rctx, post.Id) if appErr != nil { return out, appErr } @@ -264,7 +264,7 @@ func (a *App) buildContentReviewYAML(rctx request.CTX, post *model.Post, generat if gErr != nil { return out, gErr } - mappedFields, appErr := a.GetContentFlaggingMappedFields(groupID) + mappedFields, appErr := a.GetContentFlaggingMappedFields(rctx, groupID) if appErr != nil { return out, appErr } @@ -289,7 +289,7 @@ func (a *App) buildContentReviewYAML(rctx request.CTX, post *model.Post, generat out.ReporterComment = decodePropertyString(rctx, byName, contentFlaggingPropertyNameReportingComment) out.ReportTimestamp = decodePropertyInt64(rctx, byName, contentFlaggingPropertyNameReportingTime) - contentFlaggingManaged, appErr := a.GetPostContentFlaggingPropertyValue(post.Id, contentFlaggingPropertyManageByContentFlagging) + contentFlaggingManaged, appErr := a.GetPostContentFlaggingPropertyValue(rctx, post.Id, contentFlaggingPropertyManageByContentFlagging) if appErr != nil && appErr.StatusCode != http.StatusNotFound { return out, appErr } diff --git a/server/channels/app/content_flagging_report_test.go b/server/channels/app/content_flagging_report_test.go index b75252a65d5..12f64f779ac 100644 --- a/server/channels/app/content_flagging_report_test.go +++ b/server/channels/app/content_flagging_report_test.go @@ -568,10 +568,10 @@ func TestNotifyReviewersOfPostExposureReportGeneration(t *testing.T) { groupID, appErr := th.App.ContentFlaggingGroupId() require.Nil(t, appErr) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupID) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupID) require.Nil(t, appErr) - rootPostIDs, appErr := th.App.getReviewerPostsForFlaggedPost(groupID, postID, mappedFields[contentFlaggingPropertyNameFlaggedPostId].ID) + rootPostIDs, appErr := th.App.getReviewerPostsForFlaggedPost(th.Context, groupID, postID, mappedFields[contentFlaggingPropertyNameFlaggedPostId].ID) require.Nil(t, appErr) require.NotEmpty(t, rootPostIDs) diff --git a/server/channels/app/content_flagging_test.go b/server/channels/app/content_flagging_test.go index 6f14bba1c94..e39fcf824fc 100644 --- a/server/channels/app/content_flagging_test.go +++ b/server/channels/app/content_flagging_test.go @@ -41,7 +41,7 @@ func searchPropertyValue(t *testing.T, th *TestHelper, postId, fieldName string) groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) values, appErr2 := th.App.SearchPropertyValues(th.Context, groupId, model.PropertyValueSearchOpts{ @@ -193,7 +193,7 @@ func TestAssignFlaggedPostReviewer(t *testing.T) { require.Nil(t, appErr) // Verify status was updated to assigned - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusAssigned+`"`, string(statusValue.Value)) @@ -201,7 +201,7 @@ func TestAssignFlaggedPostReviewer(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) reviewerValues, err := th.App.SearchPropertyValues(rctx, groupId, model.PropertyValueSearchOpts{ @@ -228,7 +228,7 @@ func TestAssignFlaggedPostReviewer(t *testing.T) { require.Nil(t, appErr) // Verify status remains assigned - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusAssigned+`"`, string(statusValue.Value)) @@ -236,7 +236,7 @@ func TestAssignFlaggedPostReviewer(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) reviewerValues, err := th.App.SearchPropertyValues(rctx, groupId, model.PropertyValueSearchOpts{ @@ -272,7 +272,7 @@ func TestAssignFlaggedPostReviewer(t *testing.T) { require.Nil(t, appErr) // Verify status remains assigned - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusAssigned+`"`, string(statusValue.Value)) @@ -280,7 +280,7 @@ func TestAssignFlaggedPostReviewer(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) reviewerValues, err := th.App.SearchPropertyValues(rctx, groupId, model.PropertyValueSearchOpts{ @@ -302,7 +302,7 @@ func TestAssignFlaggedPostReviewer(t *testing.T) { require.Nil(t, appErr) // Verify status was updated to assigned - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusAssigned+`"`, string(statusValue.Value)) @@ -310,7 +310,7 @@ func TestAssignFlaggedPostReviewer(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) reviewerValues, err := th.App.SearchPropertyValues(rctx, groupId, model.PropertyValueSearchOpts{ @@ -338,7 +338,7 @@ func TestAssignFlaggedPostReviewer(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) // Set the status to Assigned @@ -349,7 +349,7 @@ func TestAssignFlaggedPostReviewer(t *testing.T) { appErr = th.App.AssignFlaggedPostReviewer(th.Context, post.Id, th.BasicChannel.TeamId, th.BasicUser.Id, th.SystemAdminUser.Id) require.Nil(t, appErr) - statusValue, appErr = th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr = th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusAssigned+`"`, string(statusValue.Value)) @@ -361,7 +361,7 @@ func TestAssignFlaggedPostReviewer(t *testing.T) { appErr = th.App.AssignFlaggedPostReviewer(th.Context, post.Id, th.BasicChannel.TeamId, th.BasicUser.Id, th.SystemAdminUser.Id) require.Nil(t, appErr) - statusValue, appErr = th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr = th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusRemoved+`"`, string(statusValue.Value)) @@ -373,7 +373,7 @@ func TestAssignFlaggedPostReviewer(t *testing.T) { appErr = th.App.AssignFlaggedPostReviewer(th.Context, post.Id, th.BasicChannel.TeamId, th.BasicUser.Id, th.SystemAdminUser.Id) require.Nil(t, appErr) - statusValue, appErr = th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr = th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusRetained+`"`, string(statusValue.Value)) }) @@ -997,7 +997,7 @@ func TestCanFlagPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - appErr := th.App.canFlagPost(groupId, post.Id, "en") + appErr := th.App.canFlagPost(th.Context, groupId, post.Id, "en") require.Nil(t, appErr) }) @@ -1020,7 +1020,7 @@ func TestCanFlagPost(t *testing.T) { require.Nil(t, err) // Can't fleg when post already flagged in pending status - appErr := th.App.canFlagPost(groupId, post.Id, "en") + appErr := th.App.canFlagPost(th.Context, groupId, post.Id, "en") require.NotNil(t, appErr) require.Equal(t, "Cannot quarantine this post as it is already quarantined for review.", appErr.Id) @@ -1029,7 +1029,7 @@ func TestCanFlagPost(t *testing.T) { _, err = th.App.UpdatePropertyValue(rctx, groupId, propertyValue) require.Nil(t, err) - appErr = th.App.canFlagPost(groupId, post.Id, "en") + appErr = th.App.canFlagPost(th.Context, groupId, post.Id, "en") require.NotNil(t, appErr) // Can't fleg when post already flagged in retained status @@ -1037,7 +1037,7 @@ func TestCanFlagPost(t *testing.T) { _, err = th.App.UpdatePropertyValue(rctx, groupId, propertyValue) require.Nil(t, err) - appErr = th.App.canFlagPost(groupId, post.Id, "en") + appErr = th.App.canFlagPost(th.Context, groupId, post.Id, "en") require.NotNil(t, appErr) // Can't fleg when post already flagged in removed status @@ -1045,7 +1045,7 @@ func TestCanFlagPost(t *testing.T) { _, err = th.App.UpdatePropertyValue(rctx, groupId, propertyValue) require.Nil(t, err) - appErr = th.App.canFlagPost(groupId, post.Id, "en") + appErr = th.App.canFlagPost(th.Context, groupId, post.Id, "en") require.NotNil(t, appErr) }) } @@ -1085,7 +1085,7 @@ func TestFlagPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) // Check status property @@ -1270,7 +1270,7 @@ func TestFlagPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) commentValues, err := th.App.SearchPropertyValues(rctx, groupId, model.PropertyValueSearchOpts{ @@ -1304,7 +1304,7 @@ func TestFlagPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) timeValues, err := th.App.SearchPropertyValues(rctx, groupId, model.PropertyValueSearchOpts{ @@ -1636,13 +1636,13 @@ func TestGetReviewerPostsForFlaggedPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) flaggedPostIdField, ok := mappedFields[contentFlaggingPropertyNameFlaggedPostId] require.True(t, ok) - reviewerPostIds, appErr := th.App.getReviewerPostsForFlaggedPost(groupId, post.Id, flaggedPostIdField.ID) + reviewerPostIds, appErr := th.App.getReviewerPostsForFlaggedPost(th.Context, groupId, post.Id, flaggedPostIdField.ID) require.Nil(t, appErr) require.Len(t, reviewerPostIds, 1) @@ -1661,13 +1661,13 @@ func TestGetReviewerPostsForFlaggedPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) flaggedPostIdField, ok := mappedFields[contentFlaggingPropertyNameFlaggedPostId] require.True(t, ok) - reviewerPostIds, appErr := th.App.getReviewerPostsForFlaggedPost(groupId, post.Id, flaggedPostIdField.ID) + reviewerPostIds, appErr := th.App.getReviewerPostsForFlaggedPost(th.Context, groupId, post.Id, flaggedPostIdField.ID) require.Nil(t, appErr) require.Len(t, reviewerPostIds, 0) }) @@ -1695,13 +1695,13 @@ func TestGetReviewerPostsForFlaggedPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) flaggedPostIdField, ok := mappedFields[contentFlaggingPropertyNameFlaggedPostId] require.True(t, ok) - reviewerPostIds, appErr := th.App.getReviewerPostsForFlaggedPost(groupId, post.Id, flaggedPostIdField.ID) + reviewerPostIds, appErr := th.App.getReviewerPostsForFlaggedPost(th.Context, groupId, post.Id, flaggedPostIdField.ID) require.Nil(t, appErr) require.Len(t, reviewerPostIds, 2) @@ -1720,13 +1720,13 @@ func TestGetReviewerPostsForFlaggedPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) flaggedPostIdField, ok := mappedFields[contentFlaggingPropertyNameFlaggedPostId] require.True(t, ok) - reviewerPostIds, appErr := th.App.getReviewerPostsForFlaggedPost(groupId, "invalid_post_id", flaggedPostIdField.ID) + reviewerPostIds, appErr := th.App.getReviewerPostsForFlaggedPost(th.Context, groupId, "invalid_post_id", flaggedPostIdField.ID) require.Nil(t, appErr) require.Len(t, reviewerPostIds, 0) }) @@ -2267,7 +2267,7 @@ func TestPermanentDeleteFlaggedPost(t *testing.T) { require.Greater(t, updatedPost.DeleteAt, int64(0)) // Verify status was updated to removed - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusRemoved+`"`, string(statusValue.Value)) @@ -2275,7 +2275,7 @@ func TestPermanentDeleteFlaggedPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) // Check actor user property @@ -2349,7 +2349,7 @@ func TestPermanentDeleteFlaggedPost(t *testing.T) { require.Nil(t, appErr) // Verify status was updated to removed - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusRemoved+`"`, string(statusValue.Value)) }) @@ -2361,7 +2361,7 @@ func TestPermanentDeleteFlaggedPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) statusValue.Value = json.RawMessage(fmt.Sprintf(`"%s"`, model.ContentFlaggingStatusRemoved)) @@ -2385,7 +2385,7 @@ func TestPermanentDeleteFlaggedPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) statusValue.Value = json.RawMessage(fmt.Sprintf(`"%s"`, model.ContentFlaggingStatusRetained)) @@ -2428,7 +2428,7 @@ func TestPermanentDeleteFlaggedPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) commentValues, err := th.App.SearchPropertyValues(rctx, groupId, model.PropertyValueSearchOpts{ @@ -2456,7 +2456,7 @@ func TestPermanentDeleteFlaggedPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - mappedFields, appErr := th.App.GetContentFlaggingMappedFields(groupId) + mappedFields, appErr := th.App.GetContentFlaggingMappedFields(th.Context, groupId) require.Nil(t, appErr) commentValues, err := th.App.SearchPropertyValues(rctx, groupId, model.PropertyValueSearchOpts{ @@ -2525,7 +2525,7 @@ func TestPermanentDeleteFlaggedPost(t *testing.T) { }, 5*time.Second, 200*time.Millisecond) // Verify post was deleted and status updated - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusRemoved+`"`, string(statusValue.Value)) @@ -2566,7 +2566,7 @@ func TestPermanentDeleteFlaggedPost(t *testing.T) { }, 5*time.Second, 200*time.Millisecond) // Verify status was updated - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(editedPost.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, editedPost.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) // Verify statusValue.Value is a string @@ -2612,7 +2612,7 @@ func TestPermanentDeleteFlaggedPost(t *testing.T) { require.Nil(t, appErr) // Verify status was updated to removed - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(deletedPost.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, deletedPost.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) // Verify statusValue.Value is a string @@ -2848,7 +2848,7 @@ func TestKeepFlaggedPost(t *testing.T) { require.Equal(t, int64(0), updatedPost.DeleteAt) // Verify status was updated to retained - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusRetained+`"`, string(statusValue.Value)) @@ -2912,7 +2912,7 @@ func TestKeepFlaggedPost(t *testing.T) { require.Equal(t, int64(0), restoredPost.DeleteAt) // Verify status was updated to retained - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusRetained+`"`, string(statusValue.Value)) }) @@ -2935,7 +2935,7 @@ func TestKeepFlaggedPost(t *testing.T) { require.Nil(t, appErr) // Verify status was updated to retained - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusRetained+`"`, string(statusValue.Value)) }) @@ -2947,7 +2947,7 @@ func TestKeepFlaggedPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) statusValue.Value = json.RawMessage(fmt.Sprintf(`"%s"`, model.ContentFlaggingStatusRemoved)) @@ -2971,7 +2971,7 @@ func TestKeepFlaggedPost(t *testing.T) { groupId, err := th.App.ContentFlaggingGroupId() require.Nil(t, err) - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) statusValue.Value = json.RawMessage(fmt.Sprintf(`"%s"`, model.ContentFlaggingStatusRetained)) @@ -3089,7 +3089,7 @@ func TestKeepFlaggedPost(t *testing.T) { }, 5*time.Second, 200*time.Millisecond) // Verify post was retained - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(post.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, post.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) require.Equal(t, `"`+model.ContentFlaggingStatusRetained+`"`, string(statusValue.Value)) @@ -3136,7 +3136,7 @@ func TestKeepFlaggedPost(t *testing.T) { }, 5*time.Second, 200*time.Millisecond) // Verify status was updated to retained - statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(editedPost.Id, ContentFlaggingPropertyNameStatus) + statusValue, appErr := th.App.GetPostContentFlaggingPropertyValue(th.Context, editedPost.Id, ContentFlaggingPropertyNameStatus) require.Nil(t, appErr) var stringValue string diff --git a/server/channels/app/migrations.go b/server/channels/app/migrations.go index 170dc0941d4..1bc2c7db6cd 100644 --- a/server/channels/app/migrations.go +++ b/server/channels/app/migrations.go @@ -16,6 +16,7 @@ import ( "github.com/mattermost/mattermost/server/public/shared/mlog" "github.com/mattermost/mattermost/server/public/shared/request" "github.com/mattermost/mattermost/server/public/utils" + "github.com/mattermost/mattermost/server/v8/channels/app/properties" "github.com/mattermost/mattermost/server/v8/channels/store" ) @@ -645,10 +646,11 @@ func (s *Server) doSetupContentFlaggingProperties() error { if err != nil { return fmt.Errorf("failed to register Content Flagging group: %w", err) } + rctx := properties.SystemCallerContext(request.EmptyContext(s.Log())) // Using page size of 100 and not iterating through all pages because the // number of fields are static and defined here and not expected to be more than 100 for now. - existingProperties, err := s.propertyService.SearchPropertyFields(nil, group.ID, model.PropertyFieldSearchOpts{PerPage: 100}) + existingProperties, err := s.propertyService.SearchPropertyFields(rctx, group.ID, model.PropertyFieldSearchOpts{PerPage: 100}) if err != nil { return fmt.Errorf("failed to search for existing content flagging properties: %w", err) } @@ -742,18 +744,18 @@ func (s *Server) doSetupContentFlaggingProperties() error { } for _, property := range propertiesToCreate { - if _, err := s.propertyService.CreatePropertyField(nil, property); err != nil { + if _, err := s.propertyService.CreatePropertyField(rctx, property); err != nil { // Another server may have won the race and created this field // concurrently (e.g. parallel tests sharing a database pool). // Tolerate that but propagate any other error. - if _, retryErr := s.propertyService.GetPropertyFieldByNameForObjectType(nil, group.ID, "", property.ObjectType, property.Name); retryErr != nil { + if _, retryErr := s.propertyService.GetPropertyFieldByNameForObjectType(rctx, group.ID, "", property.ObjectType, property.Name); retryErr != nil { return fmt.Errorf("failed to create content flagging property: %q, error: %w", property.Name, err) } } } if len(propertiesToUpdate) > 0 { - if _, _, _, err := s.propertyService.UpdatePropertyFields(nil, group.ID, propertiesToUpdate); err != nil { + if _, _, _, err := s.propertyService.UpdatePropertyFields(rctx, group.ID, propertiesToUpdate); err != nil { // Another server may have won the race and updated these fields // concurrently (e.g. parallel tests sharing a database pool). // Both servers write the same expected values, so tolerate the @@ -787,8 +789,9 @@ func (s *Server) doSetupBoardsProperties() error { if err != nil { return fmt.Errorf("failed to register boards property group: %w", err) } + rctx := properties.SystemCallerContext(request.EmptyContext(s.Log())) - existingProperties, err := s.propertyService.SearchPropertyFields(nil, group.ID, model.PropertyFieldSearchOpts{PerPage: 100}) + existingProperties, err := s.propertyService.SearchPropertyFields(rctx, group.ID, model.PropertyFieldSearchOpts{PerPage: 100}) if err != nil { return fmt.Errorf("failed to search for existing boards properties: %w", err) } @@ -864,18 +867,18 @@ func (s *Server) doSetupBoardsProperties() error { } for _, property := range propertiesToCreate { - if _, err := s.propertyService.CreatePropertyField(nil, property); err != nil { + if _, err := s.propertyService.CreatePropertyField(rctx, property); err != nil { // Another server may have won the race and created this field // concurrently (e.g. parallel tests sharing a database pool). // Tolerate that but propagate any other error. - if _, retryErr := s.propertyService.GetPropertyFieldByNameForObjectType(nil, group.ID, "", property.ObjectType, property.Name); retryErr != nil { + if _, retryErr := s.propertyService.GetPropertyFieldByNameForObjectType(rctx, group.ID, "", property.ObjectType, property.Name); retryErr != nil { return fmt.Errorf("failed to create boards property: %q, error: %w", property.Name, err) } } } if len(propertiesToUpdate) > 0 { - if _, _, _, err := s.propertyService.UpdatePropertyFields(nil, group.ID, propertiesToUpdate); err != nil { + if _, _, _, err := s.propertyService.UpdatePropertyFields(rctx, group.ID, propertiesToUpdate); err != nil { // Another server may have won the race and updated these fields // concurrently (e.g. parallel tests sharing a database pool). // Both servers write the same expected values, so tolerate the @@ -984,7 +987,8 @@ func syncSessionAttributeOptions(current, expected *model.PropertyField) error { // seedSessionAttributeFields idempotently seeds the built-in session attribute property fields. func (s *Server) seedSessionAttributeFields(groupID string) error { - existing, err := s.propertyService.SearchPropertyFields(nil, groupID, model.PropertyFieldSearchOpts{PerPage: 100}) + rctx := properties.SystemCallerContext(request.EmptyContext(s.Log())) + existing, err := s.propertyService.SearchPropertyFields(rctx, groupID, model.PropertyFieldSearchOpts{PerPage: 100}) if err != nil { return fmt.Errorf("failed to search for existing session attribute fields: %w", err) } @@ -1023,15 +1027,15 @@ func (s *Server) seedSessionAttributeFields(groupID string) error { } for _, field := range fieldsToCreate { - if _, err := s.propertyService.CreatePropertyField(nil, field); err != nil { - if _, retryErr := s.propertyService.GetPropertyFieldByNameForObjectType(nil, groupID, "", field.ObjectType, field.Name); retryErr != nil { + if _, err := s.propertyService.CreatePropertyField(rctx, field); err != nil { + if _, retryErr := s.propertyService.GetPropertyFieldByNameForObjectType(rctx, groupID, "", field.ObjectType, field.Name); retryErr != nil { return fmt.Errorf("failed to create session attribute field: %q, error: %w", field.Name, err) } } } if len(fieldsToUpdate) > 0 { - if _, _, _, err := s.propertyService.UpdatePropertyFields(nil, groupID, fieldsToUpdate); err != nil { + if _, _, _, err := s.propertyService.UpdatePropertyFields(rctx, groupID, fieldsToUpdate); err != nil { var conflictErr *store.ErrConflict if !errors.As(err, &conflictErr) { return fmt.Errorf("failed to update session attribute fields: %w", err) @@ -1082,8 +1086,9 @@ func (s *Server) doSetupManagedCategoryProperties() error { if err != nil { return fmt.Errorf("failed to register managed category group: %w", err) } + rctx := properties.SystemCallerContext(request.EmptyContext(s.Log())) - _, err = s.propertyService.GetPropertyFieldByNameForObjectType(nil, group.ID, "", model.PropertyValueTargetTypeChannel, model.ManagedCategoryPropertyFieldName) + _, err = s.propertyService.GetPropertyFieldByNameForObjectType(rctx, group.ID, "", model.PropertyValueTargetTypeChannel, model.ManagedCategoryPropertyFieldName) if err != nil { field := &model.PropertyField{ GroupID: group.ID, @@ -1098,8 +1103,8 @@ func (s *Server) doSetupManagedCategoryProperties() error { PermissionOptions: model.NewPointer(model.PermissionLevelMember), } - if _, err := s.propertyService.CreatePropertyField(nil, field); err != nil { - if _, retryErr := s.propertyService.GetPropertyFieldByNameForObjectType(nil, group.ID, "", field.ObjectType, model.ManagedCategoryPropertyFieldName); retryErr != nil { + if _, err := s.propertyService.CreatePropertyField(rctx, field); err != nil { + if _, retryErr := s.propertyService.GetPropertyFieldByNameForObjectType(rctx, group.ID, "", field.ObjectType, model.ManagedCategoryPropertyFieldName); retryErr != nil { return fmt.Errorf("failed to create managed category field: %w", err) } } @@ -1154,8 +1159,9 @@ func (s *Server) cacheManagedCategoryIDs() error { if err != nil { return fmt.Errorf("failed to get managed category group: %w", err) } + rctx := properties.SystemCallerContext(request.EmptyContext(s.Log())) - field, err := s.propertyService.GetPropertyFieldByNameForObjectType(nil, group.ID, "", model.PropertyValueTargetTypeChannel, model.ManagedCategoryPropertyFieldName) + field, err := s.propertyService.GetPropertyFieldByNameForObjectType(rctx, group.ID, "", model.PropertyValueTargetTypeChannel, model.ManagedCategoryPropertyFieldName) if err != nil { return fmt.Errorf("failed to get managed category field: %w", err) } diff --git a/server/channels/app/migrations_test.go b/server/channels/app/migrations_test.go index 77ff511d9ac..a6ee3e9a5d7 100644 --- a/server/channels/app/migrations_test.go +++ b/server/channels/app/migrations_test.go @@ -4,13 +4,13 @@ package app import ( - "context" "encoding/json" "maps" "sync" "testing" "github.com/mattermost/mattermost/server/public/model" + "github.com/mattermost/mattermost/server/v8/channels/app/properties" "github.com/mattermost/mattermost/server/v8/channels/store" "github.com/stretchr/testify/require" ) @@ -347,7 +347,7 @@ func TestCPADisplayNameBackfill_BackfillsProtectedSourceOnlyField(t *testing.T) // Read back via the store directly to avoid any read-access filtering // the AC layer might apply for a non-source-plugin caller. - got, err := th.Store.PropertyField().Get(context.Background(), groupID, created.ID) + got, err := th.Store.PropertyField().Get(th.Context, groupID, created.ID) require.NoError(t, err) require.Equal(t, "uas_employee_id", got.Attrs[model.CustomProfileAttributesPropertyAttrsDisplayName], "display_name must be backfilled to the field name even on protected/source_only fields") @@ -481,13 +481,13 @@ func TestDoSetupSessionAttributesProperties(t *testing.T) { require.Nil(t, appErr) // Restore the pre-conversion shape a server upgrade would find: free - // text with no options. Written with a nil request context so + // text with no options. Written with a system-caller context so // SessionAttributesHook treats it as a system caller, the same way the // seed itself does. field := sessionAttributeFieldByName(t, th, group.ID, model.SessionAttributesPropertyFieldOSPlatform) field.Type = model.PropertyFieldTypeText delete(field.Attrs, model.PropertyFieldAttributeOptions) - _, _, _, err := th.Server.propertyService.UpdatePropertyFields(nil, group.ID, []*model.PropertyField{field}) + _, _, _, err := th.Server.propertyService.UpdatePropertyFields(properties.SystemCallerContext(th.Context), group.ID, []*model.PropertyField{field}) require.NoError(t, err) require.NoError(t, th.Server.doSetupSessionAttributesProperties()) @@ -539,7 +539,7 @@ func TestDoSetupSessionAttributesProperties(t *testing.T) { field := sessionAttributeFieldByName(t, th, group.ID, model.SessionAttributesPropertyFieldIPAddress) delete(field.Attrs, model.NativeAttributeAttrOperators) - _, _, _, err := th.Server.propertyService.UpdatePropertyFields(nil, group.ID, []*model.PropertyField{field}) + _, _, _, err := th.Server.propertyService.UpdatePropertyFields(properties.SystemCallerContext(th.Context), group.ID, []*model.PropertyField{field}) require.NoError(t, err) require.NoError(t, th.Server.doSetupSessionAttributesProperties()) diff --git a/server/channels/app/properties/access_control.go b/server/channels/app/properties/access_control.go index 6fb26794d88..7e3db6da476 100644 --- a/server/channels/app/properties/access_control.go +++ b/server/channels/app/properties/access_control.go @@ -124,7 +124,7 @@ func (h *AccessControlHook) PreCreatePropertyField(rctx request.CTX, field *mode } if field.LinkedFieldID != nil && *field.LinkedFieldID != "" { - if err := h.validateAndInheritLinkedFieldSecurity(callerID, field); err != nil { + if err := h.validateAndInheritLinkedFieldSecurity(rctx, callerID, field); err != nil { return nil, fmt.Errorf("PreCreatePropertyField: %w", err) } } @@ -140,8 +140,8 @@ func (h *AccessControlHook) PreCreatePropertyField(rctx request.CTX, field *mode // the source template's security posture. If the source is protected, only // the source plugin may create linked fields. Security attrs (protected, // source_plugin_id, access_mode) are copied from the source onto the field. -func (h *AccessControlHook) validateAndInheritLinkedFieldSecurity(callerID string, field *model.PropertyField) error { - source, err := h.propertyService.getPropertyFieldFromMaster("", *field.LinkedFieldID) +func (h *AccessControlHook) validateAndInheritLinkedFieldSecurity(rctx request.CTX, callerID string, field *model.PropertyField) error { + source, err := h.propertyService.getPropertyFieldFromMaster(rctx, "", *field.LinkedFieldID) if err != nil { if store.IsErrNotFound(err) { return model.NewAppError( @@ -192,7 +192,7 @@ func (h *AccessControlHook) PreUpdatePropertyField(rctx request.CTX, groupID str callerID := h.extractCallerID(rctx) - existingField, err := h.propertyService.getPropertyField(groupID, field.ID) + existingField, err := h.propertyService.getPropertyField(rctx, groupID, field.ID) if err != nil { return nil, err } @@ -231,7 +231,7 @@ func (h *AccessControlHook) PreUpdatePropertyFields(rctx request.CTX, groupID st fieldIDs[i] = field.ID } - existingFields, err := h.propertyService.getPropertyFields(groupID, fieldIDs) + existingFields, err := h.propertyService.getPropertyFields(rctx, groupID, fieldIDs) if err != nil { return nil, err } @@ -281,7 +281,7 @@ func (h *AccessControlHook) PreDeletePropertyField(rctx request.CTX, groupID str callerID := h.extractCallerID(rctx) - existingField, err := h.propertyService.getPropertyField(groupID, id) + existingField, err := h.propertyService.getPropertyField(rctx, groupID, id) if err != nil { return err } @@ -332,7 +332,7 @@ func (h *AccessControlHook) PreCreatePropertyValue(rctx request.CTX, value *mode callerID := h.extractCallerID(rctx) - field, err := h.propertyService.getPropertyField(value.GroupID, value.FieldID) + field, err := h.propertyService.getPropertyField(rctx, value.GroupID, value.FieldID) if err != nil { return nil, err } @@ -353,7 +353,7 @@ func (h *AccessControlHook) PreCreatePropertyValues(rctx request.CTX, values []* callerID := h.extractCallerID(rctx) - fieldMap, err := h.getFieldsForValues(values) + fieldMap, err := h.getFieldsForValues(rctx, values) if err != nil { return nil, err } @@ -379,7 +379,7 @@ func (h *AccessControlHook) PreUpdatePropertyValue(rctx request.CTX, groupID str callerID := h.extractCallerID(rctx) - field, err := h.propertyService.getPropertyField(groupID, value.FieldID) + field, err := h.propertyService.getPropertyField(rctx, groupID, value.FieldID) if err != nil { return nil, err } @@ -400,7 +400,7 @@ func (h *AccessControlHook) PreUpdatePropertyValues(rctx request.CTX, groupID st callerID := h.extractCallerID(rctx) - fieldMap, err := h.getFieldsForValues(values) + fieldMap, err := h.getFieldsForValues(rctx, values) if err != nil { return nil, err } @@ -426,7 +426,7 @@ func (h *AccessControlHook) PreUpsertPropertyValue(rctx request.CTX, value *mode callerID := h.extractCallerID(rctx) - field, err := h.propertyService.getPropertyField(value.GroupID, value.FieldID) + field, err := h.propertyService.getPropertyField(rctx, value.GroupID, value.FieldID) if err != nil { return nil, err } @@ -447,7 +447,7 @@ func (h *AccessControlHook) PreUpsertPropertyValues(rctx request.CTX, values []* callerID := h.extractCallerID(rctx) - fieldMap, err := h.getFieldsForValues(values) + fieldMap, err := h.getFieldsForValues(rctx, values) if err != nil { return nil, err } @@ -478,7 +478,7 @@ func (h *AccessControlHook) PreDeletePropertyValue(rctx request.CTX, groupID str return err } - field, err := h.propertyService.getPropertyField(groupID, value.FieldID) + field, err := h.propertyService.getPropertyField(rctx, groupID, value.FieldID) if err != nil { return err } @@ -545,7 +545,7 @@ func (h *AccessControlHook) PreDeletePropertyValuesForTarget(rctx request.CTX, g fieldIDSlice = append(fieldIDSlice, fieldID) } - fields, err := h.propertyService.getPropertyFields(groupID, fieldIDSlice) + fields, err := h.propertyService.getPropertyFields(rctx, groupID, fieldIDSlice) if err != nil { return err } @@ -567,7 +567,7 @@ func (h *AccessControlHook) PreDeletePropertyValuesForField(rctx request.CTX, gr callerID := h.extractCallerID(rctx) - field, err := h.propertyService.getPropertyField(groupID, fieldID) + field, err := h.propertyService.getPropertyField(rctx, groupID, fieldID) if err != nil { return err } @@ -589,7 +589,7 @@ func (h *AccessControlHook) PostGetPropertyValue(rctx request.CTX, value *model. callerID := h.extractCallerID(rctx) - filtered, err := h.applyValueReadAccessControl([]*model.PropertyValue{value}, callerID) + filtered, err := h.applyValueReadAccessControl(rctx, []*model.PropertyValue{value}, callerID) if err != nil { return nil, err } @@ -611,7 +611,7 @@ func (h *AccessControlHook) PostGetPropertyValues(rctx request.CTX, values []*mo callerID := h.extractCallerID(rctx) - return h.applyValueReadAccessControl(values, callerID) + return h.applyValueReadAccessControl(rctx, values, callerID) } // Access Control Helper Methods @@ -1379,7 +1379,7 @@ func (h *AccessControlHook) applyFieldReadAccessControlToList(fields []*model.Pr } // getFieldsForValues fetches all unique fields associated with the given values. -func (h *AccessControlHook) getFieldsForValues(values []*model.PropertyValue) (map[string]*model.PropertyField, error) { +func (h *AccessControlHook) getFieldsForValues(rctx request.CTX, values []*model.PropertyValue) (map[string]*model.PropertyField, error) { if len(values) == 0 { return make(map[string]*model.PropertyField), nil } @@ -1399,7 +1399,7 @@ func (h *AccessControlHook) getFieldsForValues(values []*model.PropertyValue) (m fieldIDSlice = append(fieldIDSlice, fieldID) } - fields, err := h.propertyService.getPropertyFields(groupID, fieldIDSlice) + fields, err := h.propertyService.getPropertyFields(rctx, groupID, fieldIDSlice) if err != nil { return nil, fmt.Errorf("failed to fetch fields for values: %w", err) } @@ -1413,12 +1413,12 @@ func (h *AccessControlHook) getFieldsForValues(values []*model.PropertyValue) (m } // applyValueReadAccessControl applies read access control to a list of values. -func (h *AccessControlHook) applyValueReadAccessControl(values []*model.PropertyValue, callerID string) ([]*model.PropertyValue, error) { +func (h *AccessControlHook) applyValueReadAccessControl(rctx request.CTX, values []*model.PropertyValue, callerID string) ([]*model.PropertyValue, error) { if len(values) == 0 { return values, nil } - fieldMap, err := h.getFieldsForValues(values) + fieldMap, err := h.getFieldsForValues(rctx, values) if err != nil { return nil, fmt.Errorf("applyValueReadAccessControl: %w", err) } diff --git a/server/channels/app/properties/access_control_attribute_validation.go b/server/channels/app/properties/access_control_attribute_validation.go index 9cf734ccdef..ea6d69afb98 100644 --- a/server/channels/app/properties/access_control_attribute_validation.go +++ b/server/channels/app/properties/access_control_attribute_validation.go @@ -475,7 +475,7 @@ func (h *AccessControlAttributeValidationHook) PreUpdatePropertyField(rctx reque // Lenient grandfather: only validate Name against CEL rules when it // actually changes, so pre-existing fields whose names predate this // validation remain editable on all other attrs. - existing, err := h.propertyService.getPropertyField(groupID, field.ID) + existing, err := h.propertyService.getPropertyField(rctx, groupID, field.ID) if err != nil { return nil, err } @@ -503,7 +503,7 @@ func (h *AccessControlAttributeValidationHook) PreUpdatePropertyFields(rctx requ for i, f := range fields { fieldIDs[i] = f.ID } - existingFields, err := h.propertyService.getPropertyFields(groupID, fieldIDs) + existingFields, err := h.propertyService.getPropertyFields(rctx, groupID, fieldIDs) if err != nil { return nil, err } @@ -654,7 +654,7 @@ func (h *AccessControlAttributeValidationHook) validateValueAgainstField(field * return nil } -func (h *AccessControlAttributeValidationHook) validateValues(values []*model.PropertyValue) error { +func (h *AccessControlAttributeValidationHook) validateValues(rctx request.CTX, values []*model.PropertyValue) error { if len(values) == 0 { return nil } @@ -674,7 +674,7 @@ func (h *AccessControlAttributeValidationHook) validateValues(values []*model.Pr fieldIDs = append(fieldIDs, id) } - fields, err := h.propertyService.getPropertyFields(groupID, fieldIDs) + fields, err := h.propertyService.getPropertyFields(rctx, groupID, fieldIDs) if err != nil { return fmt.Errorf("failed to fetch fields for validation: %w", err) } @@ -697,43 +697,43 @@ func (h *AccessControlAttributeValidationHook) validateValues(values []*model.Pr return nil } -func (h *AccessControlAttributeValidationHook) PreUpsertPropertyValue(_ request.CTX, value *model.PropertyValue) (*model.PropertyValue, error) { - if err := h.validateValues([]*model.PropertyValue{value}); err != nil { +func (h *AccessControlAttributeValidationHook) PreUpsertPropertyValue(rctx request.CTX, value *model.PropertyValue) (*model.PropertyValue, error) { + if err := h.validateValues(rctx, []*model.PropertyValue{value}); err != nil { return nil, err } return value, nil } -func (h *AccessControlAttributeValidationHook) PreUpsertPropertyValues(_ request.CTX, values []*model.PropertyValue) ([]*model.PropertyValue, error) { - if err := h.validateValues(values); err != nil { +func (h *AccessControlAttributeValidationHook) PreUpsertPropertyValues(rctx request.CTX, values []*model.PropertyValue) ([]*model.PropertyValue, error) { + if err := h.validateValues(rctx, values); err != nil { return nil, err } return values, nil } -func (h *AccessControlAttributeValidationHook) PreCreatePropertyValue(_ request.CTX, value *model.PropertyValue) (*model.PropertyValue, error) { - if err := h.validateValues([]*model.PropertyValue{value}); err != nil { +func (h *AccessControlAttributeValidationHook) PreCreatePropertyValue(rctx request.CTX, value *model.PropertyValue) (*model.PropertyValue, error) { + if err := h.validateValues(rctx, []*model.PropertyValue{value}); err != nil { return nil, err } return value, nil } -func (h *AccessControlAttributeValidationHook) PreCreatePropertyValues(_ request.CTX, values []*model.PropertyValue) ([]*model.PropertyValue, error) { - if err := h.validateValues(values); err != nil { +func (h *AccessControlAttributeValidationHook) PreCreatePropertyValues(rctx request.CTX, values []*model.PropertyValue) ([]*model.PropertyValue, error) { + if err := h.validateValues(rctx, values); err != nil { return nil, err } return values, nil } -func (h *AccessControlAttributeValidationHook) PreUpdatePropertyValue(_ request.CTX, _ string, value *model.PropertyValue) (*model.PropertyValue, error) { - if err := h.validateValues([]*model.PropertyValue{value}); err != nil { +func (h *AccessControlAttributeValidationHook) PreUpdatePropertyValue(rctx request.CTX, _ string, value *model.PropertyValue) (*model.PropertyValue, error) { + if err := h.validateValues(rctx, []*model.PropertyValue{value}); err != nil { return nil, err } return value, nil } -func (h *AccessControlAttributeValidationHook) PreUpdatePropertyValues(_ request.CTX, _ string, values []*model.PropertyValue) ([]*model.PropertyValue, error) { - if err := h.validateValues(values); err != nil { +func (h *AccessControlAttributeValidationHook) PreUpdatePropertyValues(rctx request.CTX, _ string, values []*model.PropertyValue) ([]*model.PropertyValue, error) { + if err := h.validateValues(rctx, values); err != nil { return nil, err } return values, nil diff --git a/server/channels/app/properties/property_field.go b/server/channels/app/properties/property_field.go index 62abe66d8f4..3997f839d4c 100644 --- a/server/channels/app/properties/property_field.go +++ b/server/channels/app/properties/property_field.go @@ -4,7 +4,6 @@ package properties import ( - "context" "errors" "fmt" "net/http" @@ -38,7 +37,7 @@ func (ps *PropertyService) enforceFieldGroupVersionMatch(caller string, groupID // Private implementation methods (database access) -func (ps *PropertyService) createPropertyField(field *model.PropertyField) (*model.PropertyField, error) { +func (ps *PropertyService) createPropertyField(rctx request.CTX, field *model.PropertyField) (*model.PropertyField, error) { // Enforce version match between field and group if err := ps.enforceFieldGroupVersionMatch("CreatePropertyField", field.GroupID, field); err != nil { return nil, err @@ -62,7 +61,7 @@ func (ps *PropertyService) createPropertyField(field *model.PropertyField) (*mod ) } - source, err := ps.fieldStore.Get(store.WithMaster(context.Background()), "", *field.LinkedFieldID) + source, err := ps.fieldStore.Get(store.RequestContextWithMaster(rctx), "", *field.LinkedFieldID) if err != nil { if store.IsErrNotFound(err) { return nil, model.NewAppError( @@ -172,16 +171,16 @@ func (ps *PropertyService) createPropertyField(field *model.PropertyField) (*mod return ps.fieldStore.Create(field) } -func (ps *PropertyService) getPropertyField(groupID, id string) (*model.PropertyField, error) { - return ps.fieldStore.Get(context.Background(), groupID, id) +func (ps *PropertyService) getPropertyField(rctx request.CTX, groupID, id string) (*model.PropertyField, error) { + return ps.fieldStore.Get(rctx, groupID, id) } -func (ps *PropertyService) getPropertyFieldFromMaster(groupID, id string) (*model.PropertyField, error) { - return ps.fieldStore.Get(store.WithMaster(context.Background()), groupID, id) +func (ps *PropertyService) getPropertyFieldFromMaster(rctx request.CTX, groupID, id string) (*model.PropertyField, error) { + return ps.fieldStore.Get(store.RequestContextWithMaster(rctx), groupID, id) } -func (ps *PropertyService) getPropertyFields(groupID string, ids []string) ([]*model.PropertyField, error) { - fields, err := ps.fieldStore.GetMany(context.Background(), groupID, ids) +func (ps *PropertyService) getPropertyFields(rctx request.CTX, groupID string, ids []string) ([]*model.PropertyField, error) { + fields, err := ps.fieldStore.GetMany(rctx, groupID, ids) if err != nil { var resultsMismatchErr *store.ErrResultsMismatch if errors.As(err, &resultsMismatchErr) { @@ -192,12 +191,12 @@ func (ps *PropertyService) getPropertyFields(groupID string, ids []string) ([]*m return fields, nil } -func (ps *PropertyService) getPropertyFieldByName(groupID, targetID, name string) (*model.PropertyField, error) { - return ps.fieldStore.GetFieldByName(context.Background(), groupID, targetID, name) +func (ps *PropertyService) getPropertyFieldByName(rctx request.CTX, groupID, targetID, name string) (*model.PropertyField, error) { + return ps.fieldStore.GetFieldByName(rctx, groupID, targetID, name) } -func (ps *PropertyService) getPropertyFieldByNameForObjectType(groupID, targetID, objectType, name string) (*model.PropertyField, error) { - return ps.fieldStore.GetFieldByNameForObjectType(context.Background(), groupID, targetID, objectType, name) +func (ps *PropertyService) getPropertyFieldByNameForObjectType(rctx request.CTX, groupID, targetID, objectType, name string) (*model.PropertyField, error) { + return ps.fieldStore.GetFieldByNameForObjectType(rctx, groupID, targetID, objectType, name) } func (ps *PropertyService) countActivePropertyFieldsForGroup(groupID string) (int64, error) { @@ -254,7 +253,7 @@ func (ps *PropertyService) updatePropertyFields(rctx request.CTX, groupID string // Read from master to avoid replication lag between this read and the // subsequent UPDATE (which also runs against master). This closes the // TOCTOU window that a replica read would leave open. - existingFields, err := ps.fieldStore.GetMany(store.WithMaster(context.Background()), groupID, ids) + existingFields, err := ps.fieldStore.GetMany(store.RequestContextWithMaster(rctx), groupID, ids) if err != nil { return nil, nil, nil, fmt.Errorf("failed to get existing fields for update: %w", err) } @@ -432,10 +431,10 @@ func (ps *PropertyService) updatePropertyFields(rctx request.CTX, groupID string return requested, propagated, clearedFieldIDs, nil } -func (ps *PropertyService) deletePropertyField(groupID, id string) error { +func (ps *PropertyService) deletePropertyField(rctx request.CTX, groupID, id string) error { // if groupID is not empty, we need to check first that the field belongs to the group if groupID != "" { - if _, err := ps.getPropertyField(groupID, id); err != nil { + if _, err := ps.getPropertyField(rctx, groupID, id); err != nil { return fmt.Errorf("error getting property field %q for group %q: %w", id, groupID, err) } } @@ -470,11 +469,11 @@ func (ps *PropertyService) CreatePropertyField(rctx request.CTX, field *model.Pr return nil, fmt.Errorf("CreatePropertyField: %w", err) } - return ps.createPropertyField(field) + return ps.createPropertyField(rctx, field) } func (ps *PropertyService) GetPropertyField(rctx request.CTX, groupID, id string) (*model.PropertyField, error) { - field, err := ps.getPropertyField(groupID, id) + field, err := ps.getPropertyField(rctx, groupID, id) if err != nil { return nil, fmt.Errorf("GetPropertyField: %w", err) } @@ -483,7 +482,7 @@ func (ps *PropertyService) GetPropertyField(rctx request.CTX, groupID, id string } func (ps *PropertyService) GetPropertyFields(rctx request.CTX, groupID string, ids []string) ([]*model.PropertyField, error) { - fields, err := ps.getPropertyFields(groupID, ids) + fields, err := ps.getPropertyFields(rctx, groupID, ids) if err != nil { return nil, fmt.Errorf("GetPropertyFields: %w", err) } @@ -492,7 +491,7 @@ func (ps *PropertyService) GetPropertyFields(rctx request.CTX, groupID string, i } func (ps *PropertyService) GetPropertyFieldsForGroup(rctx request.CTX, groupID string) ([]*model.PropertyField, error) { - fields, err := ps.fieldStore.GetForGroup(context.Background(), groupID) + fields, err := ps.fieldStore.GetForGroup(rctx, groupID) if err != nil { return nil, fmt.Errorf("GetPropertyFieldsForGroup: %w", err) } @@ -505,7 +504,7 @@ func (ps *PropertyService) GetPropertyFieldsForGroup(rctx request.CTX, groupID s // Deprecated: name is not unique within a group when fields of different object // types share a name. Use GetPropertyFieldByNameForObjectType to disambiguate. func (ps *PropertyService) GetPropertyFieldByName(rctx request.CTX, groupID, targetID, name string) (*model.PropertyField, error) { - field, err := ps.getPropertyFieldByName(groupID, targetID, name) + field, err := ps.getPropertyFieldByName(rctx, groupID, targetID, name) if err != nil { return nil, fmt.Errorf("GetPropertyFieldByName: %w", err) } @@ -514,7 +513,7 @@ func (ps *PropertyService) GetPropertyFieldByName(rctx request.CTX, groupID, tar } func (ps *PropertyService) GetPropertyFieldByNameForObjectType(rctx request.CTX, groupID, targetID, objectType, name string) (*model.PropertyField, error) { - field, err := ps.getPropertyFieldByNameForObjectType(groupID, targetID, objectType, name) + field, err := ps.getPropertyFieldByNameForObjectType(rctx, groupID, targetID, objectType, name) if err != nil { return nil, fmt.Errorf("GetPropertyFieldByNameForObjectType: %w", err) } @@ -592,7 +591,7 @@ func (ps *PropertyService) DeletePropertyField(rctx request.CTX, groupID, id str return fmt.Errorf("DeletePropertyField: %w", err) } - return ps.deletePropertyField(groupID, id) + return ps.deletePropertyField(rctx, groupID, id) } // asOptionSlice extracts the options from an attrs map as []map[string]any diff --git a/server/channels/app/properties/property_value.go b/server/channels/app/properties/property_value.go index 74e9036f040..51f2cb2a010 100644 --- a/server/channels/app/properties/property_value.go +++ b/server/channels/app/properties/property_value.go @@ -4,7 +4,6 @@ package properties import ( - "context" "fmt" "net/http" @@ -18,7 +17,7 @@ import ( // field. Template fields are definition-only and must never hold values. // This is enforced at the service layer to cover all entry points (API, // CPA endpoints, plugin API). -func (ps *PropertyService) rejectTemplateValues(values []*model.PropertyValue) error { +func (ps *PropertyService) rejectTemplateValues(rctx request.CTX, values []*model.PropertyValue) error { // Collect unique field IDs seen := make(map[string]struct{}, len(values)) for _, v := range values { @@ -37,7 +36,7 @@ func (ps *PropertyService) rejectTemplateValues(values []*model.PropertyValue) e } // Batch lookup from master to avoid replication lag - fields, err := ps.fieldStore.GetMany(store.WithMaster(context.Background()), "", fieldIDs) + fields, err := ps.fieldStore.GetMany(store.RequestContextWithMaster(rctx), "", fieldIDs) if err != nil { return fmt.Errorf("failed to look up fields for template check: %w", err) } @@ -58,15 +57,15 @@ func (ps *PropertyService) rejectTemplateValues(values []*model.PropertyValue) e // Private implementation methods (database access) -func (ps *PropertyService) createPropertyValue(value *model.PropertyValue) (*model.PropertyValue, error) { - if err := ps.rejectTemplateValues([]*model.PropertyValue{value}); err != nil { +func (ps *PropertyService) createPropertyValue(rctx request.CTX, value *model.PropertyValue) (*model.PropertyValue, error) { + if err := ps.rejectTemplateValues(rctx, []*model.PropertyValue{value}); err != nil { return nil, err } return ps.valueStore.Create(value) } -func (ps *PropertyService) createPropertyValues(values []*model.PropertyValue) ([]*model.PropertyValue, error) { - if err := ps.rejectTemplateValues(values); err != nil { +func (ps *PropertyService) createPropertyValues(rctx request.CTX, values []*model.PropertyValue) ([]*model.PropertyValue, error) { + if err := ps.rejectTemplateValues(rctx, values); err != nil { return nil, err } return ps.valueStore.CreateMany(values) @@ -87,8 +86,8 @@ func (ps *PropertyService) searchPropertyValues(groupID string, opts model.Prope return ps.valueStore.SearchPropertyValues(opts) } -func (ps *PropertyService) updatePropertyValue(groupID string, value *model.PropertyValue) (*model.PropertyValue, error) { - values, err := ps.updatePropertyValues(groupID, []*model.PropertyValue{value}) +func (ps *PropertyService) updatePropertyValue(rctx request.CTX, groupID string, value *model.PropertyValue) (*model.PropertyValue, error) { + values, err := ps.updatePropertyValues(rctx, groupID, []*model.PropertyValue{value}) if err != nil { return nil, err } @@ -96,15 +95,15 @@ func (ps *PropertyService) updatePropertyValue(groupID string, value *model.Prop return values[0], nil } -func (ps *PropertyService) updatePropertyValues(groupID string, values []*model.PropertyValue) ([]*model.PropertyValue, error) { - if err := ps.rejectTemplateValues(values); err != nil { +func (ps *PropertyService) updatePropertyValues(rctx request.CTX, groupID string, values []*model.PropertyValue) ([]*model.PropertyValue, error) { + if err := ps.rejectTemplateValues(rctx, values); err != nil { return nil, err } return ps.valueStore.Update(groupID, values) } -func (ps *PropertyService) upsertPropertyValue(value *model.PropertyValue) (*model.PropertyValue, error) { - values, err := ps.upsertPropertyValues([]*model.PropertyValue{value}) +func (ps *PropertyService) upsertPropertyValue(rctx request.CTX, value *model.PropertyValue) (*model.PropertyValue, error) { + values, err := ps.upsertPropertyValues(rctx, []*model.PropertyValue{value}) if err != nil { return nil, err } @@ -112,8 +111,8 @@ func (ps *PropertyService) upsertPropertyValue(value *model.PropertyValue) (*mod return values[0], nil } -func (ps *PropertyService) upsertPropertyValues(values []*model.PropertyValue) ([]*model.PropertyValue, error) { - if err := ps.rejectTemplateValues(values); err != nil { +func (ps *PropertyService) upsertPropertyValues(rctx request.CTX, values []*model.PropertyValue) ([]*model.PropertyValue, error) { + if err := ps.rejectTemplateValues(rctx, values); err != nil { return nil, err } return ps.valueStore.Upsert(values) @@ -143,7 +142,7 @@ func (ps *PropertyService) CreatePropertyValue(rctx request.CTX, value *model.Pr return nil, fmt.Errorf("CreatePropertyValue: %w", err) } - created, err := ps.createPropertyValue(processed) + created, err := ps.createPropertyValue(rctx, processed) if err != nil { return nil, err } @@ -170,7 +169,7 @@ func (ps *PropertyService) CreatePropertyValues(rctx request.CTX, values []*mode return nil, fmt.Errorf("CreatePropertyValues: %w", err) } - created, err := ps.createPropertyValues(processed) + created, err := ps.createPropertyValues(rctx, processed) if err != nil { return nil, err } @@ -211,7 +210,7 @@ func (ps *PropertyService) UpdatePropertyValue(rctx request.CTX, groupID string, return nil, fmt.Errorf("UpdatePropertyValue: %w", err) } - updated, err := ps.updatePropertyValue(groupID, processed) + updated, err := ps.updatePropertyValue(rctx, groupID, processed) if err != nil { return nil, err } @@ -242,7 +241,7 @@ func (ps *PropertyService) UpdatePropertyValues(rctx request.CTX, groupID string return nil, fmt.Errorf("UpdatePropertyValues: %w", err) } - updated, err := ps.updatePropertyValues(groupID, processed) + updated, err := ps.updatePropertyValues(rctx, groupID, processed) if err != nil { return nil, err } @@ -260,7 +259,7 @@ func (ps *PropertyService) UpsertPropertyValue(rctx request.CTX, value *model.Pr return nil, fmt.Errorf("UpsertPropertyValue: %w", err) } - upserted, err := ps.upsertPropertyValue(processed) + upserted, err := ps.upsertPropertyValue(rctx, processed) if err != nil { return nil, err } @@ -287,7 +286,7 @@ func (ps *PropertyService) UpsertPropertyValues(rctx request.CTX, values []*mode return nil, fmt.Errorf("UpsertPropertyValues: %w", err) } - upserted, err := ps.upsertPropertyValues(processed) + upserted, err := ps.upsertPropertyValues(rctx, processed) if err != nil { return nil, err } diff --git a/server/channels/app/properties/session_attributes.go b/server/channels/app/properties/session_attributes.go index 782b3a1530b..d943bec53f4 100644 --- a/server/channels/app/properties/session_attributes.go +++ b/server/channels/app/properties/session_attributes.go @@ -4,6 +4,7 @@ package properties import ( + "context" "net/http" "reflect" @@ -32,8 +33,18 @@ func (h *SessionAttributesHook) manages(groupID string) bool { return groupID == h.groupID } +type systemCallerKey struct{} + +func SystemCallerContext(rctx request.CTX) request.CTX { + return rctx.WithContext(context.WithValue(rctx.Context(), systemCallerKey{}, true)) +} + func isSystemCaller(rctx request.CTX) bool { - return rctx == nil + if rctx == nil { + return false + } + isSystemCaller, _ := rctx.Context().Value(systemCallerKey{}).(bool) + return isSystemCaller } func (h *SessionAttributesHook) PreCreatePropertyField(rctx request.CTX, field *model.PropertyField) (*model.PropertyField, error) { @@ -54,7 +65,7 @@ func (h *SessionAttributesHook) PreUpdatePropertyField(rctx request.CTX, groupID if !h.manages(groupID) || isSystemCaller(rctx) { return field, nil } - if err := h.validateUpdate(field); err != nil { + if err := h.validateUpdate(rctx, field); err != nil { return nil, err } return field, nil @@ -65,15 +76,15 @@ func (h *SessionAttributesHook) PreUpdatePropertyFields(rctx request.CTX, groupI return fields, nil } for _, field := range fields { - if err := h.validateUpdate(field); err != nil { + if err := h.validateUpdate(rctx, field); err != nil { return nil, err } } return fields, nil } -func (h *SessionAttributesHook) validateUpdate(incoming *model.PropertyField) error { - existing, err := h.propertyService.getPropertyFieldFromMaster(h.groupID, incoming.ID) +func (h *SessionAttributesHook) validateUpdate(rctx request.CTX, incoming *model.PropertyField) error { + existing, err := h.propertyService.getPropertyFieldFromMaster(rctx, h.groupID, incoming.ID) if err != nil { return err } diff --git a/server/channels/app/properties/session_attributes_test.go b/server/channels/app/properties/session_attributes_test.go index ccdaa806f1e..30d43ba0c68 100644 --- a/server/channels/app/properties/session_attributes_test.go +++ b/server/channels/app/properties/session_attributes_test.go @@ -15,9 +15,10 @@ func TestSessionAttributesHook(t *testing.T) { th := Setup(t) group := th.RegisterPropertyGroup(t, model.PropertyGroupVersionV2) th.service.AddHook(NewSessionAttributesHook(th.service, group.ID)) + systemContext := SystemCallerContext(th.Context) createField := func() *model.PropertyField { - f, err := th.service.CreatePropertyField(nil, &model.PropertyField{ + f, err := th.service.CreatePropertyField(systemContext, &model.PropertyField{ GroupID: group.ID, Name: model.NewId(), Type: model.PropertyFieldTypeText, @@ -84,7 +85,7 @@ func TestSessionAttributesHook(t *testing.T) { t.Run("allows delete from the system caller", func(t *testing.T) { f := createField() - err := th.service.DeletePropertyField(nil, group.ID, f.ID) + err := th.service.DeletePropertyField(systemContext, group.ID, f.ID) require.NoError(t, err) }) } diff --git a/server/channels/app/session_attributes.go b/server/channels/app/session_attributes.go index 6a8ef3c0736..d557734b0ff 100644 --- a/server/channels/app/session_attributes.go +++ b/server/channels/app/session_attributes.go @@ -4,7 +4,6 @@ package app import ( - "context" "encoding/base64" "encoding/json" "errors" @@ -28,13 +27,13 @@ func (a *App) sessionAttributesEnabled() bool { return model.MinimumEnterpriseAdvancedLicense(a.License()) } -func (a *App) getSessionAttributeFieldsByName() (map[string]*model.PropertyField, *model.AppError) { +func (a *App) getSessionAttributeFieldsByName(rctx request.CTX) (map[string]*model.PropertyField, *model.AppError) { group, err := a.Srv().propertyService.Group(model.SessionAttributesPropertyGroupName) if err != nil { return nil, model.NewAppError("getSessionAttributeFieldsByName", "app.property_group.get.app_error", nil, "", http.StatusInternalServerError).Wrap(err) } - fields, err := a.Srv().Store().PropertyField().GetForGroup(context.Background(), group.ID) + fields, err := a.Srv().Store().PropertyField().GetForGroup(rctx, group.ID) if err != nil { return nil, model.NewAppError("getSessionAttributeFieldsByName", "app.property_field.get_for_group.app_error", nil, "", http.StatusInternalServerError).Wrap(err) } @@ -97,7 +96,7 @@ func (a *App) ProcessSessionAttributesRequest(rctx request.CTX, r *http.Request) return } - fieldsByName, appErr := a.getSessionAttributeFieldsByName() + fieldsByName, appErr := a.getSessionAttributeFieldsByName(rctx) if appErr != nil { rctx.Logger().Warn("Failed to load session attribute schema", mlog.Err(appErr)) return @@ -240,7 +239,7 @@ func (a *App) GetSessionAttributesManifest(rctx request.CTX, r *http.Request) ([ return nil, model.NewAppError("GetSessionAttributesManifest", "api.user.session_attributes.disabled.app_error", nil, "", http.StatusNotImplemented) } - fieldsByName, appErr := a.getSessionAttributeFieldsByName() + fieldsByName, appErr := a.getSessionAttributeFieldsByName(rctx) if appErr != nil { return nil, appErr } @@ -268,7 +267,7 @@ func (a *App) GetSessionAttributesManifest(rctx request.CTX, r *http.Request) ([ return manifest, nil } -func (a *App) GetSessionAttributes(sessionID string) (map[string]any, *model.AppError) { +func (a *App) GetSessionAttributes(rctx request.CTX, sessionID string) (map[string]any, *model.AppError) { if !a.sessionAttributesEnabled() { return nil, nil } @@ -281,7 +280,7 @@ func (a *App) GetSessionAttributes(sessionID string) (map[string]any, *model.App return nil, model.NewAppError("GetSessionAttributes", "app.access_control.get_session_attributes.app_error", nil, "", http.StatusInternalServerError).Wrap(err) } - fieldsByName, appErr := a.getSessionAttributeFieldsByName() + fieldsByName, appErr := a.getSessionAttributeFieldsByName(rctx) if appErr != nil { return nil, appErr } diff --git a/server/channels/store/context.go b/server/channels/store/context.go index 1961d9e4838..c7b01520645 100644 --- a/server/channels/store/context.go +++ b/server/channels/store/context.go @@ -20,17 +20,9 @@ const ( useMaster contextValue = "useMaster" ) -// WithMaster adds the context value that master DB should be selected for this request. -// -// Deprecated: This method is deprecated and there's ongoing change to use `request.CTX` across -// instead of `context.Context`. Please use `RequestContextWithMaster` instead. -func WithMaster(ctx context.Context) context.Context { - return context.WithValue(ctx, storeContextKey(useMaster), true) -} - // RequestContextWithMaster adds the context value that master DB should be selected for this request. func RequestContextWithMaster(rctx request.CTX) request.CTX { - ctx := WithMaster(rctx.Context()) + ctx := context.WithValue(rctx.Context(), storeContextKey(useMaster), true) rctx = rctx.WithContext(ctx) return rctx } diff --git a/server/channels/store/context_test.go b/server/channels/store/context_test.go index 44c4e17257c..a431a2fa45a 100644 --- a/server/channels/store/context_test.go +++ b/server/channels/store/context_test.go @@ -4,20 +4,12 @@ package store import ( - "context" "testing" "github.com/mattermost/mattermost/server/public/shared/request" "github.com/stretchr/testify/assert" ) -func TestContextMaster(t *testing.T) { - ctx := context.Background() - - m := WithMaster(ctx) - assert.True(t, HasMaster(m)) -} - func TestRequestContextWithMaster(t *testing.T) { t.Run("set and get", func(t *testing.T) { var rctx request.CTX = request.TestContext(t) diff --git a/server/channels/store/layer_generators/retry_layer.go.tmpl b/server/channels/store/layer_generators/retry_layer.go.tmpl index acdfe11df7d..869c1b0d1a9 100644 --- a/server/channels/store/layer_generators/retry_layer.go.tmpl +++ b/server/channels/store/layer_generators/retry_layer.go.tmpl @@ -7,7 +7,6 @@ package retrylayer import ( - "context" timepkg "time" "github.com/lib/pq" diff --git a/server/channels/store/layer_generators/timer_layer.go.tmpl b/server/channels/store/layer_generators/timer_layer.go.tmpl index f51c50e0931..c68afe4c18b 100644 --- a/server/channels/store/layer_generators/timer_layer.go.tmpl +++ b/server/channels/store/layer_generators/timer_layer.go.tmpl @@ -7,7 +7,6 @@ package timerlayer import ( - "context" "time" "github.com/mattermost/mattermost/server/public/model" diff --git a/server/channels/store/localcachelayer/main_test.go b/server/channels/store/localcachelayer/main_test.go index 451d6c25870..b434cf9fb4b 100644 --- a/server/channels/store/localcachelayer/main_test.go +++ b/server/channels/store/localcachelayer/main_test.go @@ -4,7 +4,6 @@ package localcachelayer import ( - "context" "fmt" "testing" @@ -210,7 +209,7 @@ func getMockStore(t *testing.T) *mocks.Store { fakeField := model.PropertyField{ID: "field-id", GroupID: "group-id", Name: "field-name"} mockPropertyFieldStore := mocks.PropertyFieldStore{} - mockPropertyFieldStore.On("GetForGroup", context.Background(), "group-id").Return([]*model.PropertyField{&fakeField}, nil) + mockPropertyFieldStore.On("GetForGroup", mock.Anything, "group-id").Return([]*model.PropertyField{&fakeField}, nil) mockPropertyFieldStore.On("Create", &fakeField).Return(&fakeField, nil) mockPropertyFieldStore.On("Update", "group-id", []*model.PropertyField{&fakeField}, map[string]int64(nil)).Return([]*model.PropertyField{&fakeField}, nil) mockPropertyFieldStore.On("Delete", "group-id", "field-id").Return(nil) diff --git a/server/channels/store/localcachelayer/property_field_layer.go b/server/channels/store/localcachelayer/property_field_layer.go index 3305eb67e4d..29336790cd8 100644 --- a/server/channels/store/localcachelayer/property_field_layer.go +++ b/server/channels/store/localcachelayer/property_field_layer.go @@ -5,10 +5,10 @@ package localcachelayer import ( "bytes" - "context" "github.com/mattermost/mattermost/server/public/model" "github.com/mattermost/mattermost/server/public/shared/mlog" + "github.com/mattermost/mattermost/server/public/shared/request" "github.com/mattermost/mattermost/server/v8/channels/store" ) @@ -81,12 +81,12 @@ func (s *LocalCachePropertyFieldStore) getFieldsForGroupFromCache(groupID string return nil, false } -func (s LocalCachePropertyFieldStore) GetForGroup(ctx context.Context, groupID string) ([]*model.PropertyField, error) { +func (s LocalCachePropertyFieldStore) GetForGroup(rctx request.CTX, groupID string) ([]*model.PropertyField, error) { if fields, ok := s.getFieldsForGroupFromCache(groupID); ok { return fields, nil } - fields, err := s.PropertyFieldStore.GetForGroup(ctx, groupID) + fields, err := s.PropertyFieldStore.GetForGroup(rctx, groupID) if err != nil { return nil, err } diff --git a/server/channels/store/localcachelayer/property_field_layer_test.go b/server/channels/store/localcachelayer/property_field_layer_test.go index e17dbf12254..7f8c9ce327f 100644 --- a/server/channels/store/localcachelayer/property_field_layer_test.go +++ b/server/channels/store/localcachelayer/property_field_layer_test.go @@ -4,7 +4,6 @@ package localcachelayer import ( - "context" "testing" "github.com/stretchr/testify/assert" @@ -12,6 +11,7 @@ import ( "github.com/mattermost/mattermost/server/public/model" "github.com/mattermost/mattermost/server/public/shared/mlog" + "github.com/mattermost/mattermost/server/public/shared/request" "github.com/mattermost/mattermost/server/v8/channels/store/storetest/mocks" ) @@ -20,6 +20,7 @@ func TestPropertyFieldStoreCache(t *testing.T) { fakeField := model.PropertyField{ID: "field-id", GroupID: groupID, Name: "field-name"} fakeFields := []*model.PropertyField{&fakeField} logger := mlog.CreateConsoleTestLogger(t) + rctx := request.TestContext(t) t.Run("GetForGroup cached on second call", func(t *testing.T) { mockStore := getMockStore(t) @@ -27,12 +28,12 @@ func TestPropertyFieldStoreCache(t *testing.T) { cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider, logger) require.NoError(t, err) - fields, err := cachedStore.PropertyField().GetForGroup(context.Background(), groupID) + fields, err := cachedStore.PropertyField().GetForGroup(rctx, groupID) require.NoError(t, err) assert.Equal(t, fakeFields, fields) mockStore.PropertyField().(*mocks.PropertyFieldStore).AssertNumberOfCalls(t, "GetForGroup", 1) - fields, err = cachedStore.PropertyField().GetForGroup(context.Background(), groupID) + fields, err = cachedStore.PropertyField().GetForGroup(rctx, groupID) require.NoError(t, err) assert.Equal(t, fakeFields, fields) mockStore.PropertyField().(*mocks.PropertyFieldStore).AssertNumberOfCalls(t, "GetForGroup", 1) @@ -44,14 +45,14 @@ func TestPropertyFieldStoreCache(t *testing.T) { cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider, logger) require.NoError(t, err) - _, err = cachedStore.PropertyField().GetForGroup(context.Background(), groupID) + _, err = cachedStore.PropertyField().GetForGroup(rctx, groupID) require.NoError(t, err) mockStore.PropertyField().(*mocks.PropertyFieldStore).AssertNumberOfCalls(t, "GetForGroup", 1) _, err = cachedStore.PropertyField().Create(&fakeField) require.NoError(t, err) - _, err = cachedStore.PropertyField().GetForGroup(context.Background(), groupID) + _, err = cachedStore.PropertyField().GetForGroup(rctx, groupID) require.NoError(t, err) mockStore.PropertyField().(*mocks.PropertyFieldStore).AssertNumberOfCalls(t, "GetForGroup", 2) }) @@ -62,14 +63,14 @@ func TestPropertyFieldStoreCache(t *testing.T) { cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider, logger) require.NoError(t, err) - _, err = cachedStore.PropertyField().GetForGroup(context.Background(), groupID) + _, err = cachedStore.PropertyField().GetForGroup(rctx, groupID) require.NoError(t, err) mockStore.PropertyField().(*mocks.PropertyFieldStore).AssertNumberOfCalls(t, "GetForGroup", 1) _, err = cachedStore.PropertyField().Update(groupID, fakeFields, nil) require.NoError(t, err) - _, err = cachedStore.PropertyField().GetForGroup(context.Background(), groupID) + _, err = cachedStore.PropertyField().GetForGroup(rctx, groupID) require.NoError(t, err) mockStore.PropertyField().(*mocks.PropertyFieldStore).AssertNumberOfCalls(t, "GetForGroup", 2) }) @@ -80,14 +81,14 @@ func TestPropertyFieldStoreCache(t *testing.T) { cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider, logger) require.NoError(t, err) - _, err = cachedStore.PropertyField().GetForGroup(context.Background(), groupID) + _, err = cachedStore.PropertyField().GetForGroup(rctx, groupID) require.NoError(t, err) mockStore.PropertyField().(*mocks.PropertyFieldStore).AssertNumberOfCalls(t, "GetForGroup", 1) err = cachedStore.PropertyField().Delete(groupID, fakeField.ID) require.NoError(t, err) - _, err = cachedStore.PropertyField().GetForGroup(context.Background(), groupID) + _, err = cachedStore.PropertyField().GetForGroup(rctx, groupID) require.NoError(t, err) mockStore.PropertyField().(*mocks.PropertyFieldStore).AssertNumberOfCalls(t, "GetForGroup", 2) }) diff --git a/server/channels/store/retrylayer/retrylayer.go b/server/channels/store/retrylayer/retrylayer.go index 2681b397566..2c8e38659c6 100644 --- a/server/channels/store/retrylayer/retrylayer.go +++ b/server/channels/store/retrylayer/retrylayer.go @@ -7,7 +7,6 @@ package retrylayer import ( - "context" timepkg "time" "github.com/lib/pq" @@ -10603,11 +10602,11 @@ func (s *RetryLayerPropertyFieldStore) Delete(groupID string, id string) error { } -func (s *RetryLayerPropertyFieldStore) Get(ctx context.Context, groupID string, id string) (*model.PropertyField, error) { +func (s *RetryLayerPropertyFieldStore) Get(rctx request.CTX, groupID string, id string) (*model.PropertyField, error) { tries := 0 for { - result, err := s.PropertyFieldStore.Get(ctx, groupID, id) + result, err := s.PropertyFieldStore.Get(rctx, groupID, id) if err == nil { return result, nil } @@ -10624,11 +10623,11 @@ func (s *RetryLayerPropertyFieldStore) Get(ctx context.Context, groupID string, } -func (s *RetryLayerPropertyFieldStore) GetFieldByName(ctx context.Context, groupID string, targetID string, name string) (*model.PropertyField, error) { +func (s *RetryLayerPropertyFieldStore) GetFieldByName(rctx request.CTX, groupID string, targetID string, name string) (*model.PropertyField, error) { tries := 0 for { - result, err := s.PropertyFieldStore.GetFieldByName(ctx, groupID, targetID, name) + result, err := s.PropertyFieldStore.GetFieldByName(rctx, groupID, targetID, name) if err == nil { return result, nil } @@ -10645,11 +10644,11 @@ func (s *RetryLayerPropertyFieldStore) GetFieldByName(ctx context.Context, group } -func (s *RetryLayerPropertyFieldStore) GetFieldByNameForObjectType(ctx context.Context, groupID string, targetID string, objectType string, name string) (*model.PropertyField, error) { +func (s *RetryLayerPropertyFieldStore) GetFieldByNameForObjectType(rctx request.CTX, groupID string, targetID string, objectType string, name string) (*model.PropertyField, error) { tries := 0 for { - result, err := s.PropertyFieldStore.GetFieldByNameForObjectType(ctx, groupID, targetID, objectType, name) + result, err := s.PropertyFieldStore.GetFieldByNameForObjectType(rctx, groupID, targetID, objectType, name) if err == nil { return result, nil } @@ -10666,11 +10665,11 @@ func (s *RetryLayerPropertyFieldStore) GetFieldByNameForObjectType(ctx context.C } -func (s *RetryLayerPropertyFieldStore) GetForGroup(ctx context.Context, groupID string) ([]*model.PropertyField, error) { +func (s *RetryLayerPropertyFieldStore) GetForGroup(rctx request.CTX, groupID string) ([]*model.PropertyField, error) { tries := 0 for { - result, err := s.PropertyFieldStore.GetForGroup(ctx, groupID) + result, err := s.PropertyFieldStore.GetForGroup(rctx, groupID) if err == nil { return result, nil } @@ -10687,11 +10686,11 @@ func (s *RetryLayerPropertyFieldStore) GetForGroup(ctx context.Context, groupID } -func (s *RetryLayerPropertyFieldStore) GetMany(ctx context.Context, groupID string, ids []string) ([]*model.PropertyField, error) { +func (s *RetryLayerPropertyFieldStore) GetMany(rctx request.CTX, groupID string, ids []string) ([]*model.PropertyField, error) { tries := 0 for { - result, err := s.PropertyFieldStore.GetMany(ctx, groupID, ids) + result, err := s.PropertyFieldStore.GetMany(rctx, groupID, ids) if err == nil { return result, nil } diff --git a/server/channels/store/sqlstore/context.go b/server/channels/store/sqlstore/context.go index e7885e2aab5..b51367a6283 100644 --- a/server/channels/store/sqlstore/context.go +++ b/server/channels/store/sqlstore/context.go @@ -10,14 +10,6 @@ import ( "github.com/mattermost/mattermost/server/v8/channels/store" ) -// WithMaster adds the context value that master DB should be selected for this request. -// -// Deprecated: This method is deprecated and there's ongoing change to use `request.CTX` across -// instead of `context.Context`. Please use `RequestContextWithMaster` instead. -func WithMaster(ctx context.Context) context.Context { - return store.WithMaster(ctx) -} - // RequestContextWithMaster adds the context value that master DB should be selected for this request. func RequestContextWithMaster(rctx request.CTX) request.CTX { return store.RequestContextWithMaster(rctx) diff --git a/server/channels/store/sqlstore/context_test.go b/server/channels/store/sqlstore/context_test.go index 645b19ad655..8f64baa71d1 100644 --- a/server/channels/store/sqlstore/context_test.go +++ b/server/channels/store/sqlstore/context_test.go @@ -4,24 +4,12 @@ package sqlstore import ( - "context" "testing" "github.com/mattermost/mattermost/server/public/shared/request" "github.com/stretchr/testify/assert" ) -func TestContextMaster(t *testing.T) { - if enableFullyParallelTests { - t.Parallel() - } - - ctx := context.Background() - - m := WithMaster(ctx) - assert.True(t, HasMaster(m)) -} - func TestRequestContextWithMaster(t *testing.T) { if enableFullyParallelTests { t.Parallel() diff --git a/server/channels/store/sqlstore/property_field_store.go b/server/channels/store/sqlstore/property_field_store.go index 8ae2c9e9a05..969fa1b6c6c 100644 --- a/server/channels/store/sqlstore/property_field_store.go +++ b/server/channels/store/sqlstore/property_field_store.go @@ -4,7 +4,6 @@ package sqlstore import ( - "context" "database/sql" "fmt" "strings" @@ -13,6 +12,7 @@ import ( "github.com/pkg/errors" "github.com/mattermost/mattermost/server/public/model" + "github.com/mattermost/mattermost/server/public/shared/request" "github.com/mattermost/mattermost/server/v8/channels/store" ) @@ -58,7 +58,7 @@ func (s *SqlPropertyFieldStore) Create(field *model.PropertyField) (*model.Prope return field, nil } -func (s *SqlPropertyFieldStore) Get(ctx context.Context, groupID, id string) (*model.PropertyField, error) { +func (s *SqlPropertyFieldStore) Get(rctx request.CTX, groupID, id string) (*model.PropertyField, error) { builder := s.tableSelectQuery.Where(sq.Eq{"id": id}) if groupID != "" { @@ -66,7 +66,7 @@ func (s *SqlPropertyFieldStore) Get(ctx context.Context, groupID, id string) (*m } var field model.PropertyField - if err := s.DBXFromContext(ctx).GetBuilder(&field, builder); err != nil { + if err := s.DBXFromContext(rctx.Context()).GetBuilder(&field, builder); err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, store.NewErrNotFound("PropertyField", id) } @@ -84,17 +84,17 @@ func (s *SqlPropertyFieldStore) Get(ctx context.Context, groupID, id string) (*m // returns an arbitrary match (the query has no ORDER BY/LIMIT). Use // GetFieldByNameForObjectType for a deterministic result. Retained because it // is exposed on the (stable) plugin API. -func (s *SqlPropertyFieldStore) GetFieldByName(ctx context.Context, groupID, targetID, name string) (*model.PropertyField, error) { - return s.getFieldByName(ctx, s.fieldByNameQuery(groupID, targetID, name), name) +func (s *SqlPropertyFieldStore) GetFieldByName(rctx request.CTX, groupID, targetID, name string) (*model.PropertyField, error) { + return s.getFieldByName(rctx, s.fieldByNameQuery(groupID, targetID, name), name) } // GetFieldByNameForObjectType retrieves a single property field by group, // target, object type, and name. objectType is matched exactly — including the // empty string, which is itself a valid object type, not a match-any wildcard — // so together with the typed unique index the result is deterministic. -func (s *SqlPropertyFieldStore) GetFieldByNameForObjectType(ctx context.Context, groupID, targetID, objectType, name string) (*model.PropertyField, error) { +func (s *SqlPropertyFieldStore) GetFieldByNameForObjectType(rctx request.CTX, groupID, targetID, objectType, name string) (*model.PropertyField, error) { builder := s.fieldByNameQuery(groupID, targetID, name).Where(sq.Eq{"ObjectType": objectType}) - return s.getFieldByName(ctx, builder, name) + return s.getFieldByName(rctx, builder, name) } func (s *SqlPropertyFieldStore) fieldByNameQuery(groupID, targetID, name string) sq.SelectBuilder { @@ -105,9 +105,9 @@ func (s *SqlPropertyFieldStore) fieldByNameQuery(groupID, targetID, name string) Where(sq.Eq{"DeleteAt": 0}) } -func (s *SqlPropertyFieldStore) getFieldByName(ctx context.Context, builder sq.SelectBuilder, name string) (*model.PropertyField, error) { +func (s *SqlPropertyFieldStore) getFieldByName(rctx request.CTX, builder sq.SelectBuilder, name string) (*model.PropertyField, error) { var field model.PropertyField - if err := s.DBXFromContext(ctx).GetBuilder(&field, builder); err != nil { + if err := s.DBXFromContext(rctx.Context()).GetBuilder(&field, builder); err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, store.NewErrNotFound("PropertyField", name) } @@ -117,7 +117,7 @@ func (s *SqlPropertyFieldStore) getFieldByName(ctx context.Context, builder sq.S return &field, nil } -func (s *SqlPropertyFieldStore) GetMany(ctx context.Context, groupID string, ids []string) ([]*model.PropertyField, error) { +func (s *SqlPropertyFieldStore) GetMany(rctx request.CTX, groupID string, ids []string) ([]*model.PropertyField, error) { builder := s.tableSelectQuery.Where(sq.Eq{"id": ids}) if groupID != "" { @@ -125,7 +125,7 @@ func (s *SqlPropertyFieldStore) GetMany(ctx context.Context, groupID string, ids } fields := []*model.PropertyField{} - if err := s.DBXFromContext(ctx).SelectBuilder(&fields, builder); err != nil { + if err := s.DBXFromContext(rctx.Context()).SelectBuilder(&fields, builder); err != nil { return nil, errors.Wrap(err, "property_field_get_many_query") } @@ -190,13 +190,13 @@ func (s *SqlPropertyFieldStore) CountForTarget(groupID, targetType, targetID str return count, nil } -func (s *SqlPropertyFieldStore) GetForGroup(ctx context.Context, groupID string) ([]*model.PropertyField, error) { +func (s *SqlPropertyFieldStore) GetForGroup(rctx request.CTX, groupID string) ([]*model.PropertyField, error) { builder := s.tableSelectQuery. Where(sq.Eq{"GroupID": groupID}). Where(sq.Eq{"DeleteAt": 0}) fields := []*model.PropertyField{} - if err := s.DBXFromContext(ctx).SelectBuilder(&fields, builder); err != nil { + if err := s.DBXFromContext(rctx.Context()).SelectBuilder(&fields, builder); err != nil { return nil, errors.Wrap(err, "property_field_get_for_group_query") } diff --git a/server/channels/store/store.go b/server/channels/store/store.go index 9dae3375727..cf386ecd106 100644 --- a/server/channels/store/store.go +++ b/server/channels/store/store.go @@ -6,7 +6,6 @@ package store import ( - "context" "database/sql" "time" @@ -1190,11 +1189,11 @@ type PropertyGroupStore interface { type PropertyFieldStore interface { Create(field *model.PropertyField) (*model.PropertyField, error) - Get(ctx context.Context, groupID, id string) (*model.PropertyField, error) - GetMany(ctx context.Context, groupID string, ids []string) ([]*model.PropertyField, error) - GetFieldByName(ctx context.Context, groupID, targetID, name string) (*model.PropertyField, error) - GetFieldByNameForObjectType(ctx context.Context, groupID, targetID, objectType, name string) (*model.PropertyField, error) - GetForGroup(ctx context.Context, groupID string) ([]*model.PropertyField, error) + Get(rctx request.CTX, groupID, id string) (*model.PropertyField, error) + GetMany(rctx request.CTX, groupID string, ids []string) ([]*model.PropertyField, error) + GetFieldByName(rctx request.CTX, groupID, targetID, name string) (*model.PropertyField, error) + GetFieldByNameForObjectType(rctx request.CTX, groupID, targetID, objectType, name string) (*model.PropertyField, error) + GetForGroup(rctx request.CTX, groupID string) ([]*model.PropertyField, error) CountForGroup(groupID string, includeDeleted bool) (int64, error) CountForGroupObjectType(groupID, objectType string, includeDeleted bool) (int64, error) CountForTarget(groupID, targetType, targetID string, includeDeleted bool) (int64, error) diff --git a/server/channels/store/storetest/mocks/PropertyFieldStore.go b/server/channels/store/storetest/mocks/PropertyFieldStore.go index 98df6783ebd..68adc8f8290 100644 --- a/server/channels/store/storetest/mocks/PropertyFieldStore.go +++ b/server/channels/store/storetest/mocks/PropertyFieldStore.go @@ -5,9 +5,8 @@ package mocks import ( - context "context" - model "github.com/mattermost/mattermost/server/public/model" + request "github.com/mattermost/mattermost/server/public/shared/request" mock "github.com/stretchr/testify/mock" ) @@ -204,9 +203,9 @@ func (_m *PropertyFieldStore) Delete(groupID string, id string) error { return r0 } -// Get provides a mock function with given fields: ctx, groupID, id -func (_m *PropertyFieldStore) Get(ctx context.Context, groupID string, id string) (*model.PropertyField, error) { - ret := _m.Called(ctx, groupID, id) +// Get provides a mock function with given fields: rctx, groupID, id +func (_m *PropertyFieldStore) Get(rctx request.CTX, groupID string, id string) (*model.PropertyField, error) { + ret := _m.Called(rctx, groupID, id) if len(ret) == 0 { panic("no return value specified for Get") @@ -214,19 +213,19 @@ func (_m *PropertyFieldStore) Get(ctx context.Context, groupID string, id string var r0 *model.PropertyField var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (*model.PropertyField, error)); ok { - return rf(ctx, groupID, id) + if rf, ok := ret.Get(0).(func(request.CTX, string, string) (*model.PropertyField, error)); ok { + return rf(rctx, groupID, id) } - if rf, ok := ret.Get(0).(func(context.Context, string, string) *model.PropertyField); ok { - r0 = rf(ctx, groupID, id) + if rf, ok := ret.Get(0).(func(request.CTX, string, string) *model.PropertyField); ok { + r0 = rf(rctx, groupID, id) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*model.PropertyField) } } - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, groupID, id) + if rf, ok := ret.Get(1).(func(request.CTX, string, string) error); ok { + r1 = rf(rctx, groupID, id) } else { r1 = ret.Error(1) } @@ -234,9 +233,9 @@ func (_m *PropertyFieldStore) Get(ctx context.Context, groupID string, id string return r0, r1 } -// GetFieldByName provides a mock function with given fields: ctx, groupID, targetID, name -func (_m *PropertyFieldStore) GetFieldByName(ctx context.Context, groupID string, targetID string, name string) (*model.PropertyField, error) { - ret := _m.Called(ctx, groupID, targetID, name) +// GetFieldByName provides a mock function with given fields: rctx, groupID, targetID, name +func (_m *PropertyFieldStore) GetFieldByName(rctx request.CTX, groupID string, targetID string, name string) (*model.PropertyField, error) { + ret := _m.Called(rctx, groupID, targetID, name) if len(ret) == 0 { panic("no return value specified for GetFieldByName") @@ -244,19 +243,19 @@ func (_m *PropertyFieldStore) GetFieldByName(ctx context.Context, groupID string var r0 *model.PropertyField var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (*model.PropertyField, error)); ok { - return rf(ctx, groupID, targetID, name) + if rf, ok := ret.Get(0).(func(request.CTX, string, string, string) (*model.PropertyField, error)); ok { + return rf(rctx, groupID, targetID, name) } - if rf, ok := ret.Get(0).(func(context.Context, string, string, string) *model.PropertyField); ok { - r0 = rf(ctx, groupID, targetID, name) + if rf, ok := ret.Get(0).(func(request.CTX, string, string, string) *model.PropertyField); ok { + r0 = rf(rctx, groupID, targetID, name) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*model.PropertyField) } } - if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { - r1 = rf(ctx, groupID, targetID, name) + if rf, ok := ret.Get(1).(func(request.CTX, string, string, string) error); ok { + r1 = rf(rctx, groupID, targetID, name) } else { r1 = ret.Error(1) } @@ -264,9 +263,9 @@ func (_m *PropertyFieldStore) GetFieldByName(ctx context.Context, groupID string return r0, r1 } -// GetFieldByNameForObjectType provides a mock function with given fields: ctx, groupID, targetID, objectType, name -func (_m *PropertyFieldStore) GetFieldByNameForObjectType(ctx context.Context, groupID string, targetID string, objectType string, name string) (*model.PropertyField, error) { - ret := _m.Called(ctx, groupID, targetID, objectType, name) +// GetFieldByNameForObjectType provides a mock function with given fields: rctx, groupID, targetID, objectType, name +func (_m *PropertyFieldStore) GetFieldByNameForObjectType(rctx request.CTX, groupID string, targetID string, objectType string, name string) (*model.PropertyField, error) { + ret := _m.Called(rctx, groupID, targetID, objectType, name) if len(ret) == 0 { panic("no return value specified for GetFieldByNameForObjectType") @@ -274,19 +273,19 @@ func (_m *PropertyFieldStore) GetFieldByNameForObjectType(ctx context.Context, g var r0 *model.PropertyField var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) (*model.PropertyField, error)); ok { - return rf(ctx, groupID, targetID, objectType, name) + if rf, ok := ret.Get(0).(func(request.CTX, string, string, string, string) (*model.PropertyField, error)); ok { + return rf(rctx, groupID, targetID, objectType, name) } - if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) *model.PropertyField); ok { - r0 = rf(ctx, groupID, targetID, objectType, name) + if rf, ok := ret.Get(0).(func(request.CTX, string, string, string, string) *model.PropertyField); ok { + r0 = rf(rctx, groupID, targetID, objectType, name) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*model.PropertyField) } } - if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string) error); ok { - r1 = rf(ctx, groupID, targetID, objectType, name) + if rf, ok := ret.Get(1).(func(request.CTX, string, string, string, string) error); ok { + r1 = rf(rctx, groupID, targetID, objectType, name) } else { r1 = ret.Error(1) } @@ -294,9 +293,9 @@ func (_m *PropertyFieldStore) GetFieldByNameForObjectType(ctx context.Context, g return r0, r1 } -// GetForGroup provides a mock function with given fields: ctx, groupID -func (_m *PropertyFieldStore) GetForGroup(ctx context.Context, groupID string) ([]*model.PropertyField, error) { - ret := _m.Called(ctx, groupID) +// GetForGroup provides a mock function with given fields: rctx, groupID +func (_m *PropertyFieldStore) GetForGroup(rctx request.CTX, groupID string) ([]*model.PropertyField, error) { + ret := _m.Called(rctx, groupID) if len(ret) == 0 { panic("no return value specified for GetForGroup") @@ -304,19 +303,19 @@ func (_m *PropertyFieldStore) GetForGroup(ctx context.Context, groupID string) ( var r0 []*model.PropertyField var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) ([]*model.PropertyField, error)); ok { - return rf(ctx, groupID) + if rf, ok := ret.Get(0).(func(request.CTX, string) ([]*model.PropertyField, error)); ok { + return rf(rctx, groupID) } - if rf, ok := ret.Get(0).(func(context.Context, string) []*model.PropertyField); ok { - r0 = rf(ctx, groupID) + if rf, ok := ret.Get(0).(func(request.CTX, string) []*model.PropertyField); ok { + r0 = rf(rctx, groupID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*model.PropertyField) } } - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, groupID) + if rf, ok := ret.Get(1).(func(request.CTX, string) error); ok { + r1 = rf(rctx, groupID) } else { r1 = ret.Error(1) } @@ -324,9 +323,9 @@ func (_m *PropertyFieldStore) GetForGroup(ctx context.Context, groupID string) ( return r0, r1 } -// GetMany provides a mock function with given fields: ctx, groupID, ids -func (_m *PropertyFieldStore) GetMany(ctx context.Context, groupID string, ids []string) ([]*model.PropertyField, error) { - ret := _m.Called(ctx, groupID, ids) +// GetMany provides a mock function with given fields: rctx, groupID, ids +func (_m *PropertyFieldStore) GetMany(rctx request.CTX, groupID string, ids []string) ([]*model.PropertyField, error) { + ret := _m.Called(rctx, groupID, ids) if len(ret) == 0 { panic("no return value specified for GetMany") @@ -334,19 +333,19 @@ func (_m *PropertyFieldStore) GetMany(ctx context.Context, groupID string, ids [ var r0 []*model.PropertyField var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, []string) ([]*model.PropertyField, error)); ok { - return rf(ctx, groupID, ids) + if rf, ok := ret.Get(0).(func(request.CTX, string, []string) ([]*model.PropertyField, error)); ok { + return rf(rctx, groupID, ids) } - if rf, ok := ret.Get(0).(func(context.Context, string, []string) []*model.PropertyField); ok { - r0 = rf(ctx, groupID, ids) + if rf, ok := ret.Get(0).(func(request.CTX, string, []string) []*model.PropertyField); ok { + r0 = rf(rctx, groupID, ids) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*model.PropertyField) } } - if rf, ok := ret.Get(1).(func(context.Context, string, []string) error); ok { - r1 = rf(ctx, groupID, ids) + if rf, ok := ret.Get(1).(func(request.CTX, string, []string) error); ok { + r1 = rf(rctx, groupID, ids) } else { r1 = ret.Error(1) } diff --git a/server/channels/store/storetest/property_field_store.go b/server/channels/store/storetest/property_field_store.go index b5eeacebc3f..fc4bf143027 100644 --- a/server/channels/store/storetest/property_field_store.go +++ b/server/channels/store/storetest/property_field_store.go @@ -4,7 +4,6 @@ package storetest import ( - "context" "fmt" "slices" "testing" @@ -34,7 +33,7 @@ func TestPropertyFieldStore(t *testing.T, rctx request.CTX, ss store.Store, s Sq t.Run("SearchByLinkedFieldID", func(t *testing.T) { testSearchByLinkedFieldID(t, rctx, ss) }) } -func testCreatePropertyField(t *testing.T, _ request.CTX, ss store.Store) { +func testCreatePropertyField(t *testing.T, rctx request.CTX, ss store.Store) { t.Run("should fail if the property field already has an ID set", func(t *testing.T) { newField := &model.PropertyField{ID: "sampleid"} field, err := ss.PropertyField().Create(newField) @@ -114,7 +113,7 @@ func testCreatePropertyField(t *testing.T, _ request.CTX, ss store.Store) { require.Equal(t, model.PropertyFieldObjectTypeChannel, created.ObjectType) // Verify it can be retrieved with ObjectType intact - retrieved, err := ss.PropertyField().Get(context.Background(), "", created.ID) + retrieved, err := ss.PropertyField().Get(rctx, "", created.ID) require.NoError(t, err) require.Equal(t, model.PropertyFieldObjectTypeChannel, retrieved.ObjectType) }) @@ -133,7 +132,7 @@ func testCreatePropertyField(t *testing.T, _ request.CTX, ss store.Store) { require.Empty(t, created.ObjectType) // Verify it can be retrieved - retrieved, err := ss.PropertyField().Get(context.Background(), "", created.ID) + retrieved, err := ss.PropertyField().Get(rctx, "", created.ID) require.NoError(t, err) require.Empty(t, retrieved.ObjectType) }) @@ -219,9 +218,9 @@ func insertPropertyFieldWithNullColumns(t *testing.T, ss store.Store, s SqlStore return groupID, fieldID } -func testGetPropertyField(t *testing.T, _ request.CTX, ss store.Store, s SqlStore) { +func testGetPropertyField(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) { t.Run("should fail on nonexisting field", func(t *testing.T) { - field, err := ss.PropertyField().Get(context.Background(), "", model.NewId()) + field, err := ss.PropertyField().Get(rctx, "", model.NewId()) require.Zero(t, field) var notFoundErr *store.ErrNotFound require.ErrorAs(t, err, ¬FoundErr) @@ -242,14 +241,14 @@ func testGetPropertyField(t *testing.T, _ request.CTX, ss store.Store, s SqlStor require.NotZero(t, newField.ID) t.Run("should be able to retrieve an existing property field", func(t *testing.T) { - field, err := ss.PropertyField().Get(context.Background(), groupID, newField.ID) + field, err := ss.PropertyField().Get(rctx, groupID, newField.ID) require.NoError(t, err) require.Equal(t, newField.ID, field.ID) require.True(t, field.Attrs["locked"].(bool)) require.Equal(t, "value", field.Attrs["special"]) // should work without specifying the group ID as well - field, err = ss.PropertyField().Get(context.Background(), "", newField.ID) + field, err = ss.PropertyField().Get(rctx, "", newField.ID) require.NoError(t, err) require.Equal(t, newField.ID, field.ID) require.True(t, field.Attrs["locked"].(bool)) @@ -257,7 +256,7 @@ func testGetPropertyField(t *testing.T, _ request.CTX, ss store.Store, s SqlStor }) t.Run("should not be able to retrieve an existing field when specifying a different group ID", func(t *testing.T) { - field, err := ss.PropertyField().Get(context.Background(), model.NewId(), newField.ID) + field, err := ss.PropertyField().Get(rctx, model.NewId(), newField.ID) require.Zero(t, field) var notFoundErr *store.ErrNotFound require.ErrorAs(t, err, ¬FoundErr) @@ -266,7 +265,7 @@ func testGetPropertyField(t *testing.T, _ request.CTX, ss store.Store, s SqlStor t.Run("null columns, before createdBy, updatedBy, protected and permissions migrations", func(t *testing.T) { groupID, fieldID := insertPropertyFieldWithNullColumns(t, ss, s) - field, err := ss.PropertyField().Get(context.Background(), groupID, fieldID) + field, err := ss.PropertyField().Get(rctx, groupID, fieldID) require.NoError(t, err) require.Equal(t, fieldID, field.ID) require.Empty(t, field.CreatedBy) @@ -278,9 +277,9 @@ func testGetPropertyField(t *testing.T, _ request.CTX, ss store.Store, s SqlStor }) } -func testGetManyPropertyFields(t *testing.T, _ request.CTX, ss store.Store) { +func testGetManyPropertyFields(t *testing.T, rctx request.CTX, ss store.Store) { t.Run("should fail on nonexisting fields", func(t *testing.T) { - fields, err := ss.PropertyField().GetMany(context.Background(), "", []string{model.NewId(), model.NewId()}) + fields, err := ss.PropertyField().GetMany(rctx, "", []string{model.NewId(), model.NewId()}) require.Empty(t, fields) var target *store.ErrResultsMismatch require.ErrorAs(t, err, &target) @@ -311,36 +310,36 @@ func testGetManyPropertyFields(t *testing.T, _ request.CTX, ss store.Store) { require.NotZero(t, newFieldOutsideGroup.ID) t.Run("should fail if at least one of the ids is nonexistent", func(t *testing.T) { - fields, err := ss.PropertyField().GetMany(context.Background(), groupID, []string{newFields[0].ID, newFields[1].ID, model.NewId()}) + fields, err := ss.PropertyField().GetMany(rctx, groupID, []string{newFields[0].ID, newFields[1].ID, model.NewId()}) require.Empty(t, fields) var target *store.ErrResultsMismatch require.ErrorAs(t, err, &target) }) t.Run("should be able to retrieve existing property fields", func(t *testing.T) { - fields, err := ss.PropertyField().GetMany(context.Background(), groupID, []string{newFields[0].ID, newFields[1].ID, newFields[2].ID}) + fields, err := ss.PropertyField().GetMany(rctx, groupID, []string{newFields[0].ID, newFields[1].ID, newFields[2].ID}) require.NoError(t, err) require.Len(t, fields, 3) require.ElementsMatch(t, newFields, fields) }) t.Run("should fail if asked for valid IDs but outside the group", func(t *testing.T) { - fields, err := ss.PropertyField().GetMany(context.Background(), groupID, []string{newFields[0].ID, newFieldOutsideGroup.ID}) + fields, err := ss.PropertyField().GetMany(rctx, groupID, []string{newFields[0].ID, newFieldOutsideGroup.ID}) require.Empty(t, fields) var target *store.ErrResultsMismatch require.ErrorAs(t, err, &target) }) t.Run("should be able to retrieve existing property fields from multiple groups", func(t *testing.T) { - fields, err := ss.PropertyField().GetMany(context.Background(), "", []string{newFields[0].ID, newFieldOutsideGroup.ID}) + fields, err := ss.PropertyField().GetMany(rctx, "", []string{newFields[0].ID, newFieldOutsideGroup.ID}) require.NoError(t, err) require.Len(t, fields, 2) }) } -func testGetFieldByName(t *testing.T, _ request.CTX, ss store.Store) { +func testGetFieldByName(t *testing.T, rctx request.CTX, ss store.Store) { t.Run("should fail on nonexisting field", func(t *testing.T) { - field, err := ss.PropertyField().GetFieldByName(context.Background(), "", "", "nonexistent-field-name") + field, err := ss.PropertyField().GetFieldByName(rctx, "", "", "nonexistent-field-name") require.Zero(t, field) var enf *store.ErrNotFound require.ErrorAs(t, err, &enf) @@ -363,7 +362,7 @@ func testGetFieldByName(t *testing.T, _ request.CTX, ss store.Store) { require.NotZero(t, newField.ID) t.Run("should be able to retrieve an existing property field by name", func(t *testing.T) { - field, err := ss.PropertyField().GetFieldByName(context.Background(), groupID, targetID, "unique-field-name") + field, err := ss.PropertyField().GetFieldByName(rctx, groupID, targetID, "unique-field-name") require.NoError(t, err) require.Equal(t, newField.ID, field.ID) require.Equal(t, "unique-field-name", field.Name) @@ -372,14 +371,14 @@ func testGetFieldByName(t *testing.T, _ request.CTX, ss store.Store) { }) t.Run("should not be able to retrieve an existing field when specifying a different group ID", func(t *testing.T) { - field, err := ss.PropertyField().GetFieldByName(context.Background(), model.NewId(), targetID, "unique-field-name") + field, err := ss.PropertyField().GetFieldByName(rctx, model.NewId(), targetID, "unique-field-name") require.Zero(t, field) var enf *store.ErrNotFound require.ErrorAs(t, err, &enf) }) t.Run("should not be able to retrieve an existing field when specifying a different target ID", func(t *testing.T) { - field, err := ss.PropertyField().GetFieldByName(context.Background(), groupID, model.NewId(), "unique-field-name") + field, err := ss.PropertyField().GetFieldByName(rctx, groupID, model.NewId(), "unique-field-name") require.Zero(t, field) var enf *store.ErrNotFound require.ErrorAs(t, err, &enf) @@ -406,13 +405,13 @@ func testGetFieldByName(t *testing.T, _ request.CTX, ss store.Store) { t.Run("should retrieve the correct field when multiple fields have the same name but different groups", func(t *testing.T) { // Get the field from the first group - field, err := ss.PropertyField().GetFieldByName(context.Background(), groupID, targetID, "unique-field-name") + field, err := ss.PropertyField().GetFieldByName(rctx, groupID, targetID, "unique-field-name") require.NoError(t, err) require.Equal(t, newField.ID, field.ID) require.Equal(t, model.PropertyFieldTypeText, field.Type) // Get the field from the second group - field, err = ss.PropertyField().GetFieldByName(context.Background(), anotherGroupID, targetID, "unique-field-name") + field, err = ss.PropertyField().GetFieldByName(rctx, anotherGroupID, targetID, "unique-field-name") require.NoError(t, err) require.Equal(t, duplicateNameField.ID, field.ID) require.Equal(t, model.PropertyFieldTypeSelect, field.Type) @@ -436,13 +435,13 @@ func testGetFieldByName(t *testing.T, _ request.CTX, ss store.Store) { t.Run("should retrieve the correct field when multiple fields have the same name and group but different target IDs", func(t *testing.T) { // Get the field with the first target ID - field, err := ss.PropertyField().GetFieldByName(context.Background(), groupID, targetID, "unique-field-name") + field, err := ss.PropertyField().GetFieldByName(rctx, groupID, targetID, "unique-field-name") require.NoError(t, err) require.Equal(t, newField.ID, field.ID) require.Equal(t, model.PropertyFieldTypeText, field.Type) // Get the field with the second target ID - field, err = ss.PropertyField().GetFieldByName(context.Background(), groupID, anotherTargetID, "unique-field-name") + field, err = ss.PropertyField().GetFieldByName(rctx, groupID, anotherTargetID, "unique-field-name") require.NoError(t, err) require.Equal(t, sameGroupDifferentTargetField.ID, field.ID) require.Equal(t, model.PropertyFieldTypeText, field.Type) @@ -462,7 +461,7 @@ func testGetFieldByName(t *testing.T, _ request.CTX, ss store.Store) { require.NotZero(t, deletedField.ID) // Verify it can be retrieved before deletion - field, err := ss.PropertyField().GetFieldByName(context.Background(), groupID, targetID, "to-be-deleted-field") + field, err := ss.PropertyField().GetFieldByName(rctx, groupID, targetID, "to-be-deleted-field") require.NoError(t, err) require.Equal(t, deletedField.ID, field.ID) @@ -471,7 +470,7 @@ func testGetFieldByName(t *testing.T, _ request.CTX, ss store.Store) { require.NoError(t, err) // Verify it can't be retrieved after deletion - field, err = ss.PropertyField().GetFieldByName(context.Background(), groupID, targetID, "to-be-deleted-field") + field, err = ss.PropertyField().GetFieldByName(rctx, groupID, targetID, "to-be-deleted-field") require.Zero(t, field) var enf *store.ErrNotFound require.ErrorAs(t, err, &enf) @@ -494,7 +493,7 @@ func testGetFieldByName(t *testing.T, _ request.CTX, ss store.Store) { require.NotZero(t, replacementField.ID) // Verify only the non-deleted field is retrieved - field, err := ss.PropertyField().GetFieldByName(context.Background(), groupID, targetID, "to-be-deleted-field") + field, err := ss.PropertyField().GetFieldByName(rctx, groupID, targetID, "to-be-deleted-field") require.NoError(t, err) require.Equal(t, replacementField.ID, field.ID) require.Equal(t, model.PropertyFieldTypeText, field.Type) @@ -502,7 +501,7 @@ func testGetFieldByName(t *testing.T, _ request.CTX, ss store.Store) { }) } -func testGetFieldByNameForObjectType(t *testing.T, _ request.CTX, ss store.Store) { +func testGetFieldByNameForObjectType(t *testing.T, rctx request.CTX, ss store.Store) { // Two system-scoped fields share group and name, differing only by // ObjectType — the collision the scoped lookup must disambiguate. groupID := model.NewId() @@ -531,19 +530,19 @@ func testGetFieldByNameForObjectType(t *testing.T, _ request.CTX, ss store.Store require.NotZero(t, systemField.ID) t.Run("should resolve to the field matching the requested object type", func(t *testing.T) { - field, err := ss.PropertyField().GetFieldByNameForObjectType(context.Background(), groupID, "", model.PropertyFieldObjectTypeUser, "classification") + field, err := ss.PropertyField().GetFieldByNameForObjectType(rctx, groupID, "", model.PropertyFieldObjectTypeUser, "classification") require.NoError(t, err) require.Equal(t, userField.ID, field.ID) require.Equal(t, model.PropertyFieldObjectTypeUser, field.ObjectType) - field, err = ss.PropertyField().GetFieldByNameForObjectType(context.Background(), groupID, "", model.PropertyFieldObjectTypeSystem, "classification") + field, err = ss.PropertyField().GetFieldByNameForObjectType(rctx, groupID, "", model.PropertyFieldObjectTypeSystem, "classification") require.NoError(t, err) require.Equal(t, systemField.ID, field.ID) require.Equal(t, model.PropertyFieldObjectTypeSystem, field.ObjectType) }) t.Run("should not match a field of a different object type", func(t *testing.T) { - field, err := ss.PropertyField().GetFieldByNameForObjectType(context.Background(), groupID, "", model.PropertyFieldObjectTypeChannel, "classification") + field, err := ss.PropertyField().GetFieldByNameForObjectType(rctx, groupID, "", model.PropertyFieldObjectTypeChannel, "classification") require.Zero(t, field) var enf *store.ErrNotFound require.ErrorAs(t, err, &enf) @@ -552,14 +551,14 @@ func testGetFieldByNameForObjectType(t *testing.T, _ request.CTX, ss store.Store t.Run("empty object type is matched exactly, not as match-any", func(t *testing.T) { // Neither field has an empty object type, so an empty-object-type lookup // must miss rather than return an arbitrary match. - field, err := ss.PropertyField().GetFieldByNameForObjectType(context.Background(), groupID, "", "", "classification") + field, err := ss.PropertyField().GetFieldByNameForObjectType(rctx, groupID, "", "", "classification") require.Zero(t, field) var enf *store.ErrNotFound require.ErrorAs(t, err, &enf) }) } -func testUpdatePropertyField(t *testing.T, _ request.CTX, ss store.Store) { +func testUpdatePropertyField(t *testing.T, rctx request.CTX, ss store.Store) { t.Run("should fail on nonexisting field", func(t *testing.T) { field := &model.PropertyField{ ID: model.NewId(), @@ -645,7 +644,7 @@ func testUpdatePropertyField(t *testing.T, _ request.CTX, ss store.Store) { require.NoError(t, err) // Verify first field - updated1, err := ss.PropertyField().Get(context.Background(), "", field1.ID) + updated1, err := ss.PropertyField().Get(rctx, "", field1.ID) require.NoError(t, err) require.Equal(t, "Updated first", updated1.Name) require.Equal(t, model.PropertyFieldTypeSelect, updated1.Type) @@ -655,7 +654,7 @@ func testUpdatePropertyField(t *testing.T, _ request.CTX, ss store.Store) { require.Greater(t, updated1.UpdateAt, updated1.CreateAt) // Verify second field - updated2, err := ss.PropertyField().Get(context.Background(), "", field2.ID) + updated2, err := ss.PropertyField().Get(rctx, "", field2.ID) require.NoError(t, err) require.Equal(t, "Updated second", updated2.Name) require.Equal(t, model.PropertyFieldTypeSelect, updated2.Type) @@ -789,12 +788,12 @@ func testUpdatePropertyField(t *testing.T, _ request.CTX, ss store.Store) { require.ErrorContains(t, err, "model.property_field.is_valid.app_error") // Check that fields were not updated - updated1, err := ss.PropertyField().Get(context.Background(), "", field1.ID) + updated1, err := ss.PropertyField().Get(rctx, "", field1.ID) require.NoError(t, err) require.Equal(t, "Field 1", updated1.Name) require.Equal(t, originalUpdateAt1, updated1.UpdateAt) - updated2, err := ss.PropertyField().Get(context.Background(), "", field2.ID) + updated2, err := ss.PropertyField().Get(rctx, "", field2.ID) require.NoError(t, err) require.Equal(t, groupID, updated2.GroupID) require.Equal(t, originalUpdateAt2, updated2.UpdateAt) @@ -834,7 +833,7 @@ func testUpdatePropertyField(t *testing.T, _ request.CTX, ss store.Store) { require.ErrorContains(t, err, "failed to update, some property fields were not found") // Check that the valid field was not updated - updated1, err := ss.PropertyField().Get(context.Background(), "", field1.ID) + updated1, err := ss.PropertyField().Get(rctx, "", field1.ID) require.NoError(t, err) require.Equal(t, "First field", updated1.Name) require.Equal(t, originalUpdateAt, updated1.UpdateAt) @@ -869,7 +868,7 @@ func testUpdatePropertyField(t *testing.T, _ request.CTX, ss store.Store) { // Verify the fields were updated for _, field := range []*model.PropertyField{field1, field2} { - updated, err := ss.PropertyField().Get(context.Background(), "", field.ID) + updated, err := ss.PropertyField().Get(rctx, "", field.ID) require.NoError(t, err) require.Contains(t, updated.Name, "Updated Group Field") } @@ -908,11 +907,11 @@ func testUpdatePropertyField(t *testing.T, _ request.CTX, ss store.Store) { require.ErrorContains(t, err, "failed to update, some property fields were not found") // Verify neither field was updated due to transaction rollback - updated1, err := ss.PropertyField().Get(context.Background(), "", field1.ID) + updated1, err := ss.PropertyField().Get(rctx, "", field1.ID) require.NoError(t, err) require.Equal(t, originalName1, updated1.Name) - updated2, err := ss.PropertyField().Get(context.Background(), "", field2.ID) + updated2, err := ss.PropertyField().Get(rctx, "", field2.ID) require.NoError(t, err) require.Equal(t, originalName2, updated2.Name) }) @@ -940,7 +939,7 @@ func testUpdatePropertyField(t *testing.T, _ request.CTX, ss store.Store) { require.NoError(t, err) // Verify CreatedBy stays the same but UpdatedBy changes - fetched, err := ss.PropertyField().Get(context.Background(), "", field.ID) + fetched, err := ss.PropertyField().Get(rctx, "", field.ID) require.NoError(t, err) require.Equal(t, creatorUserID, fetched.CreatedBy, "CreatedBy should not change on update") require.Equal(t, updaterUserID, fetched.UpdatedBy, "UpdatedBy should change on update") @@ -983,19 +982,19 @@ func testUpdatePropertyField(t *testing.T, _ request.CTX, ss store.Store) { require.NoError(t, err) // Verify both fields have correct UpdatedBy - fetched1, err := ss.PropertyField().Get(context.Background(), "", field1.ID) + fetched1, err := ss.PropertyField().Get(rctx, "", field1.ID) require.NoError(t, err) require.Equal(t, user1, fetched1.UpdatedBy) require.Equal(t, creatorUserID, fetched1.CreatedBy) - fetched2, err := ss.PropertyField().Get(context.Background(), "", field2.ID) + fetched2, err := ss.PropertyField().Get(rctx, "", field2.ID) require.NoError(t, err) require.Equal(t, user2, fetched2.UpdatedBy) require.Equal(t, creatorUserID, fetched2.CreatedBy) }) } -func testDeletePropertyField(t *testing.T, _ request.CTX, ss store.Store) { +func testDeletePropertyField(t *testing.T, rctx request.CTX, ss store.Store) { t.Run("should fail on nonexisting field", func(t *testing.T) { err := ss.PropertyField().Delete("", model.NewId()) var enf *store.ErrNotFound @@ -1017,7 +1016,7 @@ func testDeletePropertyField(t *testing.T, _ request.CTX, ss store.Store) { require.NoError(t, err) // Verify the field was soft-deleted - deletedField, err := ss.PropertyField().Get(context.Background(), "", field.ID) + deletedField, err := ss.PropertyField().Get(rctx, "", field.ID) require.NoError(t, err) require.NotZero(t, deletedField.DeleteAt) }) @@ -1044,7 +1043,7 @@ func testDeletePropertyField(t *testing.T, _ request.CTX, ss store.Store) { require.NoError(t, err) // Verify the field was soft-deleted - deletedField, err := ss.PropertyField().Get(context.Background(), groupID, field.ID) + deletedField, err := ss.PropertyField().Get(rctx, groupID, field.ID) require.NoError(t, err) require.NotZero(t, deletedField.DeleteAt) }) @@ -1067,7 +1066,7 @@ func testDeletePropertyField(t *testing.T, _ request.CTX, ss store.Store) { require.ErrorAs(t, err, &enf) // Verify the field was not deleted - nonDeletedField, err := ss.PropertyField().Get(context.Background(), groupID, field.ID) + nonDeletedField, err := ss.PropertyField().Get(rctx, groupID, field.ID) require.NoError(t, err) require.Zero(t, nonDeletedField.DeleteAt) }) @@ -3069,7 +3068,7 @@ func testCountLinkedFields(t *testing.T, _ request.CTX, ss store.Store) { }) } -func testUpdateWithPropagation(t *testing.T, _ request.CTX, ss store.Store) { +func testUpdateWithPropagation(t *testing.T, rctx request.CTX, ss store.Store) { groupID := model.NewId() optA := map[string]any{"id": model.NewId(), "name": "A"} @@ -3134,12 +3133,12 @@ func testUpdateWithPropagation(t *testing.T, _ request.CTX, ss store.Store) { require.Len(t, result, 3) // Verify both linked fields now have the updated options - retrievedLinked1, gErr := ss.PropertyField().Get(context.Background(), "", linked1.ID) + retrievedLinked1, gErr := ss.PropertyField().Get(rctx, "", linked1.ID) require.NoError(t, gErr) options1 := retrievedLinked1.Attrs["options"].([]any) require.Len(t, options1, 3) - retrievedLinked2, gErr := ss.PropertyField().Get(context.Background(), "", linked2.ID) + retrievedLinked2, gErr := ss.PropertyField().Get(rctx, "", linked2.ID) require.NoError(t, gErr) options2 := retrievedLinked2.Attrs["options"].([]any) require.Len(t, options2, 3) @@ -3159,12 +3158,12 @@ func testUpdateWithPropagation(t *testing.T, _ request.CTX, ss store.Store) { require.Len(t, result, 3) // source + 2 linked // Verify linked fields have exactly 2 options - retrievedLinked1, gErr := ss.PropertyField().Get(context.Background(), "", linked1.ID) + retrievedLinked1, gErr := ss.PropertyField().Get(rctx, "", linked1.ID) require.NoError(t, gErr) options1 := retrievedLinked1.Attrs["options"].([]any) require.Len(t, options1, 2) - retrievedLinked2, gErr := ss.PropertyField().Get(context.Background(), "", linked2.ID) + retrievedLinked2, gErr := ss.PropertyField().Get(rctx, "", linked2.ID) require.NoError(t, gErr) options2 := retrievedLinked2.Attrs["options"].([]any) require.Len(t, options2, 2) @@ -3183,7 +3182,7 @@ func testUpdateWithPropagation(t *testing.T, _ request.CTX, ss store.Store) { require.NoError(t, uErr) // Verify linked fields have the renamed option - retrievedLinked1, gErr := ss.PropertyField().Get(context.Background(), "", linked1.ID) + retrievedLinked1, gErr := ss.PropertyField().Get(rctx, "", linked1.ID) require.NoError(t, gErr) options1 := retrievedLinked1.Attrs["options"].([]any) require.Len(t, options1, 1) @@ -3202,7 +3201,7 @@ func testUpdateWithPropagation(t *testing.T, _ request.CTX, ss store.Store) { t.Run("should reject update when expectedUpdateAts do not match (optimistic concurrency)", func(t *testing.T) { // Read the current state of the source field - current, gErr := ss.PropertyField().Get(context.Background(), "", sourceField.ID) + current, gErr := ss.PropertyField().Get(rctx, "", sourceField.ID) require.NoError(t, gErr) // Simulate a concurrent update by directly modifying the field @@ -3220,14 +3219,14 @@ func testUpdateWithPropagation(t *testing.T, _ request.CTX, ss store.Store) { require.ErrorAs(t, uErr, &conflictErr) // Verify the field was NOT updated (concurrent update's value persists) - after, gErr := ss.PropertyField().Get(context.Background(), "", sourceField.ID) + after, gErr := ss.PropertyField().Get(rctx, "", sourceField.ID) require.NoError(t, gErr) require.Equal(t, "Concurrent Update", after.Name) }) t.Run("should succeed when expectedUpdateAts match current state", func(t *testing.T) { // Read the current state - current, gErr := ss.PropertyField().Get(context.Background(), "", sourceField.ID) + current, gErr := ss.PropertyField().Get(rctx, "", sourceField.ID) require.NoError(t, gErr) // Update with correct expectedUpdateAts @@ -3252,7 +3251,7 @@ func testUpdateWithPropagation(t *testing.T, _ request.CTX, ss store.Store) { require.NoError(t, cErr) // Get fresh state of batch field - freshBatch, gErr := ss.PropertyField().Get(context.Background(), "", batchField.ID) + freshBatch, gErr := ss.PropertyField().Get(rctx, "", batchField.ID) require.NoError(t, gErr) // Save the pre-update UpdateAt before the concurrent modification @@ -3267,7 +3266,7 @@ func testUpdateWithPropagation(t *testing.T, _ request.CTX, ss store.Store) { require.NoError(t, uErr) // Re-fetch the source since it wasn't modified (its UpdateAt is still valid) - freshSource, gErr := ss.PropertyField().Get(context.Background(), "", sourceField.ID) + freshSource, gErr := ss.PropertyField().Get(rctx, "", sourceField.ID) require.NoError(t, gErr) // Attempt batch update using stale UpdateAt for batchField but fresh for source @@ -3284,18 +3283,18 @@ func testUpdateWithPropagation(t *testing.T, _ request.CTX, ss store.Store) { require.ErrorAs(t, uErr, &conflictErr) // Verify neither field was updated (transaction rolled back) - afterSource, gErr := ss.PropertyField().Get(context.Background(), "", sourceField.ID) + afterSource, gErr := ss.PropertyField().Get(rctx, "", sourceField.ID) require.NoError(t, gErr) require.NotEqual(t, "Should Not Stick", afterSource.Name) - afterBatch, gErr := ss.PropertyField().Get(context.Background(), "", batchField.ID) + afterBatch, gErr := ss.PropertyField().Get(rctx, "", batchField.ID) require.NoError(t, gErr) require.Equal(t, "Concurrent Batch Change", afterBatch.Name) }) t.Run("should propagate and enforce optimistic concurrency together", func(t *testing.T) { // Get fresh state of source field for OCC - freshSource, gErr := ss.PropertyField().Get(context.Background(), "", sourceField.ID) + freshSource, gErr := ss.PropertyField().Get(rctx, "", sourceField.ID) require.NoError(t, gErr) optNew := map[string]any{"id": model.NewId(), "name": "PropagateOCC"} @@ -3309,7 +3308,7 @@ func testUpdateWithPropagation(t *testing.T, _ request.CTX, ss store.Store) { require.Len(t, result, 3) // Verify propagation occurred on linked fields - retrievedLinked1, gErr := ss.PropertyField().Get(context.Background(), "", linked1.ID) + retrievedLinked1, gErr := ss.PropertyField().Get(rctx, "", linked1.ID) require.NoError(t, gErr) opts := retrievedLinked1.Attrs["options"].([]any) require.Len(t, opts, 1) @@ -3317,7 +3316,7 @@ func testUpdateWithPropagation(t *testing.T, _ request.CTX, ss store.Store) { }) t.Run("should reject propagation when source has stale expectedUpdateAt", func(t *testing.T) { - freshSource, gErr := ss.PropertyField().Get(context.Background(), "", sourceField.ID) + freshSource, gErr := ss.PropertyField().Get(rctx, "", sourceField.ID) require.NoError(t, gErr) // Save the pre-update UpdateAt @@ -3341,7 +3340,7 @@ func testUpdateWithPropagation(t *testing.T, _ request.CTX, ss store.Store) { require.ErrorAs(t, uErr, &conflictErr) // Verify linked fields were NOT updated (propagation rolled back) - retrievedLinked1, gErr := ss.PropertyField().Get(context.Background(), "", linked1.ID) + retrievedLinked1, gErr := ss.PropertyField().Get(rctx, "", linked1.ID) require.NoError(t, gErr) opts := retrievedLinked1.Attrs["options"].([]any) firstOpt := opts[0].(map[string]any) @@ -3349,7 +3348,7 @@ func testUpdateWithPropagation(t *testing.T, _ request.CTX, ss store.Store) { }) t.Run("nil expectedUpdateAts should skip concurrency check (backwards compat)", func(t *testing.T) { - freshSource, gErr := ss.PropertyField().Get(context.Background(), "", sourceField.ID) + freshSource, gErr := ss.PropertyField().Get(rctx, "", sourceField.ID) require.NoError(t, gErr) // Update without any concurrency check — should always succeed diff --git a/server/channels/store/timerlayer/timerlayer.go b/server/channels/store/timerlayer/timerlayer.go index 5e301eddbc4..bf5e2a20780 100644 --- a/server/channels/store/timerlayer/timerlayer.go +++ b/server/channels/store/timerlayer/timerlayer.go @@ -7,7 +7,6 @@ package timerlayer import ( - "context" "time" "github.com/mattermost/mattermost/server/public/model" @@ -8452,10 +8451,10 @@ func (s *TimerLayerPropertyFieldStore) Delete(groupID string, id string) error { return err } -func (s *TimerLayerPropertyFieldStore) Get(ctx context.Context, groupID string, id string) (*model.PropertyField, error) { +func (s *TimerLayerPropertyFieldStore) Get(rctx request.CTX, groupID string, id string) (*model.PropertyField, error) { start := time.Now() - result, err := s.PropertyFieldStore.Get(ctx, groupID, id) + result, err := s.PropertyFieldStore.Get(rctx, groupID, id) elapsed := float64(time.Since(start)) / float64(time.Second) if s.Root.Metrics != nil { @@ -8468,10 +8467,10 @@ func (s *TimerLayerPropertyFieldStore) Get(ctx context.Context, groupID string, return result, err } -func (s *TimerLayerPropertyFieldStore) GetFieldByName(ctx context.Context, groupID string, targetID string, name string) (*model.PropertyField, error) { +func (s *TimerLayerPropertyFieldStore) GetFieldByName(rctx request.CTX, groupID string, targetID string, name string) (*model.PropertyField, error) { start := time.Now() - result, err := s.PropertyFieldStore.GetFieldByName(ctx, groupID, targetID, name) + result, err := s.PropertyFieldStore.GetFieldByName(rctx, groupID, targetID, name) elapsed := float64(time.Since(start)) / float64(time.Second) if s.Root.Metrics != nil { @@ -8484,10 +8483,10 @@ func (s *TimerLayerPropertyFieldStore) GetFieldByName(ctx context.Context, group return result, err } -func (s *TimerLayerPropertyFieldStore) GetFieldByNameForObjectType(ctx context.Context, groupID string, targetID string, objectType string, name string) (*model.PropertyField, error) { +func (s *TimerLayerPropertyFieldStore) GetFieldByNameForObjectType(rctx request.CTX, groupID string, targetID string, objectType string, name string) (*model.PropertyField, error) { start := time.Now() - result, err := s.PropertyFieldStore.GetFieldByNameForObjectType(ctx, groupID, targetID, objectType, name) + result, err := s.PropertyFieldStore.GetFieldByNameForObjectType(rctx, groupID, targetID, objectType, name) elapsed := float64(time.Since(start)) / float64(time.Second) if s.Root.Metrics != nil { @@ -8500,10 +8499,10 @@ func (s *TimerLayerPropertyFieldStore) GetFieldByNameForObjectType(ctx context.C return result, err } -func (s *TimerLayerPropertyFieldStore) GetForGroup(ctx context.Context, groupID string) ([]*model.PropertyField, error) { +func (s *TimerLayerPropertyFieldStore) GetForGroup(rctx request.CTX, groupID string) ([]*model.PropertyField, error) { start := time.Now() - result, err := s.PropertyFieldStore.GetForGroup(ctx, groupID) + result, err := s.PropertyFieldStore.GetForGroup(rctx, groupID) elapsed := float64(time.Since(start)) / float64(time.Second) if s.Root.Metrics != nil { @@ -8516,10 +8515,10 @@ func (s *TimerLayerPropertyFieldStore) GetForGroup(ctx context.Context, groupID return result, err } -func (s *TimerLayerPropertyFieldStore) GetMany(ctx context.Context, groupID string, ids []string) ([]*model.PropertyField, error) { +func (s *TimerLayerPropertyFieldStore) GetMany(rctx request.CTX, groupID string, ids []string) ([]*model.PropertyField, error) { start := time.Now() - result, err := s.PropertyFieldStore.GetMany(ctx, groupID, ids) + result, err := s.PropertyFieldStore.GetMany(rctx, groupID, ids) elapsed := float64(time.Since(start)) / float64(time.Second) if s.Root.Metrics != nil {