[MM-70224] Migrate property field reads to request context (#37636)

* Migrate property field reads to request context

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

* Preserve nil property service request context behavior

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

* Use explicit session attributes system context

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

* Use non-nil property contexts for internal calls

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

* Thread request context through content flagging lookups

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

* Update content flagging helper tests for request context

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

* Thread request context through content flagging values

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

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

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

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

* Remove context import directly from store layer templates

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

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

* Remove deprecated store.WithMaster/sqlstore.WithMaster helpers

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

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

* Fix TestDoSetupSessionAttributesProperties nil-context panic

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

* ci trigger

* ci trigger

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Ben Schumacher
2026-08-24 10:35:12 +02:00
committed by GitHub
parent 2d6fc01907
commit a3e171f730
31 changed files with 388 additions and 416 deletions
+3 -3
View File
@@ -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
+2 -2
View File
@@ -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
}
+33 -33
View File
@@ -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)
}
@@ -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)
@@ -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
}
@@ -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)
+46 -46
View File
@@ -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
+22 -16
View File
@@ -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)
}
+5 -5
View File
@@ -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())
@@ -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)
}
@@ -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
@@ -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
@@ -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
}
@@ -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
}
@@ -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)
})
}
+6 -7
View File
@@ -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
}
+1 -9
View File
@@ -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
}
-8
View File
@@ -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)
@@ -7,7 +7,6 @@
package retrylayer
import (
"context"
timepkg "time"
"github.com/lib/pq"
@@ -7,7 +7,6 @@
package timerlayer
import (
"context"
"time"
"github.com/mattermost/mattermost/server/public/model"
@@ -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)
@@ -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
}
@@ -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)
})
+10 -11
View File
@@ -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
}
@@ -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)
@@ -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()
@@ -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")
}
+5 -6
View File
@@ -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)
@@ -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)
}
@@ -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, &notFoundErr)
@@ -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, &notFoundErr)
@@ -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
+10 -11
View File
@@ -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 {