fix: sync contact phone privacy disclosure
This commit is contained in:
parent
0e2fcdf9c8
commit
e1a95c7318
19 changed files with 789 additions and 50 deletions
|
|
@ -419,6 +419,7 @@ func (f *fakeDialogReadModelCache) flushCount() int {
|
|||
type fakePrivacyReadModelCache struct {
|
||||
mu sync.Mutex
|
||||
ids []int64
|
||||
warmed []int64
|
||||
flushes int
|
||||
}
|
||||
|
||||
|
|
@ -428,6 +429,13 @@ func (f *fakePrivacyReadModelCache) InvalidateOwners(ids ...int64) {
|
|||
f.ids = append(f.ids, ids...)
|
||||
}
|
||||
|
||||
func (f *fakePrivacyReadModelCache) WarmOwners(_ context.Context, ids ...int64) error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.warmed = append(f.warmed, ids...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakePrivacyReadModelCache) FlushReadModelCache() {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
|
@ -440,6 +448,12 @@ func (f *fakePrivacyReadModelCache) idsSnapshot() []int64 {
|
|||
return append([]int64(nil), f.ids...)
|
||||
}
|
||||
|
||||
func (f *fakePrivacyReadModelCache) warmedSnapshot() []int64 {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return append([]int64(nil), f.warmed...)
|
||||
}
|
||||
|
||||
func (f *fakePrivacyReadModelCache) flushCount() int {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
|
@ -509,6 +523,9 @@ func TestReadModelChangeListenerInvalidatesAccountCaches(t *testing.T) {
|
|||
if len(privacy.ids) != 1 || privacy.ids[0] != 21 {
|
||||
t.Fatalf("privacy invalidations = %v, want [21]", privacy.ids)
|
||||
}
|
||||
if warmed := privacy.warmedSnapshot(); len(warmed) != 1 || warmed[0] != 21 {
|
||||
t.Fatalf("privacy warms = %v, want [21]", warmed)
|
||||
}
|
||||
|
||||
listener.handlePayload(`{"model":"dialog_light","owner_user_id":22,"peer_type":"user","peer_id":32,"version":4}`)
|
||||
if len(dialogs.owners) != 1 || dialogs.owners[0] != 22 || dialogs.keys[0] != (domain.Peer{Type: domain.PeerTypeUser, ID: 32}) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package postgres
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"go.uber.org/zap"
|
||||
|
|
@ -13,6 +14,8 @@ import (
|
|||
|
||||
const readModelChangeNotifyChannel = "telesrv_read_model_changed"
|
||||
|
||||
const privacyReadModelWarmTimeout = 5 * time.Second
|
||||
|
||||
// ReadModelCacheSet 是 read_model_versions 通知可失效的进程内投影缓存集合。
|
||||
// 后续新增 read model 时,把缓存接到这里即可复用同一条 LISTEN 连接。
|
||||
type ReadModelCacheSet struct {
|
||||
|
|
@ -90,6 +93,14 @@ type PrivacyReadModelCache interface {
|
|||
FlushReadModelCache()
|
||||
}
|
||||
|
||||
// PrivacyReadModelWarmer lets the low-frequency change stream rebuild owner
|
||||
// snapshots after invalidation, so the next user projection does not own a
|
||||
// synchronous database miss. It is optional; caches without it remain
|
||||
// cache-aside and only receive invalidation.
|
||||
type PrivacyReadModelWarmer interface {
|
||||
WarmOwners(context.Context, ...int64) error
|
||||
}
|
||||
|
||||
type ProfilePhotoReadModelCache interface {
|
||||
InvalidateOwner(domain.PeerType, int64)
|
||||
FlushReadModelCache()
|
||||
|
|
@ -393,6 +404,15 @@ func (l *ReadModelChangeListener) handlePayload(payload string) {
|
|||
l.caches.RPCProjections.InvalidateRPCProjectionReadModelForUser(evt.OwnerUserID)
|
||||
l.caches.RPCProjections.InvalidateRPCProjectionReadModelForViewer(evt.OwnerUserID)
|
||||
}
|
||||
if warmer, ok := l.caches.Privacy.(PrivacyReadModelWarmer); ok && evt.OwnerUserID != 0 {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), privacyReadModelWarmTimeout)
|
||||
err := warmer.WarmOwners(ctx, evt.OwnerUserID)
|
||||
cancel()
|
||||
if err != nil {
|
||||
l.log.Warn("warm privacy read model after change",
|
||||
zap.Int64("owner_user_id", evt.OwnerUserID), zap.Error(err))
|
||||
}
|
||||
}
|
||||
case "dialog_light":
|
||||
if peerType, ok := readModelPeerType(evt.PeerType); ok && evt.OwnerUserID != 0 && evt.PeerID != 0 {
|
||||
peer := domain.Peer{Type: peerType, ID: evt.PeerID}
|
||||
|
|
|
|||
|
|
@ -1126,7 +1126,7 @@ WHERE sv.owner_peer_type = $1
|
|||
OR lower(COALESCE(c.contact_last_name, u.last_name)) LIKE $7 ESCAPE '\'
|
||||
OR lower(trim(COALESCE(NULLIF(c.contact_first_name, ''), u.first_name) || ' ' || COALESCE(c.contact_last_name, u.last_name))) LIKE $7 ESCAPE '\'
|
||||
OR lower(u.username) LIKE $7 ESCAPE '\'
|
||||
OR lower(COALESCE(NULLIF(c.contact_phone, ''), u.phone)) LIKE $7 ESCAPE '\'
|
||||
OR lower(c.contact_phone) LIKE $7 ESCAPE '\'
|
||||
)`, string(req.Owner.Type), req.Owner.ID, int32(req.StoryID), req.ViewerUserID, req.JustContacts, querySet, queryLike).Scan(&count); err != nil {
|
||||
return domain.StoryViewList{}, fmt.Errorf("count story views: %w", err)
|
||||
}
|
||||
|
|
@ -1160,7 +1160,7 @@ WHERE sv.owner_peer_type = $1
|
|||
OR lower(COALESCE(c.contact_last_name, u.last_name)) LIKE $7 ESCAPE '\'
|
||||
OR lower(trim(COALESCE(NULLIF(c.contact_first_name, ''), u.first_name) || ' ' || COALESCE(c.contact_last_name, u.last_name))) LIKE $7 ESCAPE '\'
|
||||
OR lower(u.username) LIKE $7 ESCAPE '\'
|
||||
OR lower(COALESCE(NULLIF(c.contact_phone, ''), u.phone)) LIKE $7 ESCAPE '\'
|
||||
OR lower(c.contact_phone) LIKE $7 ESCAPE '\'
|
||||
)
|
||||
AND (
|
||||
NOT $9::boolean
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue