feat: sync privacy read-model rules
This commit is contained in:
parent
9f467f4be7
commit
5d5883a3d1
20 changed files with 1011 additions and 20 deletions
166
internal/rpc/privacy_paid_messages_test.go
Normal file
166
internal/rpc/privacy_paid_messages_test.go
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/iamxvbaba/td/clock"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
"go.uber.org/zap/zaptest"
|
||||
|
||||
appaccount "telesrv/internal/app/account"
|
||||
appprivacy "telesrv/internal/app/privacy"
|
||||
appusers "telesrv/internal/app/users"
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/store/memory"
|
||||
)
|
||||
|
||||
func newPrivateRequirementRouter(t *testing.T, senderPremium bool) (*Router, *appaccount.Service, *appprivacy.Service, *memory.ContactStore, domain.User, domain.User) {
|
||||
t.Helper()
|
||||
ctx := context.Background()
|
||||
usersStore := memory.NewUserStore()
|
||||
aliceInput := domain.User{AccessHash: 11, Phone: "15550008101", FirstName: "Alice"}
|
||||
if senderPremium {
|
||||
aliceInput.PremiumUntil = int(time.Now().Add(time.Hour).Unix())
|
||||
}
|
||||
alice, err := usersStore.Create(ctx, aliceInput)
|
||||
if err != nil {
|
||||
t.Fatalf("create Alice: %v", err)
|
||||
}
|
||||
bob, err := usersStore.Create(ctx, domain.User{AccessHash: 22, Phone: "15550008102", FirstName: "Bob"})
|
||||
if err != nil {
|
||||
t.Fatalf("create Bob: %v", err)
|
||||
}
|
||||
users := appusers.NewService(usersStore)
|
||||
contacts := memory.NewContactStore()
|
||||
privacy := appprivacy.NewService(memory.NewPrivacyStore(), contacts).ConfigureReadModels(users, nil)
|
||||
settingsStore := memory.NewPasswordStore()
|
||||
account := appaccount.NewService(settingsStore, appaccount.WithAccountSettings(settingsStore))
|
||||
router := New(Config{}, Deps{
|
||||
Account: account,
|
||||
Privacy: privacy,
|
||||
Users: users,
|
||||
Messages: &captureMessages{},
|
||||
}, zaptest.NewLogger(t), clock.System)
|
||||
return router, account, privacy, contacts, alice, bob
|
||||
}
|
||||
|
||||
func TestPrivateContactRequirementUsesNoPaidMessagesReadModel(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
r, account, privacy, contacts, alice, bob := newPrivateRequirementRouter(t, false)
|
||||
if _, err := account.SetGlobalPrivacy(ctx, bob.ID, domain.GlobalPrivacy{NoncontactPeersPaidStars: 7}); err != nil {
|
||||
t.Fatalf("set Bob paid requirement: %v", err)
|
||||
}
|
||||
full, err := r.onUsersGetFullUser(WithUserID(ctx, alice.ID), &tg.InputUser{
|
||||
UserID: bob.ID, AccessHash: bob.AccessHash,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("get Bob full user: %v", err)
|
||||
}
|
||||
if stars, ok := full.FullUser.GetSendPaidMessagesStars(); !ok || stars != 7 {
|
||||
t.Fatalf("full user paid stars = %d, %v; want 7, true", stars, ok)
|
||||
}
|
||||
projected, ok := full.Users[0].(*tg.User)
|
||||
if !ok {
|
||||
t.Fatalf("projected user = %T, want *tg.User", full.Users[0])
|
||||
}
|
||||
if stars, ok := projected.GetSendPaidMessagesStars(); !ok || stars != 7 {
|
||||
t.Fatalf("user paid stars = %d, %v; want 7, true", stars, ok)
|
||||
}
|
||||
requirements, err := r.onUsersGetRequirementsToContact(WithUserID(ctx, alice.ID), []tg.InputUserClass{
|
||||
&tg.InputUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("get requirements: %v", err)
|
||||
}
|
||||
if paid, ok := requirements[0].(*tg.RequirementToContactPaidMessages); !ok || paid.StarsAmount != 7 {
|
||||
t.Fatalf("requirement = %#v, want paid 7", requirements[0])
|
||||
}
|
||||
|
||||
send := func(randomID int64, allow int64) error {
|
||||
req := &tg.MessagesSendMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
Message: "hello",
|
||||
RandomID: randomID,
|
||||
}
|
||||
if allow != 0 {
|
||||
req.SetAllowPaidStars(allow)
|
||||
}
|
||||
_, err := r.onMessagesSendMessage(WithUserID(ctx, alice.ID), req)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := send(81001, 0); err == nil || !strings.Contains(err.Error(), "ALLOW_PAYMENT_REQUIRED") || !strings.Contains(err.Error(), "(7)") {
|
||||
t.Fatalf("non-exempt send err = %v, want ALLOW_PAYMENT_REQUIRED 7", err)
|
||||
}
|
||||
if err := send(81002, 7); err == nil || !strings.Contains(err.Error(), "PAYMENT_UNSUPPORTED") {
|
||||
t.Fatalf("authorized paid send err = %v, want explicit unsupported ledger", err)
|
||||
}
|
||||
|
||||
if _, err := privacy.SetRules(ctx, bob.ID, domain.PrivacyKeyNoPaidMessages, []domain.PrivacyRule{{
|
||||
Kind: domain.PrivacyRuleAllowUsers,
|
||||
UserIDs: []int64{alice.ID},
|
||||
}, {
|
||||
Kind: domain.PrivacyRuleDisallowAll,
|
||||
}}); err != nil {
|
||||
t.Fatalf("allow Alice in NoPaidMessages: %v", err)
|
||||
}
|
||||
if err := send(81003, 0); err != nil {
|
||||
t.Fatalf("explicit no-paid exception send: %v", err)
|
||||
}
|
||||
full, err = r.onUsersGetFullUser(WithUserID(ctx, alice.ID), &tg.InputUser{
|
||||
UserID: bob.ID, AccessHash: bob.AccessHash,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("get exempt Bob full user: %v", err)
|
||||
}
|
||||
if _, ok := full.FullUser.GetSendPaidMessagesStars(); ok || full.FullUser.ContactRequirePremium {
|
||||
t.Fatalf("exempt full user still carries contact restriction: %+v", full.FullUser)
|
||||
}
|
||||
|
||||
if _, err := privacy.SetRules(ctx, bob.ID, domain.PrivacyKeyNoPaidMessages, []domain.PrivacyRule{{Kind: domain.PrivacyRuleDisallowAll}}); err != nil {
|
||||
t.Fatalf("clear explicit exception: %v", err)
|
||||
}
|
||||
if _, err := contacts.Upsert(ctx, bob.ID, domain.ContactInput{
|
||||
ContactUserID: alice.ID,
|
||||
FirstName: "Alice",
|
||||
}); err != nil {
|
||||
t.Fatalf("Bob add Alice contact: %v", err)
|
||||
}
|
||||
if err := send(81004, 0); err != nil {
|
||||
t.Fatalf("recipient contact must be free: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivateContactRequirementPremiumGateUsesViewerFactsReadModel(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
senderPremium bool
|
||||
wantErr bool
|
||||
}{
|
||||
{name: "non-premium blocked", wantErr: true},
|
||||
{name: "premium allowed", senderPremium: true},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
r, account, _, _, alice, bob := newPrivateRequirementRouter(t, tc.senderPremium)
|
||||
if _, err := account.SetGlobalPrivacy(ctx, bob.ID, domain.GlobalPrivacy{NewNoncontactPeersRequirePremium: true}); err != nil {
|
||||
t.Fatalf("set premium requirement: %v", err)
|
||||
}
|
||||
_, err := r.onMessagesSendMessage(WithUserID(ctx, alice.ID), &tg.MessagesSendMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
Message: "hello",
|
||||
RandomID: 82001,
|
||||
})
|
||||
if tc.wantErr {
|
||||
if err == nil || !strings.Contains(err.Error(), "PREMIUM_ACCOUNT_REQUIRED") {
|
||||
t.Fatalf("send err = %v, want PREMIUM_ACCOUNT_REQUIRED", err)
|
||||
}
|
||||
} else if err != nil {
|
||||
t.Fatalf("premium sender should pass: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue