forked from gnolang/gno
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
243 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module gno.land/r/demo/teritori/social | ||
|
||
require ( | ||
gno.land/p/demo/avl v0.0.0-latest | ||
gno.land/p/demo/testutils v0.0.0-latest | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package social | ||
|
||
import ( | ||
"std" | ||
|
||
"gno.land/p/demo/avl" | ||
) | ||
|
||
var ( | ||
addr2User avl.Tree // std.Address -> *User | ||
) | ||
|
||
func getOrCreateUser(addr std.Address) *User { | ||
userI, ok := addr2User.Get(addr.String()) | ||
if ok { | ||
return userI.(*User) | ||
} | ||
user := &User{ | ||
address: addr, | ||
} | ||
addr2User.Set(addr.String(), user) | ||
return user | ||
} | ||
|
||
func Follow(addr std.Address) { | ||
// get caller/inviter. | ||
caller := std.GetOrigCaller() | ||
callerUser := getOrCreateUser(caller) | ||
user := getOrCreateUser(addr) | ||
callerUser.Follow(user) | ||
} | ||
|
||
func Unfollow(addr std.Address) { | ||
// get caller/inviter. | ||
caller := std.GetOrigCaller() | ||
callerUser := getOrCreateUser(caller) | ||
user := getOrCreateUser(addr) | ||
callerUser.Unfollow(user) | ||
} | ||
|
||
func Followers(addr std.Address) []std.Address { | ||
userI, ok := addr2User.Get(addr.String()) | ||
if !ok { | ||
return nil | ||
} | ||
user := userI.(*User) | ||
return user.Followers() | ||
} | ||
|
||
func FollowedCount(addr std.Address) uint{ | ||
userI, ok := addr2User.Get(addr.String()) | ||
if !ok { | ||
return 0 | ||
} | ||
user := userI.(*User) | ||
return uint(user.followeds.Size()) | ||
} | ||
|
||
func Followed(addr std.Address) []std.Address { | ||
userI, ok := addr2User.Get(addr.String()) | ||
if !ok { | ||
return nil | ||
} | ||
|
||
user := userI.(*User) | ||
|
||
return user.Followed() | ||
} | ||
|
||
func FollowersCount(addr std.Address) uint { | ||
userI, ok := addr2User.Get(addr.String()) | ||
if !ok { | ||
return 0 | ||
} | ||
user := userI.(*User) | ||
return uint(user.followers.Size()) | ||
} | ||
|
||
func IsFollower(follower std.Address, followed std.Address) bool { | ||
userI, ok := addr2User.Get(followed.String()) | ||
if !ok { | ||
return false | ||
} | ||
user := userI.(*User) | ||
_, ok = user.followers.Get(follower.String()) | ||
return ok | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package social | ||
|
||
|
||
import ( | ||
"std" | ||
"testing" | ||
|
||
"gno.land/p/demo/testutils" | ||
) | ||
|
||
|
||
func TestFollow_Follow(t *testing.T) { | ||
user := testutils.TestAddress("user") | ||
std.TestSetOrigCaller(user) | ||
|
||
|
||
Follow(user) | ||
|
||
if c := FollowersCount(user); c != 1 { | ||
t.Fatalf("FollowersCount expected to have 1 has %d", c) | ||
} | ||
|
||
if followers := Followers(user); followers[0].String() != string(user) { | ||
t.Fatalf("Followers expected to have %s has %s", string(user), followers[0].String()) | ||
} | ||
|
||
if followed := Followed(user); followed[0].String() != string(user) { | ||
t.Fatalf("Followed expected to have %s has %s", followed[0].String()) | ||
} | ||
} | ||
|
||
func TestFollow_UnFollow(t *testing.T) { | ||
user1 := testutils.TestAddress("user1") | ||
user2 := testutils.TestAddress("user2") | ||
std.TestSetOrigCaller(user1) | ||
|
||
Follow(user2) | ||
if IsFollower(user1, user2) != true { | ||
t.Fatalf("expected to be a follower") | ||
} | ||
|
||
Unfollow(user2) | ||
if IsFollower(user1, user2) != false { | ||
t.Fatalf("expected to not be a follower") | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Social Network System | ||
|
||
## Overview | ||
The Social Network System is designed to facilitate user interactions within a social network. It allows users to follow and unfollow each other, as well as retrieve information about followers and followed users. | ||
|
||
## Modules | ||
|
||
### 1. User Management | ||
- This module manages user information within the social network. | ||
- Each user is represented by a `User` struct containing their address and lists of followers and followed users. | ||
|
||
### 2. Following Functionality | ||
- Users can follow and unfollow other users. | ||
- When a user follows another user, they are added to the followed user's list of followers, and the followed user is added to the user's list of followed users. | ||
- When a user unfollows another user, they are removed from the followed user's list of followers, and the followed user is removed from the user's list of followed users. | ||
|
||
## Data Structures | ||
|
||
### User | ||
```go | ||
type User struct { | ||
address std.Address | ||
followers *avl.Tree // std.Address -> *User | ||
followeds *avl.Tree // std.Address -> *User | ||
} | ||
``` | ||
|
||
## Functions | ||
|
||
### User Management | ||
- `Followers() []std.Address`: Returns a list of addresses of users who are followers of the user. | ||
- `Followed() []std.Address`: Returns a list of addresses of users whom the user is following. | ||
|
||
### Following Functionality | ||
- `Follow(user *User)`: Adds the given user to the list of users being followed by the user. | ||
- `Unfollow(user *User)`: Removes the given user from the list of users being followed by the user. | ||
|
||
## Realm Configuration Process | ||
- Users are managed within the social network system using the provided functionality. | ||
- The system utilizes an AVL tree data structure to efficiently store and retrieve user information. | ||
|
||
## Usage | ||
- Users interact with the system by following or unfollowing other users. | ||
- User information is maintained and updated dynamically as users follow and unfollow each other. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package social | ||
|
||
import ( | ||
"std" | ||
|
||
"gno.land/p/demo/avl" | ||
) | ||
|
||
type User struct { | ||
address std.Address | ||
followers avl.Tree | ||
followeds avl.Tree | ||
} | ||
|
||
func (u *User) Address() std.Address { | ||
return u.address | ||
} | ||
|
||
func (u *User) Followers() []std.Address { | ||
followers := make([]std.Address, 0, u.followers.Size()) | ||
u.followers.Iterate("", "", func(key string, value interface{}) bool { | ||
follower := value.(*User) | ||
followers = append(followers, follower.address) | ||
return false | ||
}) | ||
return followers | ||
} | ||
|
||
func (u *User) Followed() []std.Address { | ||
followeds := make([]std.Address, 0, u.followeds.Size()) | ||
u.followeds.Iterate("", "", func(key string, value interface{}) bool { | ||
followed := value.(*User) | ||
followeds = append(followeds, followed.address) | ||
return false | ||
}) | ||
return followeds | ||
} | ||
|
||
func (u *User) Follow(user *User) { | ||
if user, ok := u.followeds.Get(user.address.String()); ok { | ||
panic("already follow") | ||
} | ||
u.followeds.Set(user.address.String(), user) | ||
user.followers.Set(u.address.String(), u) | ||
} | ||
|
||
func (u *User) Unfollow(user *User) { | ||
if _, ok := u.followeds.Get(user.address.String()); !ok { | ||
panic("not follow") | ||
} | ||
if _, ok := u.followeds.Remove(user.address.String()); !ok { | ||
panic("can't remove on followed") | ||
} | ||
|
||
if _, ok := user.followers.Remove(u.address.String()); !ok { | ||
panic("can't remove on follower") | ||
} | ||
} |