From e9ab4e32b147fafac9a1302ae48baf34c6f5ca0f Mon Sep 17 00:00:00 2001 From: or-else Date: Mon, 20 Mar 2023 09:24:19 -0700 Subject: [PATCH] alow root user to find suspended topics and accounts --- server/db/adapter.go | 8 ++++---- server/db/mongodb/adapter.go | 19 ++++++++++--------- server/db/mysql/adapter.go | 20 ++++++++++++++------ server/db/rethinkdb/adapter.go | 20 ++++++++++++-------- server/store/mock_store/mock_store.go | 8 ++++---- server/store/store.go | 8 ++++---- server/topic.go | 3 +-- 7 files changed, 49 insertions(+), 37 deletions(-) diff --git a/server/db/adapter.go b/server/db/adapter.go index 3462d79d9..2a036b1bb 100644 --- a/server/db/adapter.go +++ b/server/db/adapter.go @@ -141,10 +141,10 @@ type Adapter interface { // Search - // FindUsers searches for new contacts given a list of tags - FindUsers(user t.Uid, req [][]string, opt []string) ([]t.Subscription, error) - // FindTopics searches for group topics given a list of tags - FindTopics(req [][]string, opt []string) ([]t.Subscription, error) + // FindUsers searches for new contacts given a list of tags. + FindUsers(user t.Uid, req [][]string, opt []string, activeOnly bool) ([]t.Subscription, error) + // FindTopics searches for group topics given a list of tags. + FindTopics(req [][]string, opt []string, activeOnly bool) ([]t.Subscription, error) // Messages diff --git a/server/db/mongodb/adapter.go b/server/db/mongodb/adapter.go index 4aa2c27b6..c0405add8 100644 --- a/server/db/mongodb/adapter.go +++ b/server/db/mongodb/adapter.go @@ -2054,7 +2054,7 @@ func (a *adapter) subsDelete(ctx context.Context, filter b.M, hard bool) error { } // Search -func (a *adapter) getFindPipeline(req [][]string, opt []string) (map[string]struct{}, b.A) { +func (a *adapter) getFindPipeline(req [][]string, opt []string, activeOnly bool) (map[string]struct{}, b.A) { allReq := t.FlattenDoubleSlice(req) index := make(map[string]struct{}) var allTags []interface{} @@ -2063,11 +2063,12 @@ func (a *adapter) getFindPipeline(req [][]string, opt []string) (map[string]stru index[tag] = struct{}{} } + matchOn := b.M{"tags": b.M{"$in": allTags}} + if activeOnly { + matchOn["state"] = b.M{"$eq": t.StateOK} + } pipeline := b.A{ - b.M{"$match": b.M{ - "tags": b.M{"$in": allTags}, - "state": b.M{"$ne": t.StateDeleted}, - }}, + b.M{"$match": matchOn}, b.M{"$project": b.M{"_id": 1, "access": 1, "createdat": 1, "updatedat": 1, "public": 1, "trusted": 1, "tags": 1}}, @@ -2104,8 +2105,8 @@ func (a *adapter) getFindPipeline(req [][]string, opt []string) (map[string]stru } // FindUsers searches for new contacts given a list of tags -func (a *adapter) FindUsers(uid t.Uid, req [][]string, opt []string) ([]t.Subscription, error) { - index, pipeline := a.getFindPipeline(req, opt) +func (a *adapter) FindUsers(uid t.Uid, req [][]string, opt []string, activeOnly bool) ([]t.Subscription, error) { + index, pipeline := a.getFindPipeline(req, opt, activeOnly) cur, err := a.db.Collection("users").Aggregate(a.ctx, pipeline) if err != nil { return nil, err @@ -2143,8 +2144,8 @@ func (a *adapter) FindUsers(uid t.Uid, req [][]string, opt []string) ([]t.Subscr } // FindTopics searches for group topics given a list of tags -func (a *adapter) FindTopics(req [][]string, opt []string) ([]t.Subscription, error) { - index, pipeline := a.getFindPipeline(req, opt) +func (a *adapter) FindTopics(req [][]string, opt []string, activeOnly bool) ([]t.Subscription, error) { + index, pipeline := a.getFindPipeline(req, opt, activeOnly) cur, err := a.db.Collection("topics").Aggregate(a.ctx, pipeline) if err != nil { return nil, err diff --git a/server/db/mysql/adapter.go b/server/db/mysql/adapter.go index ae4f4e1da..1700e1973 100644 --- a/server/db/mysql/adapter.go +++ b/server/db/mysql/adapter.go @@ -2341,10 +2341,14 @@ func (a *adapter) SubsDelForUser(user t.Uid, hard bool) error { // Returns a list of users who match given tags, such as "email:jdoe@example.com" or "tel:+18003287448". // Searching the 'users.Tags' for the given tags using respective index. -func (a *adapter) FindUsers(uid t.Uid, req [][]string, opt []string) ([]t.Subscription, error) { +func (a *adapter) FindUsers(uid t.Uid, req [][]string, opt []string, activeOnly bool) ([]t.Subscription, error) { index := make(map[string]struct{}) var args []interface{} - args = append(args, t.StateOK) + stateConstraint := "" + if activeOnly { + args = append(args, t.StateOK) + stateConstraint = "u.state=? AND " + } allReq := t.FlattenDoubleSlice(req) for _, tag := range append(allReq, opt...) { args = append(args, tag) @@ -2353,7 +2357,7 @@ func (a *adapter) FindUsers(uid t.Uid, req [][]string, opt []string) ([]t.Subscr query := "SELECT u.id,u.createdat,u.updatedat,u.access,u.public,u.trusted,u.tags,COUNT(*) AS matches " + "FROM users AS u LEFT JOIN usertags AS t ON t.userid=u.id " + - "WHERE u.state=? AND t.tag IN (?" + strings.Repeat(",?", len(allReq)+len(opt)-1) + ") " + + "WHERE " + stateConstraint + "t.tag IN (?" + strings.Repeat(",?", len(allReq)+len(opt)-1) + ") " + "GROUP BY u.id,u.createdat,u.updatedat,u.access,u.public,u.trusted,u.tags " if len(allReq) > 0 { query += "HAVING" @@ -2429,10 +2433,14 @@ func (a *adapter) FindUsers(uid t.Uid, req [][]string, opt []string) ([]t.Subscr // Returns a list of topics with matching tags. // Searching the 'topics.Tags' for the given tags using respective index. -func (a *adapter) FindTopics(req [][]string, opt []string) ([]t.Subscription, error) { +func (a *adapter) FindTopics(req [][]string, opt []string, activeOnly bool) ([]t.Subscription, error) { index := make(map[string]struct{}) var args []interface{} - args = append(args, t.StateOK) + stateConstraint := "" + if activeOnly { + args = append(args, t.StateOK) + stateConstraint = "u.state=? AND " + } var allReq []string for _, el := range req { allReq = append(allReq, el...) @@ -2444,7 +2452,7 @@ func (a *adapter) FindTopics(req [][]string, opt []string) ([]t.Subscription, er query := "SELECT t.name AS topic,t.createdat,t.updatedat,t.usebt,t.access,t.public,t.trusted,t.tags,COUNT(*) AS matches " + "FROM topics AS t LEFT JOIN topictags AS tt ON t.name=tt.topic " + - "WHERE t.state=? AND tt.tag IN (?" + strings.Repeat(",?", len(allReq)+len(opt)-1) + ") " + + "WHERE " + stateConstraint + "tt.tag IN (?" + strings.Repeat(",?", len(allReq)+len(opt)-1) + ") " + "GROUP BY t.name,t.createdat,t.updatedat,t.usebt,t.access,t.public,t.trusted,t.tags " if len(allReq) > 0 { query += "HAVING" diff --git a/server/db/rethinkdb/adapter.go b/server/db/rethinkdb/adapter.go index 6429856fd..31dc3ee6a 100644 --- a/server/db/rethinkdb/adapter.go +++ b/server/db/rethinkdb/adapter.go @@ -1863,7 +1863,7 @@ func (a *adapter) subsDelForUser(user t.Uid, hard bool) error { // FindUsers returns a list of users who match given tags, such as "email:jdoe@example.com" or "tel:+18003287448". // Searching the 'users.Tags' for the given tags using respective index. -func (a *adapter) FindUsers(uid t.Uid, req [][]string, opt []string) ([]t.Subscription, error) { +func (a *adapter) FindUsers(uid t.Uid, req [][]string, opt []string, activeOnly bool) ([]t.Subscription, error) { index := make(map[string]struct{}) allReq := t.FlattenDoubleSlice(req) var allTags []interface{} @@ -1888,9 +1888,11 @@ func (a *adapter) FindUsers(uid t.Uid, req [][]string, opt []string) ([]t.Subscr // Get users matched by tags, sort by number of matches from high to low. query := rdb.DB(a.dbName). Table("users"). - GetAllByIndex("Tags", allTags...). - Filter(rdb.Row.Field("State").Eq(t.StateOK)). - Pluck("Id", "Access", "CreatedAt", "UpdatedAt", "Public", "Trusted", "Tags"). + GetAllByIndex("Tags", allTags...) + if activeOnly { + query = query.Filter(rdb.Row.Field("State").Eq(t.StateOK)) + } + query = query.Pluck("Id", "Access", "CreatedAt", "UpdatedAt", "Public", "Trusted", "Tags"). Group("Id"). Ungroup(). Map(func(row rdb.Term) rdb.Term { @@ -1948,7 +1950,7 @@ func (a *adapter) FindUsers(uid t.Uid, req [][]string, opt []string) ([]t.Subscr // FindTopics returns a list of topics with matching tags. // Searching the 'topics.Tags' for the given tags using respective index. -func (a *adapter) FindTopics(req [][]string, opt []string) ([]t.Subscription, error) { +func (a *adapter) FindTopics(req [][]string, opt []string, activeOnly bool) ([]t.Subscription, error) { index := make(map[string]struct{}) var allReq []string for _, el := range req { @@ -1961,9 +1963,11 @@ func (a *adapter) FindTopics(req [][]string, opt []string) ([]t.Subscription, er } query := rdb.DB(a.dbName). Table("topics"). - GetAllByIndex("Tags", allTags...). - Filter(rdb.Row.Field("State").Eq(t.StateOK)). - Pluck("Id", "Access", "CreatedAt", "UpdatedAt", "UseBt", "Public", "Trusted", "Tags"). + GetAllByIndex("Tags", allTags...) + if activeOnly { + query = query.Filter(rdb.Row.Field("State").Eq(t.StateOK)) + } + query = query.Pluck("Id", "Access", "CreatedAt", "UpdatedAt", "UseBt", "Public", "Trusted", "Tags"). Group("Id"). Ungroup(). Map(func(row rdb.Term) rdb.Term { diff --git a/server/store/mock_store/mock_store.go b/server/store/mock_store/mock_store.go index 2ff2af1c4..14945d18d 100644 --- a/server/store/mock_store/mock_store.go +++ b/server/store/mock_store/mock_store.go @@ -415,18 +415,18 @@ func (mr *MockUsersPersistenceInterfaceMockRecorder) FailCred(id, method interfa } // FindSubs mocks base method. -func (m *MockUsersPersistenceInterface) FindSubs(id types.Uid, required [][]string, optional []string) ([]types.Subscription, error) { +func (m *MockUsersPersistenceInterface) FindSubs(id types.Uid, required [][]string, optional []string, activeOnly bool) ([]types.Subscription, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FindSubs", id, required, optional) + ret := m.ctrl.Call(m, "FindSubs", id, required, optional, activeOnly) ret0, _ := ret[0].([]types.Subscription) ret1, _ := ret[1].(error) return ret0, ret1 } // FindSubs indicates an expected call of FindSubs. -func (mr *MockUsersPersistenceInterfaceMockRecorder) FindSubs(id, required, optional interface{}) *gomock.Call { +func (mr *MockUsersPersistenceInterfaceMockRecorder) FindSubs(id, required, optional, activeOnly interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindSubs", reflect.TypeOf((*MockUsersPersistenceInterface)(nil).FindSubs), id, required, optional) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindSubs", reflect.TypeOf((*MockUsersPersistenceInterface)(nil).FindSubs), id, required, optional, activeOnly) } // Get mocks base method. diff --git a/server/store/store.go b/server/store/store.go index b0aab5caf..114764c65 100644 --- a/server/store/store.go +++ b/server/store/store.go @@ -266,7 +266,7 @@ type UsersPersistenceInterface interface { UpdateTags(uid types.Uid, add, remove, reset []string) ([]string, error) UpdateState(uid types.Uid, state types.ObjState) error GetSubs(id types.Uid) ([]types.Subscription, error) - FindSubs(id types.Uid, required [][]string, optional []string) ([]types.Subscription, error) + FindSubs(id types.Uid, required [][]string, optional []string, activeOnly bool) ([]types.Subscription, error) GetTopics(id types.Uid, opts *types.QueryOpt) ([]types.Subscription, error) GetTopicsAny(id types.Uid, opts *types.QueryOpt) ([]types.Subscription, error) GetOwnTopics(id types.Uid) ([]string, error) @@ -424,12 +424,12 @@ func (usersMapper) GetSubs(id types.Uid) ([]types.Subscription, error) { // `required` specifies an AND of ORs for required terms: // at least one element of every sublist in `required` must be present in the object's tags list. // `optional` specifies a list of optional terms. -func (usersMapper) FindSubs(id types.Uid, required [][]string, optional []string) ([]types.Subscription, error) { - usubs, err := adp.FindUsers(id, required, optional) +func (usersMapper) FindSubs(id types.Uid, required [][]string, optional []string, activeOnly bool) ([]types.Subscription, error) { + usubs, err := adp.FindUsers(id, required, optional, activeOnly) if err != nil { return nil, err } - tsubs, err := adp.FindTopics(required, optional) + tsubs, err := adp.FindTopics(required, optional, activeOnly) if err != nil { return nil, err } diff --git a/server/topic.go b/server/topic.go index 48355e398..44609b977 100644 --- a/server/topic.go +++ b/server/topic.go @@ -2419,8 +2419,7 @@ func (t *Topic) replyGetSub(sess *Session, asUid types.Uid, authLevel auth.Level return errors.New("attempt to search by restricted tags") } - // TODO: allow root to find suspended users and topics. - subs, err = store.Users.FindSubs(asUid, req, opt) + subs, err = store.Users.FindSubs(asUid, req, opt, sess.authLvl == auth.LevelRoot) if err != nil { sess.queueOut(decodeStoreErrorExplicitTs(err, id, msg.Original, now, incomingReqTs, nil)) return err