mirror of
https://github.com/mattermost/mattermost.git
synced 2026-08-26 13:17:29 -05:00
Allows SearchPropertyValues to target master with the context mechanism
This commit is contained in:
@@ -304,7 +304,7 @@ func (h *AccessControlHook) PostGetPropertyField(rctx request.CTX, field *model.
|
||||
}
|
||||
|
||||
callerID := h.extractCallerID(rctx)
|
||||
return h.applyFieldReadAccessControl(field, callerID), nil
|
||||
return h.applyFieldReadAccessControl(rctx, field, callerID), nil
|
||||
}
|
||||
|
||||
// PostGetPropertyFields applies read access control to a list of fields.
|
||||
@@ -319,7 +319,7 @@ func (h *AccessControlHook) PostGetPropertyFields(rctx request.CTX, fields []*mo
|
||||
}
|
||||
|
||||
callerID := h.extractCallerID(rctx)
|
||||
return h.applyFieldReadAccessControlToList(fields, callerID), nil
|
||||
return h.applyFieldReadAccessControlToList(rctx, fields, callerID), nil
|
||||
}
|
||||
|
||||
// Value Pre-Hooks
|
||||
@@ -516,7 +516,7 @@ func (h *AccessControlHook) PreDeletePropertyValuesForTarget(rctx request.CTX, g
|
||||
opts.Cursor = cursor
|
||||
}
|
||||
|
||||
values, err := h.propertyService.searchPropertyValues(groupID, opts)
|
||||
values, err := h.propertyService.searchPropertyValues(rctx, groupID, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -911,7 +911,7 @@ func (h *AccessControlHook) checkValueWriteAccess(field *model.PropertyField, ca
|
||||
}
|
||||
|
||||
// getCallerValuesForField retrieves all property values for the caller on a specific field.
|
||||
func (h *AccessControlHook) getCallerValuesForField(groupID, fieldID, callerID string) ([]*model.PropertyValue, error) {
|
||||
func (h *AccessControlHook) getCallerValuesForField(rctx request.CTX, groupID, fieldID, callerID string) ([]*model.PropertyValue, error) {
|
||||
if callerID == "" {
|
||||
return []*model.PropertyValue{}, nil
|
||||
}
|
||||
@@ -936,7 +936,7 @@ func (h *AccessControlHook) getCallerValuesForField(groupID, fieldID, callerID s
|
||||
opts.Cursor = cursor
|
||||
}
|
||||
|
||||
values, err := h.propertyService.searchPropertyValues(groupID, opts)
|
||||
values, err := h.propertyService.searchPropertyValues(rctx, groupID, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get caller values for field: %w", err)
|
||||
}
|
||||
@@ -1010,8 +1010,8 @@ func (h *AccessControlHook) copyPropertyField(field *model.PropertyField) *model
|
||||
}
|
||||
|
||||
// getCallerOptionIDsForField retrieves the caller's values for a field and extracts all option IDs.
|
||||
func (h *AccessControlHook) getCallerOptionIDsForField(groupID, fieldID, callerID string, fieldType model.PropertyFieldType) (map[string]struct{}, error) {
|
||||
callerValues, err := h.getCallerValuesForField(groupID, fieldID, callerID)
|
||||
func (h *AccessControlHook) getCallerOptionIDsForField(rctx request.CTX, groupID, fieldID, callerID string, fieldType model.PropertyFieldType) (map[string]struct{}, error) {
|
||||
callerValues, err := h.getCallerValuesForField(rctx, groupID, fieldID, callerID)
|
||||
if err != nil {
|
||||
return make(map[string]struct{}), err
|
||||
}
|
||||
@@ -1039,16 +1039,16 @@ func (h *AccessControlHook) getCallerOptionIDsForField(groupID, fieldID, callerI
|
||||
// field exposes every option at or below the caller's own rank ("everything at
|
||||
// your rank and lower"), so a higher-cleared caller sees the full ladder up to
|
||||
// their level. See filterSharedOnlyRankFieldOptions.
|
||||
func (h *AccessControlHook) filterSharedOnlyFieldOptions(field *model.PropertyField, callerID string) *model.PropertyField {
|
||||
func (h *AccessControlHook) filterSharedOnlyFieldOptions(rctx request.CTX, field *model.PropertyField, callerID string) *model.PropertyField {
|
||||
if !field.Type.SupportsOptions() {
|
||||
return field
|
||||
}
|
||||
|
||||
if field.Type == model.PropertyFieldTypeRank {
|
||||
return h.filterSharedOnlyRankFieldOptions(field, callerID)
|
||||
return h.filterSharedOnlyRankFieldOptions(rctx, field, callerID)
|
||||
}
|
||||
|
||||
callerOptionIDs, err := h.getCallerOptionIDsForField(field.GroupID, field.ID, callerID, field.Type)
|
||||
callerOptionIDs, err := h.getCallerOptionIDsForField(rctx, field.GroupID, field.ID, callerID, field.Type)
|
||||
if err != nil || len(callerOptionIDs) == 0 {
|
||||
filteredField := h.copyPropertyField(field)
|
||||
filteredField.Attrs[model.PropertyFieldAttributeOptions] = []any{}
|
||||
@@ -1092,7 +1092,7 @@ func (h *AccessControlHook) filterSharedOnlyFieldOptions(field *model.PropertyFi
|
||||
// or below the caller's own rank, rather than the exact-match intersection
|
||||
// used for select/multiselect. A caller who holds no value for the field (and
|
||||
// therefore has no rank) sees no options.
|
||||
func (h *AccessControlHook) filterSharedOnlyRankFieldOptions(field *model.PropertyField, callerID string) *model.PropertyField {
|
||||
func (h *AccessControlHook) filterSharedOnlyRankFieldOptions(rctx request.CTX, field *model.PropertyField, callerID string) *model.PropertyField {
|
||||
// Bail out before building the rank map or the caller-rank store lookup when
|
||||
// there are no options to filter: an absent or malformed options array has
|
||||
// nothing to hide, so the field is returned untouched.
|
||||
@@ -1109,7 +1109,7 @@ func (h *AccessControlHook) filterSharedOnlyRankFieldOptions(field *model.Proper
|
||||
}
|
||||
|
||||
rankByID := buildOptionRankMap(field)
|
||||
callerRank, ok := h.callerRankForField(field, callerID, rankByID)
|
||||
callerRank, ok := h.callerRankForField(rctx, field, callerID, rankByID)
|
||||
if !ok {
|
||||
filteredField := h.copyPropertyField(field)
|
||||
filteredField.Attrs[model.PropertyFieldAttributeOptions] = []any{}
|
||||
@@ -1145,8 +1145,8 @@ func (h *AccessControlHook) filterSharedOnlyRankFieldOptions(field *model.Proper
|
||||
// single value per user), so the caller has at most one option; we take it.
|
||||
// ok is false when the caller has no value for the field or the option carries
|
||||
// no rank, in which case the caller has no clearance and sees nothing.
|
||||
func (h *AccessControlHook) callerRankForField(field *model.PropertyField, callerID string, rankByID map[string]int) (int, bool) {
|
||||
callerOptionIDs, err := h.getCallerOptionIDsForField(field.GroupID, field.ID, callerID, field.Type)
|
||||
func (h *AccessControlHook) callerRankForField(rctx request.CTX, field *model.PropertyField, callerID string, rankByID map[string]int) (int, bool) {
|
||||
callerOptionIDs, err := h.getCallerOptionIDsForField(rctx, field.GroupID, field.ID, callerID, field.Type)
|
||||
if err != nil || len(callerOptionIDs) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
@@ -1197,16 +1197,16 @@ func buildOptionRankMap(field *model.PropertyField) map[string]int {
|
||||
// The binary path is what protects scenarios like LDAP/SAML-synced text codenames whose
|
||||
// existence is itself controlled information: a caller who doesn't hold the same value
|
||||
// must not see the target's value through any read endpoint.
|
||||
func (h *AccessControlHook) filterSharedOnlyValue(field *model.PropertyField, value *model.PropertyValue, callerID string) *model.PropertyValue {
|
||||
func (h *AccessControlHook) filterSharedOnlyValue(rctx request.CTX, field *model.PropertyField, value *model.PropertyValue, callerID string) *model.PropertyValue {
|
||||
if field.Type == model.PropertyFieldTypeRank {
|
||||
return h.filterSharedOnlyRankValue(field, value, callerID)
|
||||
return h.filterSharedOnlyRankValue(rctx, field, value, callerID)
|
||||
}
|
||||
|
||||
if field.Type != model.PropertyFieldTypeSelect && field.Type != model.PropertyFieldTypeMultiselect {
|
||||
return h.filterSharedOnlyScalarValue(field, value, callerID)
|
||||
return h.filterSharedOnlyScalarValue(rctx, field, value, callerID)
|
||||
}
|
||||
|
||||
callerOptionIDs, err := h.getCallerOptionIDsForField(field.GroupID, field.ID, callerID, field.Type)
|
||||
callerOptionIDs, err := h.getCallerOptionIDsForField(rctx, field.GroupID, field.ID, callerID, field.Type)
|
||||
if err != nil || len(callerOptionIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -1261,9 +1261,9 @@ func (h *AccessControlHook) filterSharedOnlyValue(field *model.PropertyField, va
|
||||
// option match. A caller who holds no value of their own (and therefore has no
|
||||
// rank) sees nothing. A rank field is select-shaped, so the target has at most
|
||||
// one option.
|
||||
func (h *AccessControlHook) filterSharedOnlyRankValue(field *model.PropertyField, value *model.PropertyValue, callerID string) *model.PropertyValue {
|
||||
func (h *AccessControlHook) filterSharedOnlyRankValue(rctx request.CTX, field *model.PropertyField, value *model.PropertyValue, callerID string) *model.PropertyValue {
|
||||
rankByID := buildOptionRankMap(field)
|
||||
callerRank, ok := h.callerRankForField(field, callerID, rankByID)
|
||||
callerRank, ok := h.callerRankForField(rctx, field, callerID, rankByID)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -1319,12 +1319,12 @@ func (h *AccessControlHook) clampRankValueToRank(value *model.PropertyValue, ran
|
||||
// returns the value as-is if the caller's own stored value for the same field equals
|
||||
// the target's value, otherwise nil. Caller and target may legitimately store nothing,
|
||||
// in which case the value is hidden.
|
||||
func (h *AccessControlHook) filterSharedOnlyScalarValue(field *model.PropertyField, value *model.PropertyValue, callerID string) *model.PropertyValue {
|
||||
func (h *AccessControlHook) filterSharedOnlyScalarValue(rctx request.CTX, field *model.PropertyField, value *model.PropertyValue, callerID string) *model.PropertyValue {
|
||||
if value == nil || len(value.Value) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
callerValues, err := h.getCallerValuesForField(field.GroupID, field.ID, callerID)
|
||||
callerValues, err := h.getCallerValuesForField(rctx, field.GroupID, field.ID, callerID)
|
||||
if err != nil || len(callerValues) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -1344,7 +1344,7 @@ func (h *AccessControlHook) filterSharedOnlyScalarValue(field *model.PropertyFie
|
||||
// - Any access mode when the caller is the field's source plugin: returned as-is
|
||||
// - Shared-only fields: returned with options filtered using filterSharedOnlyFieldOptions
|
||||
// - Source-only or unknown access modes: returned with empty options (secure default)
|
||||
func (h *AccessControlHook) applyFieldReadAccessControl(field *model.PropertyField, callerID string) *model.PropertyField {
|
||||
func (h *AccessControlHook) applyFieldReadAccessControl(rctx request.CTX, field *model.PropertyField, callerID string) *model.PropertyField {
|
||||
if h.hasUnrestrictedFieldReadAccess(field, callerID) {
|
||||
return field
|
||||
}
|
||||
@@ -1352,7 +1352,7 @@ func (h *AccessControlHook) applyFieldReadAccessControl(field *model.PropertyFie
|
||||
accessMode := h.getAccessMode(field)
|
||||
|
||||
if accessMode == model.PropertyAccessModeSharedOnly {
|
||||
return h.filterSharedOnlyFieldOptions(field, callerID)
|
||||
return h.filterSharedOnlyFieldOptions(rctx, field, callerID)
|
||||
}
|
||||
|
||||
// Source-only or unknown: return with empty options (secure default)
|
||||
@@ -1364,14 +1364,14 @@ func (h *AccessControlHook) applyFieldReadAccessControl(field *model.PropertyFie
|
||||
}
|
||||
|
||||
// applyFieldReadAccessControlToList applies read access control to a list of fields.
|
||||
func (h *AccessControlHook) applyFieldReadAccessControlToList(fields []*model.PropertyField, callerID string) []*model.PropertyField {
|
||||
func (h *AccessControlHook) applyFieldReadAccessControlToList(rctx request.CTX, fields []*model.PropertyField, callerID string) []*model.PropertyField {
|
||||
if len(fields) == 0 {
|
||||
return fields
|
||||
}
|
||||
|
||||
filtered := make([]*model.PropertyField, 0, len(fields))
|
||||
for _, field := range fields {
|
||||
filtered = append(filtered, h.applyFieldReadAccessControl(field, callerID))
|
||||
filtered = append(filtered, h.applyFieldReadAccessControl(rctx, field, callerID))
|
||||
}
|
||||
|
||||
return filtered
|
||||
@@ -1434,7 +1434,7 @@ func (h *AccessControlHook) applyValueReadAccessControl(rctx request.CTX, values
|
||||
if h.hasUnrestrictedFieldReadAccess(field, callerID) {
|
||||
filtered = append(filtered, value)
|
||||
} else if accessMode == model.PropertyAccessModeSharedOnly {
|
||||
filteredValue := h.filterSharedOnlyValue(field, value, callerID)
|
||||
filteredValue := h.filterSharedOnlyValue(rctx, field, value, callerID)
|
||||
if filteredValue != nil {
|
||||
filtered = append(filtered, filteredValue)
|
||||
}
|
||||
|
||||
@@ -79,11 +79,11 @@ func (ps *PropertyService) getPropertyValues(groupID string, ids []string) ([]*m
|
||||
return ps.valueStore.GetMany(groupID, ids)
|
||||
}
|
||||
|
||||
func (ps *PropertyService) searchPropertyValues(groupID string, opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error) {
|
||||
func (ps *PropertyService) searchPropertyValues(rctx request.CTX, groupID string, opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error) {
|
||||
// groupID is part of the search method signature to
|
||||
// incentivize the use of the database indexes in searches
|
||||
opts.GroupID = groupID
|
||||
return ps.valueStore.SearchPropertyValues(opts)
|
||||
return ps.valueStore.SearchPropertyValues(rctx, opts)
|
||||
}
|
||||
|
||||
func (ps *PropertyService) updatePropertyValue(rctx request.CTX, groupID string, value *model.PropertyValue) (*model.PropertyValue, error) {
|
||||
@@ -196,7 +196,7 @@ func (ps *PropertyService) GetPropertyValues(rctx request.CTX, groupID string, i
|
||||
}
|
||||
|
||||
func (ps *PropertyService) SearchPropertyValues(rctx request.CTX, groupID string, opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error) {
|
||||
values, err := ps.searchPropertyValues(groupID, opts)
|
||||
values, err := ps.searchPropertyValues(rctx, groupID, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("SearchPropertyValues: %w", err)
|
||||
}
|
||||
|
||||
@@ -10980,11 +10980,11 @@ func (s *RetryLayerPropertyValueStore) GetMany(groupID string, ids []string) ([]
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerPropertyValueStore) SearchPropertyValues(opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error) {
|
||||
func (s *RetryLayerPropertyValueStore) SearchPropertyValues(rctx request.CTX, opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.PropertyValueStore.SearchPropertyValues(opts)
|
||||
result, err := s.PropertyValueStore.SearchPropertyValues(rctx, opts)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -11,6 +11,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"
|
||||
)
|
||||
|
||||
@@ -134,7 +135,7 @@ func (s *SqlPropertyValueStore) GetMany(groupID string, ids []string) ([]*model.
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func (s *SqlPropertyValueStore) SearchPropertyValues(opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error) {
|
||||
func (s *SqlPropertyValueStore) SearchPropertyValues(rctx request.CTX, opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error) {
|
||||
if err := opts.IsValid(); err != nil {
|
||||
return nil, fmt.Errorf("opts is invalid: %w", err)
|
||||
}
|
||||
@@ -204,7 +205,7 @@ func (s *SqlPropertyValueStore) SearchPropertyValues(opts model.PropertyValueSea
|
||||
}
|
||||
|
||||
var values []*model.PropertyValue
|
||||
if err := s.GetReplica().SelectBuilder(&values, builder); err != nil {
|
||||
if err := s.DBXFromContext(rctx.Context()).SelectBuilder(&values, builder); err != nil {
|
||||
return nil, errors.Wrap(err, "property_value_search_query")
|
||||
}
|
||||
|
||||
|
||||
@@ -1209,7 +1209,7 @@ type PropertyValueStore interface {
|
||||
CreateMany(values []*model.PropertyValue) ([]*model.PropertyValue, error)
|
||||
Get(groupID, id string) (*model.PropertyValue, error)
|
||||
GetMany(groupID string, ids []string) ([]*model.PropertyValue, error)
|
||||
SearchPropertyValues(opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error)
|
||||
SearchPropertyValues(rctx request.CTX, opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error)
|
||||
Update(groupID string, values []*model.PropertyValue) ([]*model.PropertyValue, error)
|
||||
Upsert(values []*model.PropertyValue) ([]*model.PropertyValue, error)
|
||||
Delete(groupID string, id string) error
|
||||
|
||||
@@ -6,6 +6,7 @@ package mocks
|
||||
|
||||
import (
|
||||
model "github.com/mattermost/mattermost/server/public/model"
|
||||
request "github.com/mattermost/mattermost/server/public/shared/request"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
@@ -188,9 +189,9 @@ func (_m *PropertyValueStore) GetMany(groupID string, ids []string) ([]*model.Pr
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// SearchPropertyValues provides a mock function with given fields: opts
|
||||
func (_m *PropertyValueStore) SearchPropertyValues(opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error) {
|
||||
ret := _m.Called(opts)
|
||||
// SearchPropertyValues provides a mock function with given fields: rctx, opts
|
||||
func (_m *PropertyValueStore) SearchPropertyValues(rctx request.CTX, opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error) {
|
||||
ret := _m.Called(rctx, opts)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SearchPropertyValues")
|
||||
@@ -198,19 +199,19 @@ func (_m *PropertyValueStore) SearchPropertyValues(opts model.PropertyValueSearc
|
||||
|
||||
var r0 []*model.PropertyValue
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(model.PropertyValueSearchOpts) ([]*model.PropertyValue, error)); ok {
|
||||
return rf(opts)
|
||||
if rf, ok := ret.Get(0).(func(request.CTX, model.PropertyValueSearchOpts) ([]*model.PropertyValue, error)); ok {
|
||||
return rf(rctx, opts)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(model.PropertyValueSearchOpts) []*model.PropertyValue); ok {
|
||||
r0 = rf(opts)
|
||||
if rf, ok := ret.Get(0).(func(request.CTX, model.PropertyValueSearchOpts) []*model.PropertyValue); ok {
|
||||
r0 = rf(rctx, opts)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.PropertyValue)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(model.PropertyValueSearchOpts) error); ok {
|
||||
r1 = rf(opts)
|
||||
if rf, ok := ret.Get(1).(func(request.CTX, model.PropertyValueSearchOpts) error); ok {
|
||||
r1 = rf(rctx, opts)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ func testCreatePropertyValue(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
})
|
||||
}
|
||||
|
||||
func testCreateManyPropertyValues(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
func testCreateManyPropertyValues(t *testing.T, rctx request.CTX, ss store.Store) {
|
||||
t.Run("should return nil when given empty slice", func(t *testing.T) {
|
||||
values, err := ss.PropertyValue().CreateMany([]*model.PropertyValue{})
|
||||
require.NoError(t, err)
|
||||
@@ -126,7 +126,7 @@ func testCreateManyPropertyValues(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
require.ErrorContains(t, err, "model.property_value.is_valid.app_error")
|
||||
|
||||
// Verify no values were created
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
TargetIDs: []string{validValue.TargetID},
|
||||
PerPage: 10,
|
||||
})
|
||||
@@ -248,7 +248,7 @@ func testCreateManyPropertyValues(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
require.Zero(t, values)
|
||||
|
||||
// Verify the unique value was not created due to transaction rollback
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
TargetIDs: []string{value3.TargetID},
|
||||
PerPage: 10,
|
||||
})
|
||||
@@ -846,7 +846,7 @@ func testUpdatePropertyValue(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
})
|
||||
}
|
||||
|
||||
func testUpsertPropertyValue(t *testing.T, _ request.CTX, ss store.Store, s SqlStore) {
|
||||
func testUpsertPropertyValue(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) {
|
||||
t.Run("should fail if the property value is not valid", func(t *testing.T) {
|
||||
value := &model.PropertyValue{
|
||||
TargetID: "",
|
||||
@@ -1000,7 +1000,7 @@ func testUpsertPropertyValue(t *testing.T, _ request.CTX, ss store.Store, s SqlS
|
||||
require.Equal(t, originalValue.UpdateAt, retrieved.UpdateAt)
|
||||
|
||||
// Verify the invalid value was not inserted
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
TargetIDs: []string{invalidValue.TargetID},
|
||||
PerPage: 10,
|
||||
})
|
||||
@@ -1215,7 +1215,7 @@ func testDeletePropertyValue(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
})
|
||||
}
|
||||
|
||||
func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s SqlStore) {
|
||||
func testSearchPropertyValues(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) {
|
||||
groupID := model.NewId()
|
||||
targetID := model.NewId()
|
||||
fieldID := model.NewId()
|
||||
@@ -1408,7 +1408,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(tc.opts)
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(rctx, tc.opts)
|
||||
if tc.expectedError {
|
||||
require.Error(t, err)
|
||||
return
|
||||
@@ -1426,7 +1426,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
t.Run("null columns, before createdBy and updatedBy migrations", func(t *testing.T) {
|
||||
nullGroupID, _, _, nullValueID := insertPropertyValueWithNullColumns(t, ss, s)
|
||||
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: nullGroupID,
|
||||
PerPage: 10,
|
||||
})
|
||||
@@ -1481,7 +1481,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
t.Run("SinceUpdateAt filters correctly by UpdateAt", func(t *testing.T) {
|
||||
// `>=` semantics: value1 is included at the boundary,
|
||||
// plus value3 and the post-update value2.
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: groupID,
|
||||
SinceUpdateAt: value1.UpdateAt,
|
||||
PerPage: 10,
|
||||
@@ -1499,7 +1499,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
t.Run("SinceUpdateAt with boundary condition", func(t *testing.T) {
|
||||
// `value3.UpdateAt - 1` keeps value3 in the window and value2's
|
||||
// post-Update timestamp is even later, so both are returned.
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: groupID,
|
||||
SinceUpdateAt: value3.UpdateAt - 1,
|
||||
PerPage: 10,
|
||||
@@ -1517,7 +1517,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
t.Run("SinceUpdateAt at the most recent update returns just that row", func(t *testing.T) {
|
||||
// `>=` semantics: querying at the highest UpdateAt in the
|
||||
// group returns the row at exactly that timestamp.
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: groupID,
|
||||
SinceUpdateAt: updatedValue2.UpdateAt,
|
||||
PerPage: 10,
|
||||
@@ -1528,7 +1528,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
})
|
||||
|
||||
t.Run("SinceUpdateAt with very recent timestamp", func(t *testing.T) {
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: groupID,
|
||||
SinceUpdateAt: model.GetMillis(),
|
||||
PerPage: 10,
|
||||
@@ -1566,7 +1566,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
require.Equal(t, tieUpdateAt, updated[1].UpdateAt)
|
||||
require.Equal(t, tieUpdateAt, updated[2].UpdateAt)
|
||||
|
||||
page1, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
page1, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: tieGroup,
|
||||
SinceUpdateAt: tieUpdateAt,
|
||||
PerPage: 2,
|
||||
@@ -1575,7 +1575,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
require.Len(t, page1, 2, "boundary row + one more must come back on the first page")
|
||||
|
||||
last := page1[len(page1)-1]
|
||||
page2, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
page2, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: tieGroup,
|
||||
SinceUpdateAt: tieUpdateAt,
|
||||
Cursor: model.PropertyValueSearchCursor{
|
||||
@@ -1649,7 +1649,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
}
|
||||
|
||||
t.Run("orders by UpdateAt ASC, Id ASC", func(t *testing.T) {
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: groupID,
|
||||
SinceUpdateAt: value1.UpdateAt,
|
||||
PerPage: 10,
|
||||
@@ -1664,7 +1664,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
t.Run("auto-includes tombstones", func(t *testing.T) {
|
||||
require.NoError(t, ss.PropertyValue().Delete("", value3.ID))
|
||||
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
results, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: groupID,
|
||||
SinceUpdateAt: value1.UpdateAt,
|
||||
PerPage: 10,
|
||||
@@ -1685,7 +1685,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
t.Run("paginates with cursor UpdateAt", func(t *testing.T) {
|
||||
// `>=` semantics: first page is value1 (the boundary row),
|
||||
// cursored to value3, then value2.
|
||||
first, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
first, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: groupID,
|
||||
SinceUpdateAt: value1.UpdateAt,
|
||||
PerPage: 1,
|
||||
@@ -1693,7 +1693,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{value1.ID}, idsOf(first))
|
||||
|
||||
second, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
second, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: groupID,
|
||||
SinceUpdateAt: value1.UpdateAt,
|
||||
Cursor: model.PropertyValueSearchCursor{
|
||||
@@ -1705,7 +1705,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{value3.ID}, idsOf(second))
|
||||
|
||||
third, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
third, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: groupID,
|
||||
SinceUpdateAt: value1.UpdateAt,
|
||||
Cursor: model.PropertyValueSearchCursor{
|
||||
@@ -1719,7 +1719,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
})
|
||||
|
||||
t.Run("directory mode rejects cursor_update_at", func(t *testing.T) {
|
||||
_, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
_, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: groupID,
|
||||
Cursor: model.PropertyValueSearchCursor{
|
||||
PropertyValueID: value1.ID,
|
||||
@@ -1731,7 +1731,7 @@ func testSearchPropertyValues(t *testing.T, _ request.CTX, ss store.Store, s Sql
|
||||
})
|
||||
|
||||
t.Run("delta mode rejects cursor_create_at", func(t *testing.T) {
|
||||
_, err := ss.PropertyValue().SearchPropertyValues(model.PropertyValueSearchOpts{
|
||||
_, err := ss.PropertyValue().SearchPropertyValues(rctx, model.PropertyValueSearchOpts{
|
||||
GroupID: groupID,
|
||||
SinceUpdateAt: value1.UpdateAt,
|
||||
Cursor: model.PropertyValueSearchCursor{
|
||||
@@ -1795,7 +1795,7 @@ func testCreatePropertyValueWithArray(t *testing.T, _ request.CTX, ss store.Stor
|
||||
})
|
||||
}
|
||||
|
||||
func testDeleteForField(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
func testDeleteForField(t *testing.T, rctx request.CTX, ss store.Store) {
|
||||
t.Run("should delete values with matching fieldID and groupID", func(t *testing.T) {
|
||||
fieldID := model.NewId()
|
||||
groupID := model.NewId()
|
||||
@@ -1927,7 +1927,7 @@ func testDeleteForField(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
PerPage: 10,
|
||||
}
|
||||
|
||||
values, err := ss.PropertyValue().SearchPropertyValues(opts)
|
||||
values, err := ss.PropertyValue().SearchPropertyValues(rctx, opts)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Find our two values within the results
|
||||
|
||||
@@ -8739,10 +8739,10 @@ func (s *TimerLayerPropertyValueStore) GetMany(groupID string, ids []string) ([]
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerPropertyValueStore) SearchPropertyValues(opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error) {
|
||||
func (s *TimerLayerPropertyValueStore) SearchPropertyValues(rctx request.CTX, opts model.PropertyValueSearchOpts) ([]*model.PropertyValue, error) {
|
||||
start := time.Now()
|
||||
|
||||
result, err := s.PropertyValueStore.SearchPropertyValues(opts)
|
||||
result, err := s.PropertyValueStore.SearchPropertyValues(rctx, opts)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
|
||||
Reference in New Issue
Block a user