Skip to content

Commit

Permalink
chore: copy boards realm to boards2 (#3110)
Browse files Browse the repository at this point in the history
Co-authored-by: Manfred Touron <[email protected]>
Co-authored-by: Jae Kwon <[email protected]>
Co-authored-by: Jeff Thompson <[email protected]>
Co-authored-by: Hariom Verma <[email protected]>
Co-authored-by: Morgan <[email protected]>
Co-authored-by: Albert Le Batteux <[email protected]>
Co-authored-by: Guilhem Fanton <[email protected]>
Co-authored-by: Blake <[email protected]>
Co-authored-by: Jeff Thompson <[email protected]>
Co-authored-by: Leon Hudak <[email protected]>
Co-authored-by: Poroburu <[email protected]>
Co-authored-by: deelawn <[email protected]>
Co-authored-by: grepsuzette <[email protected]>
Co-authored-by: jon roethke <[email protected]>
  • Loading branch information
15 people authored Nov 12, 2024
1 parent 42d5089 commit 1510a6f
Show file tree
Hide file tree
Showing 8 changed files with 802 additions and 0 deletions.
139 changes: 139 additions & 0 deletions examples/gno.land/r/demo/boards2/board.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package boards

import (
"std"
"strconv"
"time"

"gno.land/p/demo/avl"
"gno.land/p/moul/txlink"
)

//----------------------------------------
// Board

type BoardID uint64

func (bid BoardID) String() string {
return strconv.Itoa(int(bid))
}

type Board struct {
id BoardID // only set for public boards.
url string
name string
creator std.Address
threads avl.Tree // Post.id -> *Post
postsCtr uint64 // increments Post.id
createdAt time.Time
deleted avl.Tree // TODO reserved for fast-delete.
}

func newBoard(id BoardID, url string, name string, creator std.Address) *Board {
if !reName.MatchString(name) {
panic("invalid name: " + name)
}
exists := gBoardsByName.Has(name)
if exists {
panic("board already exists")
}
return &Board{
id: id,
url: url,
name: name,
creator: creator,
threads: avl.Tree{},
createdAt: time.Now(),
deleted: avl.Tree{},
}
}

/* TODO support this once we figure out how to ensure URL correctness.
// A private board is not tracked by gBoards*,
// but must be persisted by the caller's realm.
// Private boards have 0 id and does not ping
// back the remote board on reposts.
func NewPrivateBoard(url string, name string, creator std.Address) *Board {
return newBoard(0, url, name, creator)
}
*/

func (board *Board) IsPrivate() bool {
return board.id == 0
}

func (board *Board) GetThread(pid PostID) *Post {
pidkey := postIDKey(pid)
postI, exists := board.threads.Get(pidkey)
if !exists {
return nil
}
return postI.(*Post)
}

func (board *Board) AddThread(creator std.Address, title string, body string) *Post {
pid := board.incGetPostID()
pidkey := postIDKey(pid)
thread := newPost(board, pid, creator, title, body, pid, 0, 0)
board.threads.Set(pidkey, thread)
return thread
}

// NOTE: this can be potentially very expensive for threads with many replies.
// TODO: implement optional fast-delete where thread is simply moved.
func (board *Board) DeleteThread(pid PostID) {
pidkey := postIDKey(pid)
_, removed := board.threads.Remove(pidkey)
if !removed {
panic("thread does not exist with id " + pid.String())
}
}

func (board *Board) HasPermission(addr std.Address, perm Permission) bool {
if board.creator == addr {
switch perm {
case EditPermission:
return true
case DeletePermission:
return true
default:
return false
}
}
return false
}

// Renders the board for display suitable as plaintext in
// console. This is suitable for demonstration or tests,
// but not for prod.
func (board *Board) RenderBoard() string {
str := ""
str += "\\[[post](" + board.GetPostFormURL() + ")]\n\n"
if board.threads.Size() > 0 {
board.threads.Iterate("", "", func(key string, value interface{}) bool {
if str != "" {
str += "----------------------------------------\n"
}
str += value.(*Post).RenderSummary() + "\n"
return false
})
}
return str
}

func (board *Board) incGetPostID() PostID {
board.postsCtr++
return PostID(board.postsCtr)
}

func (board *Board) GetURLFromThreadAndReplyID(threadID, replyID PostID) string {
if replyID == 0 {
return board.url + "/" + threadID.String()
} else {
return board.url + "/" + threadID.String() + "/" + replyID.String()
}
}

func (board *Board) GetPostFormURL() string {
return txlink.URL("CreateThread", "bid", board.id.String())
}
22 changes: 22 additions & 0 deletions examples/gno.land/r/demo/boards2/boards.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package boards

import (
"regexp"

"gno.land/p/demo/avl"
)

//----------------------------------------
// Realm (package) state

var (
gBoards avl.Tree // id -> *Board
gBoardsCtr int // increments Board.id
gBoardsByName avl.Tree // name -> *Board
gDefaultAnonFee = 100000000 // minimum fee required if anonymous
)

//----------------------------------------
// Constants

var reName = regexp.MustCompile(`^[a-z]+[_a-z0-9]{2,29}$`)
7 changes: 7 additions & 0 deletions examples/gno.land/r/demo/boards2/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module gno.land/r/demo/boards2

require (
gno.land/p/demo/avl v0.0.0-latest
gno.land/p/moul/txlink v0.0.0-latest
gno.land/r/demo/users v0.0.0-latest
)
95 changes: 95 additions & 0 deletions examples/gno.land/r/demo/boards2/misc.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package boards

import (
"std"
"strconv"
"strings"

"gno.land/r/demo/users"
)

//----------------------------------------
// private utility methods
// XXX ensure these cannot be called from public.

func getBoard(bid BoardID) *Board {
bidkey := boardIDKey(bid)
board_, exists := gBoards.Get(bidkey)
if !exists {
return nil
}
board := board_.(*Board)
return board
}

func incGetBoardID() BoardID {
gBoardsCtr++
return BoardID(gBoardsCtr)
}

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
}
}

func boardIDKey(bid BoardID) string {
return padZero(uint64(bid), 10)
}

func postIDKey(pid PostID) string {
return padZero(uint64(pid), 10)
}

func indentBody(indent string, body string) string {
lines := strings.Split(body, "\n")
res := ""
for i, line := range lines {
if i > 0 {
res += "\n"
}
res += indent + line
}
return res
}

// NOTE: length must be greater than 3.
func summaryOf(str string, length int) string {
lines := strings.SplitN(str, "\n", 2)
line := lines[0]
if len(line) > length {
line = line[:(length-3)] + "..."
} else if len(lines) > 1 {
// len(line) <= 80
line = line + "..."
}
return line
}

func displayAddressMD(addr std.Address) string {
user := users.GetUserByAddress(addr)
if user == nil {
return "[" + addr.String() + "](/r/demo/users:" + addr.String() + ")"
} else {
return "[@" + user.Name + "](/r/demo/users:" + user.Name + ")"
}
}

func usernameOf(addr std.Address) string {
user := users.GetUserByAddress(addr)
if user == nil {
return ""
}
return user.Name
}
Loading

0 comments on commit 1510a6f

Please sign in to comment.