Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove unfollows #67

Merged
merged 1 commit into from
Sep 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 5 additions & 21 deletions service/adapters/apns/apns.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,30 +140,21 @@ func FollowChangePayload(followChange domain.FollowChangeBatch) ([]byte, error)

func FollowChangePayloadWithValidation(followChange domain.FollowChangeBatch, validate bool) ([]byte, error) {
alertMessage := ""
totalNpubs := len(followChange.Follows) + len(followChange.Unfollows)
totalNpubs := len(followChange.Follows)
if validate && totalNpubs > MAX_TOTAL_NPUBS {
return nil, errors.New("FollowChangeBatch for followee " + followChange.Followee.Hex() + " has too many npubs (" + fmt.Sprint(totalNpubs) + "). MAX_TOTAL_NPUBS is " + fmt.Sprint(MAX_TOTAL_NPUBS))
}

singleChange := totalNpubs == 1

if singleChange {
isFollow := len(followChange.Follows) == 1
if strings.HasPrefix(followChange.FriendlyFollower, "npub") {
if isFollow {
alertMessage = "You have a new follower!"
} else {
alertMessage = "You've been unfollowed!"
}
alertMessage = "You have a new follower!"
} else {
if isFollow {
alertMessage = followChange.FriendlyFollower + " is a new follower!"
} else {
alertMessage = followChange.FriendlyFollower + " has unfollowed you!"
}
alertMessage = followChange.FriendlyFollower + " is a new follower!"
}
} else {
alertMessage = fmt.Sprintf("You have %d new followers and %d unfollows!", len(followChange.Follows), len(followChange.Unfollows))
alertMessage = fmt.Sprintf("You have %d new followers!", len(followChange.Follows))
}

followeeNpub, error := nip19.EncodePublicKey(followChange.Followee.Hex())
Expand All @@ -176,25 +167,18 @@ func FollowChangePayloadWithValidation(followChange domain.FollowChangeBatch, va
return nil, errors.Wrap(error, "error encoding follow npubs")
}

npubUnfollows, error := pubkeysToNpubs(followChange.Unfollows)
if error != nil {
return nil, errors.Wrap(error, "error encoding unfollow npubs")
}

// See https://developer.apple.com/documentation/usernotifications/generating-a-remote-notification

var data map[string]interface{}

if singleChange {
data = map[string]interface{}{
"follows": npubFollows,
"unfollows": npubUnfollows,
"friendlyFollower": followChange.FriendlyFollower,
}
} else {
data = map[string]interface{}{
"follows": npubFollows,
"unfollows": npubUnfollows,
"follows": npubFollows,
}
}

Expand Down
80 changes: 9 additions & 71 deletions service/adapters/apns/apns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ func TestFollowChangePayload_SingleFollow(t *testing.T) {
Followee: pk1,
FriendlyFollower: "npub_someFollower",
Follows: []domain.PublicKey{pk2},
Unfollows: nil,
}

payload, err := apns.FollowChangePayload(batch)
Expand All @@ -36,44 +35,6 @@ func TestFollowChangePayload_SingleFollow(t *testing.T) {
},
"data": map[string]interface{}{
"follows": []interface{}{pk2Npub}, // Use []interface{}
"unfollows": []interface{}{},
"friendlyFollower": batch.FriendlyFollower,
},
}

var actualPayload map[string]interface{}
err = json.Unmarshal(payload, &actualPayload)
require.NoError(t, err)

require.Equal(t, expectedPayload, actualPayload)
}

