github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/r/demo/boards/board.gno (about)

     1  package boards
     2  
     3  import (
     4  	"std"
     5  	"strconv"
     6  	"time"
     7  
     8  	"gno.land/p/demo/avl"
     9  )
    10  
    11  //----------------------------------------
    12  // Board
    13  
    14  type BoardID uint64
    15  
    16  func (bid BoardID) String() string {
    17  	return strconv.Itoa(int(bid))
    18  }
    19  
    20  type Board struct {
    21  	id        BoardID // only set for public boards.
    22  	url       string
    23  	name      string
    24  	creator   std.Address
    25  	threads   avl.Tree // Post.id -> *Post
    26  	postsCtr  uint64   // increments Post.id
    27  	createdAt time.Time
    28  	deleted   avl.Tree // TODO reserved for fast-delete.
    29  }
    30  
    31  func newBoard(id BoardID, url string, name string, creator std.Address) *Board {
    32  	if !reName.MatchString(name) {
    33  		panic("invalid name: " + name)
    34  	}
    35  	exists := gBoardsByName.Has(name)
    36  	if exists {
    37  		panic("board already exists")
    38  	}
    39  	return &Board{
    40  		id:        id,
    41  		url:       url,
    42  		name:      name,
    43  		creator:   creator,
    44  		threads:   avl.Tree{},
    45  		createdAt: time.Now(),
    46  		deleted:   avl.Tree{},
    47  	}
    48  }
    49  
    50  /* TODO support this once we figure out how to ensure URL correctness.
    51  // A private board is not tracked by gBoards*,
    52  // but must be persisted by the caller's realm.
    53  // Private boards have 0 id and does not ping
    54  // back the remote board on reposts.
    55  func NewPrivateBoard(url string, name string, creator std.Address) *Board {
    56  	return newBoard(0, url, name, creator)
    57  }
    58  */
    59  
    60  func (board *Board) IsPrivate() bool {
    61  	return board.id == 0
    62  }
    63  
    64  func (board *Board) GetThread(pid PostID) *Post {
    65  	pidkey := postIDKey(pid)
    66  	postI, exists := board.threads.Get(pidkey)
    67  	if !exists {
    68  		return nil
    69  	}
    70  	return postI.(*Post)
    71  }
    72  
    73  func (board *Board) AddThread(creator std.Address, title string, body string) *Post {
    74  	pid := board.incGetPostID()
    75  	pidkey := postIDKey(pid)
    76  	thread := newPost(board, pid, creator, title, body, pid, 0, 0)
    77  	board.threads.Set(pidkey, thread)
    78  	return thread
    79  }
    80  
    81  // NOTE: this can be potentially very expensive for threads with many replies.
    82  // TODO: implement optional fast-delete where thread is simply moved.
    83  func (board *Board) DeleteThread(pid PostID) {
    84  	pidkey := postIDKey(pid)
    85  	_, removed := board.threads.Remove(pidkey)
    86  	if !removed {
    87  		panic("thread does not exist with id " + pid.String())
    88  	}
    89  }
    90  
    91  func (board *Board) HasPermission(addr std.Address, perm Permission) bool {
    92  	if board.creator == addr {
    93  		switch perm {
    94  		case EditPermission:
    95  			return true
    96  		case DeletePermission:
    97  			return true
    98  		default:
    99  			return false
   100  		}
   101  	}
   102  	return false
   103  }
   104  
   105  // Renders the board for display suitable as plaintext in
   106  // console.  This is suitable for demonstration or tests,
   107  // but not for prod.
   108  func (board *Board) RenderBoard() string {
   109  	str := ""
   110  	str += "\\[[post](" + board.GetPostFormURL() + ")]\n\n"
   111  	if board.threads.Size() > 0 {
   112  		board.threads.Iterate("", "", func(key string, value interface{}) bool {
   113  			if str != "" {
   114  				str += "----------------------------------------\n"
   115  			}
   116  			str += value.(*Post).RenderSummary() + "\n"
   117  			return false
   118  		})
   119  	}
   120  	return str
   121  }
   122  
   123  func (board *Board) incGetPostID() PostID {
   124  	board.postsCtr++
   125  	return PostID(board.postsCtr)
   126  }
   127  
   128  func (board *Board) GetURLFromThreadAndReplyID(threadID, replyID PostID) string {
   129  	if replyID == 0 {
   130  		return board.url + "/" + threadID.String()
   131  	} else {
   132  		return board.url + "/" + threadID.String() + "/" + replyID.String()
   133  	}
   134  }
   135  
   136  func (board *Board) GetPostFormURL() string {
   137  	return "/r/demo/boards?help&__func=CreateThread" +
   138  		"&bid=" + board.id.String() +
   139  		"&body.type=textarea"
   140  }