forked from gnolang/gno
-
Notifications
You must be signed in to change notification settings - Fork 0
Develop contract + testing social feed #1
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
Open
hthieu1110
wants to merge
59
commits into
master
Choose a base branch
from
feat/add-socia-feed-realm
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
59 commits
Select commit
Hold shift + click to select a range
6b210f7
wip: init + testing social feed
hthieu1110 7562657
feat: add tests
hthieu1110 8f67fcb
wip: try to output object to strinng
hthieu1110 3f5d519
wip: stringify objects
72eb493
feat: user binutils to convert data to buffer
hthieu1110 121faab
feat: add binutils
hthieu1110 5dc2d12
Merge branch 'feat/add-socia-feed-realm' of github.com:TERITORI/gno i…
hthieu1110 87cf403
wip: encoding reactions
7c1f7a2
feat: add GetPost by id
hthieu1110 fc909b0
wip: handle subposts
hthieu1110 e2a6a60
feat: add pagination for query posts/comments
736143e
feat: handle pginnations for posts
hthieu1110 c683cd3
chore: remove uneeded files
hthieu1110 c6ea0c6
Merge remote-tracking branch 'origin' into feat/add-socia-feed-realm
hthieu1110 18d7e3b
fix: remove unneeded AssertOrig
hthieu1110 b48e66d
feat: add render + remove check for origCaller
hthieu1110 6fb95d7
feat: add extra binutils
hthieu1110 dc88135
feat: add extra binutils
hthieu1110 a440d7f
chore: update module name
hthieu1110 5adb1a9
chore: update module name
hthieu1110 20481ba
feat: handle all categories
hthieu1110 030a5fb
feat: update social_feeds_v4
hthieu1110 5f05ad7
chore: optimize test code
hthieu1110 0f93a72
Add TipPost + tests
hthieu1110 480ebcc
Add filter by user + test
hthieu1110 e681af4
feat: add migration to social_feeds
hthieu1110 03e03a9
wip: add flag
hthieu1110 c662f34
wip: add flags
hthieu1110 2e93a46
wip
hthieu1110 208face
wip: add missinng files
hthieu1110 f9ffa3c
fix: test bank send
hthieu1110 d282920
chore: change branch
hthieu1110 cefd249
wip: handle flag posts
hthieu1110 cecc1fd
wip: handle flag post + temporary fix filter hidden posts due to Get…
hthieu1110 5871be5
feat: add hiddenPostsForUser
hthieu1110 56df907
chore: add daodao pkg
hthieu1110 1301aeb
Merge remote-tracking branch 'origin/master' into feat/add-socia-feed…
hthieu1110 a6b3eb1
chore: add files for daodao plg
hthieu1110 af44d23
chore: add needed utils
hthieu1110 c5b3f9f
wip: add flag post
hthieu1110 ea6a39b
feat: done flag post + exec
hthieu1110 95285aa
chore: rename social_feeds_v5
hthieu1110 749b9b2
feat: deploy all updated versions
hthieu1110 86d82b0
fix: add missing pkg to gno.mod
hthieu1110 c9502dd
fix: fix pagination when querying posts
hthieu1110 5af5dbe
feat: add test for query out of range
hthieu1110 f645019
wip: migrate
hthieu1110 a45fd60
wip
hthieu1110 80c5aad
feat: done migration + wip: testing migration
hthieu1110 0f72bcd
feat: handle comments by parentID instead of comments array
hthieu1110 8948048
feat: use json encoding + adjust tests
hthieu1110 fcad5c5
feat: done migration JSON
hthieu1110 7371b6f
fix: optimize char used for metadata
hthieu1110 8800438
feat: add social_feeds_v8 + social_feeds_dao_v2
hthieu1110 ddd6f11
fix unicode pkg
hthieu1110 758edfc
fix: parserString
hthieu1110 8a20006
update gno pkg with updated ujson
hthieu1110 af6c3dc
update feeds with update string parsed
hthieu1110 3ea5128
update teritori group name
hthieu1110 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,77 @@ | ||
| package social_feeds | ||
|
|
||
| import ( | ||
| "std" | ||
| "time" | ||
|
|
||
| "gno.land/p/demo/avl" | ||
| ) | ||
|
|
||
| type FeedID uint64 | ||
|
|
||
| type Feed struct { | ||
| id FeedID | ||
| url string | ||
| name string | ||
| creator std.Address | ||
| owner std.Address | ||
| posts avl.Tree // Post.id -> *Post | ||
| createdAt time.Time | ||
| deleted avl.Tree | ||
|
|
||
| postsCtr uint64 | ||
| } | ||
|
|
||
| func newFeed(fid FeedID, url string, name string, creator std.Address) *Feed { | ||
| if !reName.MatchString(name) { | ||
| panic("invalid feed name: " + name) | ||
| } | ||
|
|
||
| if gFeedsByName.Has(name) { | ||
| panic("feed already exists: " + name) | ||
| } | ||
|
|
||
| return &Feed{ | ||
| id: fid, | ||
| url: url, | ||
| name: name, | ||
| creator: creator, | ||
| owner: creator, | ||
| posts: avl.Tree{}, | ||
| createdAt: time.Now(), | ||
| deleted: avl.Tree{}, | ||
|
|
||
| postsCtr: 0, | ||
| } | ||
| } | ||
|
|
||
| func (feed *Feed) incGetPostID() PostID { | ||
| feed.postsCtr++ | ||
| return PostID(feed.postsCtr) | ||
| } | ||
|
|
||
| func (feed *Feed) GetPost(pid PostID) *Post { | ||
| pidkey := postIDKey(pid) | ||
| post_, exists := feed.posts.Get(pidkey) | ||
| if !exists { | ||
| return nil | ||
| } | ||
| return post_.(*Post) | ||
| } | ||
|
|
||
| func (feed *Feed) MustGetPost(pid PostID) *Post { | ||
| post := feed.GetPost(pid) | ||
| if post == nil { | ||
| panic("post does not exist") | ||
| } | ||
| return post | ||
| } | ||
|
|
||
| func (feed *Feed) AddPost(creator std.Address, parentID PostID, category uint64, metadata string) *Post { | ||
| pid := feed.incGetPostID() | ||
| pidkey := postIDKey(pid) | ||
|
|
||
| post := newPost(feed, pid, creator, parentID, category, metadata) | ||
| feed.posts.Set(pidkey, post) | ||
| return post | ||
| } | ||
This file contains hidden or 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,22 @@ | ||
| package social_feeds | ||
|
|
||
| import ( | ||
| "regexp" | ||
|
|
||
| "gno.land/p/demo/avl" | ||
| ) | ||
|
|
||
| //---------------------------------------- | ||
| // Realm (package) state | ||
|
|
||
| var ( | ||
| gFeeds avl.Tree // id -> *Feed | ||
| gFeedsCtr int // increments Feed.id | ||
| gFeedsByName avl.Tree // name -> *Feed | ||
| gDefaultAnonFee = 100000000 // minimum fee required if anonymous | ||
| ) | ||
|
|
||
| //---------------------------------------- | ||
| // Constants | ||
|
|
||
| var reName = regexp.MustCompile(`^[a-z]+[_a-z0-9]{2,29}$`) |
This file contains hidden or 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,45 @@ | ||
| package social_feeds | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "testing" | ||
|
|
||
| "gno.land/r/demo/users" | ||
| ) | ||
|
|
||
| func Test(t *testing.T) { | ||
| { | ||
| // Create Feed | ||
| testing.SetOrigCaller("yo") | ||
n0izn0iz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| feedID := CreateFeed("teritori") | ||
|
|
||
| if feedID != 1 { | ||
| t.Fatalf("expected feedID: 1, got %q.", feedID) | ||
| } | ||
| } | ||
| { | ||
| // Create Post | ||
| postID := CreatePost(1, 0, 0, `{"gifs": [], "files": [], "title": "", "message": "testouille", "hashtags": [], "mentions": [], "createdAt": "2023-03-29T12:19:04.858Z", "updatedAt": "2023-03-29T12:19:04.858Z"}`) | ||
|
|
||
| if postID != 1 { | ||
| t.Fatalf("expected postID: 1, got %q.", postID) | ||
| } | ||
| } | ||
| { | ||
| // React Post | ||
| ReactPost(1, 1, "🥰", true) | ||
|
|
||
| feed := mustGetFeed(1) | ||
| post := feed.MustGetPost(1) | ||
|
|
||
| reactionCount_, ok := post.reactions.Get("🥰") | ||
| if !ok { | ||
| t.Fatalf("expected 🥰 exists") | ||
| } | ||
|
|
||
| reactionCount := reactionCount_.(int) | ||
| if reactionCount != 1 { | ||
| t.Fatalf("expected reactionCount: 1, got %q.", reactionCount) | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or 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/social_feeds | ||
|
|
||
| require ( | ||
| "gno.land/p/demo/avl" v0.0.0-latest | ||
| "gno.land/r/demo/users" v0.0.0-latest | ||
| ) |
This file contains hidden or 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,66 @@ | ||
| package social_feeds | ||
|
|
||
| import ( | ||
| "std" | ||
| "strconv" | ||
| "strings" | ||
|
|
||
| "gno.land/r/demo/users" | ||
| ) | ||
|
|
||
| func getFeed(fid FeedID) *Feed { | ||
| fidkey := feedIDKey(fid) | ||
| feed_, exists := gFeeds.Get(fidkey) | ||
| if !exists { | ||
| return nil | ||
| } | ||
| feed := feed_.(*Feed) | ||
| return feed | ||
| } | ||
|
|
||
| func mustGetFeed(fid FeedID) *Feed { | ||
| feed := getFeed(fid) | ||
| if feed == nil { | ||
| panic("Feed does not exist") | ||
| } | ||
| return feed | ||
| } | ||
|
|
||
| func incGetFeedID() FeedID { | ||
| gFeedsCtr++ | ||
| return FeedID(gFeedsCtr) | ||
| } | ||
|
|
||
| func usernameOf(addr std.Address) string { | ||
| user := users.GetUserByAddress(addr) | ||
| if user == nil { | ||
| return "" | ||
| } else { | ||
| return user.Name() | ||
| } | ||
| } | ||
|
|
||
| func feedIDKey(fid FeedID) string { | ||
| return padZero(uint64(fid), 10) | ||
| } | ||
|
|
||
| func postIDKey(pid PostID) string { | ||
| return padZero(uint64(pid), 10) | ||
| } | ||
|
|
||
| func padLeft(str string, length int) string { | ||
| if len(str) >= length { | ||
| return str | ||
| } else { | ||
| return strings.Repeat(" ", length-len(str)) + str | ||
| } | ||
| } | ||
|
|
||
| func padZero(u64 uint64, length int) string { | ||
| str := strconv.Itoa(int(u64)) | ||
| if len(str) >= length { | ||
| return str | ||
| } else { | ||
| return strings.Repeat("0", length-len(str)) + str | ||
| } | ||
| } |
This file contains hidden or 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_feeds | ||
|
|
||
| import ( | ||
| "std" | ||
| "strconv" | ||
| "time" | ||
|
|
||
| "gno.land/p/demo/avl" | ||
| ) | ||
|
|
||
| type PostID uint64 | ||
|
|
||
| type Reaction struct { | ||
| icon string | ||
| count uint64 | ||
| } | ||
|
|
||
| var Categories []string = []string{ | ||
| "Reaction", | ||
| "Comment", | ||
| "Norman", | ||
hthieu1110 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "Article", | ||
| "Picture", | ||
| "Audio", | ||
| "Video", | ||
| } | ||
|
|
||
| type Post struct { | ||
| id PostID | ||
| parentID PostID | ||
| feedID FeedID | ||
| category uint64 | ||
| metadata string | ||
| reactions avl.Tree | ||
| creator std.Address | ||
| deleted bool | ||
|
|
||
| createdAt time.Time | ||
| updatedAt time.Time | ||
| deletedAt time.Time | ||
| } | ||
|
|
||
| func newPost(feed *Feed, id PostID, creator std.Address, parentID PostID, category uint64, metadata string) *Post { | ||
| return &Post{ | ||
| id: id, | ||
| parentID: parentID, | ||
| feedID: feed.id, | ||
| category: category, | ||
| metadata: metadata, | ||
| reactions: avl.Tree{}, | ||
| creator: creator, | ||
| createdAt: time.Now(), | ||
| } | ||
| } | ||
|
|
||
| func (post *Post) Update(category uint64, metadata string) { | ||
| post.category = category | ||
| post.metadata = metadata | ||
| post.updatedAt = time.Now() | ||
| } | ||
|
|
||
| func (post *Post) Delete() { | ||
| post.deleted = true | ||
| post.deletedAt = time.Now() | ||
| } | ||
|
|
||
| // Always remove reaction if count = 0 | ||
| func (post *Post) React(icon string, up bool) { | ||
| count_, ok := post.reactions.Get(icon) | ||
| count := 0 | ||
|
|
||
| if ok { | ||
| count = count_.(int) | ||
| } | ||
|
|
||
| if up { | ||
| count++ | ||
| } else { | ||
| count-- | ||
| } | ||
|
|
||
| if count <= 0 { | ||
| post.reactions.Remove(icon) | ||
| } else { | ||
| post.reactions.Set(icon, count) | ||
| } | ||
| } | ||
This file contains hidden or 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,84 @@ | ||
| package social_feeds | ||
|
|
||
| import ( | ||
| "std" | ||
| "strconv" | ||
| ) | ||
|
|
||
| func CreateFeed(name string) FeedID { | ||
| std.AssertOriginCall() | ||
| fid := incGetFeedID() | ||
| caller := std.PrevRealm().Addr() | ||
| if usernameOf(caller) == "" { | ||
| panic("unauthorized") | ||
| } | ||
| url := "/r/demo/feeds:" + name | ||
| feed := newFeed(fid, url, name, caller) | ||
| fidkey := feedIDKey(fid) | ||
| gFeeds.Set(fidkey, feed) | ||
| gFeedsByName.Set(name, feed) | ||
| return feed.id | ||
| } | ||
|
|
||
| // Anyone can create a post in a existing feed | ||
| // Anonymous user has to pay a configurable minimum fee | ||
| func CreatePost(fid FeedID, parentID PostID, catetory uint64, metadata string) PostID { | ||
| std.AssertOriginCall() | ||
| caller := std.PrevRealm().Addr() | ||
|
|
||
| // if usernameOf(caller) == "" { | ||
| // if !checkAnonFee() { | ||
| // panic("please register, otherwise minimum fee " + strconv.Itoa(gDefaultAnonFee) + " is required if anonymous") | ||
| // } | ||
| // } | ||
hthieu1110 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| feed := mustGetFeed(fid) | ||
| post := feed.AddPost(caller, parentID, catetory, metadata) | ||
| return post.id | ||
| } | ||
|
|
||
| // Only post's owner can edit post | ||
| func EditPost(fid FeedID, pid PostID, category uint64, metadata string) { | ||
| std.AssertOriginCall() | ||
| caller := std.PrevRealm().Addr() | ||
| feed := mustGetFeed(fid) | ||
| post := feed.MustGetPost(pid) | ||
|
|
||
| if caller != post.creator { | ||
| panic("you are not creator of this post") | ||
| } | ||
|
|
||
| post.Update(category, metadata) | ||
| } | ||
|
|
||
| // Only owner can delete the post | ||
| func DeletePost(fid FeedID, pid PostID) { | ||
| std.AssertOriginCall() | ||
| caller := std.PrevRealm().Addr() | ||
| feed := mustGetFeed(fid) | ||
| post := feed.MustGetPost(pid) | ||
|
|
||
| if caller != post.creator { | ||
| panic("you are not creator of this post") | ||
| } | ||
|
|
||
| post.Delete() | ||
| } | ||
|
|
||
| // Any one can react post | ||
| func ReactPost(fid FeedID, pid PostID, icon string, up bool) { | ||
| std.AssertOriginCall() | ||
| caller := std.PrevRealm().Addr() | ||
| feed := mustGetFeed(fid) | ||
| post := feed.MustGetPost(pid) | ||
|
|
||
| post.React(icon, up) | ||
| } | ||
|
|
||
| func checkAnonFee() bool { | ||
| sent := std.GetOrigSend() | ||
| anonFeeCoin := std.Coin{"ugnot", int64(gDefaultAnonFee)} | ||
| if len(sent) == 1 && sent[0].IsGTE(anonFeeCoin) { | ||
| return true | ||
| } | ||
| return false | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these should return a copy of Post, otherwise other realms could arbitrarily call
Post.UpdateorPost.DeleteI thinkUh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually there is a mechanism where a realm cannot modify objects owned by other realms so this might not be needed
just FYI: currently there is a bug in it that allows to change ownership when you store a pointer that is passed to you