func TestFollowChangePayload_SingleUnfollow(t *testing.T) {
pk1, pk1Npub := fixtures.PublicKeyAndNpub()
pk2, pk2Npub := fixtures.PublicKeyAndNpub()

batch := domain.FollowChangeBatch{
Followee: pk1,
FriendlyFollower: "npub_someFollower",
Follows: nil,
Unfollows: []domain.PublicKey{pk2},
}

payload, err := apns.FollowChangePayload(batch)
require.NoError(t, err)

expectedAlert := "You've been unfollowed!"
expectedPayload := map[string]interface{}{
"aps": map[string]interface{}{
"alert": expectedAlert,
"sound": "default",
"badge": float64(1), // Convert badge to float64
"thread-id": pk1Npub,
"interruption-level": "passive",
},
"data": map[string]interface{}{
"follows": []interface{}{},
"unfollows": []interface{}{pk2Npub}, // Use []interface{}
"friendlyFollower": batch.FriendlyFollower,
},
}
Expand All @@ -89,19 +50,17 @@ func TestFollowChangePayload_MultipleFollowsUnfollows(t *testing.T) {
pk1, pk1Npub := fixtures.PublicKeyAndNpub()
pk2, pk2Npub := fixtures.PublicKeyAndNpub()
pk3, pk3Npub := fixtures.PublicKeyAndNpub()
pk4, pk4Npub := fixtures.PublicKeyAndNpub()

batch := domain.FollowChangeBatch{
Followee: pk1,
FriendlyFollower: "FriendlyUser",
Follows: []domain.PublicKey{pk2, pk3},
Unfollows: []domain.PublicKey{pk4},
}

payload, err := apns.FollowChangePayload(batch)
require.NoError(t, err)

expectedAlert := "You have 2 new followers and 1 unfollows!"
expectedAlert := "You have 2 new followers!"
expectedPayload := map[string]interface{}{
"aps": map[string]interface{}{
"alert": expectedAlert,
Expand All @@ -111,8 +70,7 @@ func TestFollowChangePayload_MultipleFollowsUnfollows(t *testing.T) {
"interruption-level": "passive",
},
"data": map[string]interface{}{
"follows": []interface{}{pk2Npub, pk3Npub}, // Use []interface{}
"unfollows": []interface{}{pk4Npub}, // Use []interface{}
"follows": []interface{}{pk2Npub, pk3Npub}, // Use []interface{}
},
}

Expand All @@ -131,7 +89,6 @@ func TestFollowChangePayload_SingleFollow_WithFriendlyFollower(t *testing.T) {
Followee: pk1,
FriendlyFollower: "John Doe",
Follows: []domain.PublicKey{pk2},
Unfollows: nil,
}

payload, err := apns.FollowChangePayload(batch)
Expand All @@ -148,7 +105,6 @@ func TestFollowChangePayload_SingleFollow_WithFriendlyFollower(t *testing.T) {
},
"data": map[string]interface{}{
"follows": []interface{}{pk2Npub}, // Use []interface{}
"unfollows": []interface{}{},
"friendlyFollower": batch.FriendlyFollower,
},
}
Expand All @@ -171,18 +127,16 @@ func TestFollowChangePayload_BatchedFollow_WithNoFriendlyFollower(t *testing.T)
pk1, pk1Npub := fixtures.PublicKeyAndNpub()
pk2, pk2Npub := fixtures.PublicKeyAndNpub()
pk3, pk3Npub := fixtures.PublicKeyAndNpub()
pk4, pk4Npub := fixtures.PublicKeyAndNpub()

batch := domain.FollowChangeBatch{
Followee: pk1,
Follows: []domain.PublicKey{pk2, pk3},
Unfollows: []domain.PublicKey{pk4},
Followee: pk1,
Follows: []domain.PublicKey{pk2, pk3},
}

payload, err := apns.FollowChangePayload(batch)
require.NoError(t, err)

expectedAlert := "You have 2 new followers and 1 unfollows!"
expectedAlert := "You have 2 new followers!"
expectedPayload := map[string]interface{}{
"aps": map[string]interface{}{
"alert": expectedAlert,
Expand All @@ -192,8 +146,7 @@ func TestFollowChangePayload_BatchedFollow_WithNoFriendlyFollower(t *testing.T)
"interruption-level": "passive",
},
"data": map[string]interface{}{
"follows": []interface{}{pk2Npub, pk3Npub}, // Use []interface{}
"unfollows": []interface{}{pk4Npub},
"follows": []interface{}{pk2Npub, pk3Npub}, // Use []interface{}
},
}

Expand All @@ -217,17 +170,12 @@ func TestFollowChangePayload_Exceeds4096Bytes_With59TotalNpubs(t *testing.T) {
Followee: pk1,
FriendlyFollower: "npub_someFollower_wont_be_added",
Follows: []domain.PublicKey{},
Unfollows: []domain.PublicKey{},
}

for i := 0; i < 29; i++ { // 29 follows
for i := 0; i < 59; i++ {
follow, _ := fixtures.PublicKeyAndNpub()
batch.Follows = append(batch.Follows, follow)
}
for i := 0; i < 30; i++ { // 30 unfollows
unfollow, _ := fixtures.PublicKeyAndNpub()
batch.Unfollows = append(batch.Unfollows, unfollow)
}

payload, err := apns.FollowChangePayloadWithValidation(batch, false)
require.NoError(t, err)
Expand All @@ -245,17 +193,12 @@ func TestFollowChangePayload_ValidPayload_With58TotalNpubs_IsValid(t *testing.T)
Followee: pk1,
FriendlyFollower: "npub_someFollower_wont_be_added",
Follows: []domain.PublicKey{},
Unfollows: []domain.PublicKey{},
}

for i := 0; i < 29; i++ { // 29 follows
for i := 0; i < 58; i++ {
follow, _ := fixtures.PublicKeyAndNpub()
batch.Follows = append(batch.Follows, follow)
}
for i := 0; i < 29; i++ { // 29 unfollows
unfollow, _ := fixtures.PublicKeyAndNpub()
batch.Unfollows = append(batch.Unfollows, unfollow)
}

payload, err := apns.FollowChangePayloadWithValidation(batch, true) // With validation
require.NoError(t, err)
Expand All @@ -273,17 +216,12 @@ func TestFollowChangePayload_InvalidPayload_With59TotalNpubs_Fails_With_Validati
Followee: pk1,
FriendlyFollower: "npub_someFollower_wont_be_added",
Follows: []domain.PublicKey{},
Unfollows: []domain.PublicKey{},
}

for i := 0; i < 29; i++ { // 29 follows
for i := 0; i < 59; i++ { // 29 follows
follow, _ := fixtures.PublicKeyAndNpub()
batch.Follows = append(batch.Follows, follow)
}
for i := 0; i < 30; i++ { // 30 unfollows
unfollow, _ := fixtures.PublicKeyAndNpub()
batch.Unfollows = append(batch.Unfollows, unfollow)
}

payload, err := apns.FollowChangePayload(batch) // This always validates
require.Error(t, err)
Expand Down
20 changes: 3 additions & 17 deletions service/domain/follow_change_batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ type FollowChangeBatch struct {
Followee PublicKey `json:"followee"`
FriendlyFollower string `json:"friendlyFollower"`
Follows []PublicKey `json:"follows"`
Unfollows []PublicKey `json:"unfollows"`
}

func (f *FollowChangeBatch) UnmarshalJSON(data []byte) error {
var temp struct {
Followee string `json:"followee"`
FriendlyFollower string `json:"friendlyFollower"`
Follows []string `json:"follows"`
Unfollows []string `json:"unfollows"`
}

if err := json.Unmarshal(data, &temp); err != nil {
Expand All @@ -46,14 +44,6 @@ func (f *FollowChangeBatch) UnmarshalJSON(data []byte) error {
}
}

f.Unfollows = make([]PublicKey, len(temp.Unfollows))
for i, npub := range temp.Unfollows {
f.Unfollows[i], err = NewPublicKeyFromNpub(npub)
if err != nil {
return errors.New("invalid npub for unfollow: " + err.Error())
}
}

return nil
}

Expand All @@ -63,13 +53,9 @@ func (f FollowChangeBatch) String() string {
friendlyFollowee = f.Followee.Hex()
}

if len(f.Follows)+len(f.Unfollows) == 1 {
if len(f.Follows) == 1 {
return fmt.Sprintf("Follow: %s -----> %s", f.FriendlyFollower, friendlyFollowee)
} else {
return fmt.Sprintf("Unfollow: %s --x--> %s", f.FriendlyFollower, friendlyFollowee)
}
if len(f.Follows) == 1 {
return fmt.Sprintf("Follow: %s -----> %s", f.FriendlyFollower, friendlyFollowee)
}

return fmt.Sprintf("Follow aggregate: %d follows, %d unfollows for %s", len(f.Follows), len(f.Unfollows), friendlyFollowee)
return fmt.Sprintf("Follow aggregate: %d followers for %s", len(f.Follows), friendlyFollowee)
}
31 changes: 5 additions & 26 deletions service/domain/follow_change_batch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@ func TestFollowChangeBatch_UnmarshalJSON_Valid(t *testing.T) {
pk1, pk1Npub := fixtures.PublicKeyAndNpub()
pk2, pk2Npub := fixtures.PublicKeyAndNpub()
pk3, pk3Npub := fixtures.PublicKeyAndNpub()
pk4, pk4Npub := fixtures.PublicKeyAndNpub()

jsonData := `{
"followee": "` + pk1Npub + `",
"friendlyFollower": "FriendlyUser",
"follows": ["` + pk2Npub + `", "` + pk3Npub + `"],
"unfollows": ["` + pk4Npub + `"]
"follows": ["` + pk2Npub + `", "` + pk3Npub + `"]
}`

var batch domain.FollowChangeBatch
Expand All @@ -29,7 +27,6 @@ func TestFollowChangeBatch_UnmarshalJSON_Valid(t *testing.T) {
assert.Equal(t, pk1, batch.Followee)
assert.Equal(t, "FriendlyUser", batch.FriendlyFollower)
assert.Equal(t, []domain.PublicKey{pk2, pk3}, batch.Follows)
assert.Equal(t, []domain.PublicKey{pk4}, batch.Unfollows)
}

func TestFollowChangeBatch_UnmarshalJSON_InvalidFollowee(t *testing.T) {
Expand All @@ -38,8 +35,7 @@ func TestFollowChangeBatch_UnmarshalJSON_InvalidFollowee(t *testing.T) {
jsonData := `{
"followee": "invalid",
"friendlyFollower": "FriendlyUser",
"follows": ["` + pk1Npub + `"],
"unfollows": []
"follows": ["` + pk1Npub + `"]
}`

var batch domain.FollowChangeBatch
Expand All @@ -54,8 +50,7 @@ func TestFollowChangeBatch_UnmarshalJSON_InvalidFollows(t *testing.T) {
jsonData := `{
"followee": "` + pk1Npub + `",
"friendlyFollower": "FriendlyUser",
"follows": ["invalid"],
"unfollows": []
"follows": ["invalid"]
}`

var batch domain.FollowChangeBatch
Expand All @@ -78,33 +73,17 @@ func TestFollowChangeBatch_String_SingleFollow(t *testing.T) {
assert.Equal(t, expected, batch.String())
}

func TestFollowChangeBatch_String_SingleUnfollow(t *testing.T) {
pk1, pk1Npub := fixtures.PublicKeyAndNpub()
pk2, _ := fixtures.PublicKeyAndNpub()

batch := domain.FollowChangeBatch{
Followee: pk1,
FriendlyFollower: "FriendlyUser",
Unfollows: []domain.PublicKey{pk2},
}

expected := "Unfollow: FriendlyUser --x--> " + pk1Npub
assert.Equal(t, expected, batch.String())
}

func TestFollowChangeBatch_String_MultipleFollowsUnfollows(t *testing.T) {
func TestFollowChangeBatch_String_MultipleFollows(t *testing.T) {
pk1, pk1Npub := fixtures.PublicKeyAndNpub()
pk2, _ := fixtures.PublicKeyAndNpub()
pk3, _ := fixtures.PublicKeyAndNpub()
pk4, _ := fixtures.PublicKeyAndNpub()

batch := domain.FollowChangeBatch{
Followee: pk1,
FriendlyFollower: "FriendlyUser",
Follows: []domain.PublicKey{pk2, pk3},
Unfollows: []domain.PublicKey{pk4},
}

expected := "Follow aggregate: 2 follows, 1 unfollows for " + pk1Npub
expected := "Follow aggregate: 2 followers for " + pk1Npub
assert.Equal(t, expected, batch.String())
}
Loading