Skip to content

Commit

Permalink
feat: Add Social Network System
Browse files Browse the repository at this point in the history
  • Loading branch information
omarsy committed Feb 16, 2024
1 parent 26fcec5 commit b2e5977
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 0 deletions.
6 changes: 6 additions & 0 deletions examples/gno.land/r/demo/teritori/social/gno.mod
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
)
87 changes: 87 additions & 0 deletions examples/gno.land/r/demo/teritori/social/social.gno
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
}
48 changes: 48 additions & 0 deletions examples/gno.land/r/demo/teritori/social/social_test.gno
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")
}
}


44 changes: 44 additions & 0 deletions examples/gno.land/r/demo/teritori/social/spec.md
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.
58 changes: 58 additions & 0 deletions examples/gno.land/r/demo/teritori/social/user.gno
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 _, 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")
}
}

0 comments on commit b2e5977

Please sign in to comment.