PathrockNetwork Gno Explorer
HomeBlocksTransactionsRealmsPackagesValidators

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/gnoland/boards2/v0

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v0
Namespace
gnoland / boards2
Files
252 (README)(gnomod.toml)
Exported functions
51
Module
gno.land/r/gnoland/boards2/v0
gno
0.9

Files (252)

  • README.mdmarkdown
  • gnomod.tomltoml
  • boards.gnogno
  • doc.gnogno
  • flag.gnogno
  • format.gnogno
  • hub.gnogno
  • meta.gnogno
  • permissions_validators_basic.gnogno
  • permissions_validators_open.gnogno
  • permissions.gnogno
  • public_ban.gnogno
  • public_flag.gnogno
  • public_freeze.gnogno
  • public_invite.gnogno
  • public_lock.gnogno
  • public.gnogno
  • render_board.gnogno
  • render_post.gnogno
  • render_reply.gnogno
  • render_thread.gnogno
  • render.gnogno
  • uris_board.gnogno
  • uris_post.gnogno
  • z_accept_invite_00_filetest.gnogno
  • z_accept_invite_01_filetest.gnogno
  • z_accept_invite_02_filetest.gnogno
  • z_accept_invite_03_filetest.gnogno
  • z_ban_00_filetest.gnogno
  • z_ban_01_filetest.gnogno
  • z_ban_02_filetest.gnogno
  • z_change_member_role_00_filetest.gnogno
  • z_change_member_role_01_filetest.gnogno
  • z_change_member_role_02_filetest.gnogno
  • z_change_member_role_03_filetest.gnogno
  • z_change_member_role_04_filetest.gnogno
  • z_change_member_role_05_filetest.gnogno
  • z_change_member_role_06_filetest.gnogno
  • z_change_member_role_07_filetest.gnogno
  • z_create_board_00_filetest.gnogno
  • z_create_board_01_filetest.gnogno
  • z_create_board_02_filetest.gnogno
  • z_create_board_03_filetest.gnogno
  • z_create_board_04_filetest.gnogno
  • z_create_board_05_filetest.gnogno
  • z_create_board_06_filetest.gnogno
  • z_create_board_07_filetest.gnogno
  • z_create_board_08_filetest.gnogno
  • z_create_board_09_filetest.gnogno
  • z_create_board_10_filetest.gnogno
  • z_create_reply_00_filetest.gnogno
  • z_create_reply_01_filetest.gnogno
  • z_create_reply_02_filetest.gnogno
  • z_create_reply_03_filetest.gnogno
  • z_create_reply_04_filetest.gnogno
  • z_create_reply_05_filetest.gnogno
  • z_create_reply_06_filetest.gnogno
  • z_create_reply_07_filetest.gnogno
  • z_create_reply_08_filetest.gnogno
  • z_create_reply_09_filetest.gnogno
  • z_create_reply_10_filetest.gnogno
  • z_create_reply_11_filetest.gnogno
  • z_create_reply_12_filetest.gnogno
  • z_create_reply_13_filetest.gnogno
  • z_create_reply_14_filetest.gnogno
  • z_create_reply_15_filetest.gnogno
  • z_create_reply_16_filetest.gnogno
  • z_create_repost_00_filetest.gnogno
  • z_create_repost_01_filetest.gnogno
  • z_create_repost_02_filetest.gnogno
  • z_create_repost_03_filetest.gnogno
  • z_create_repost_04_filetest.gnogno
  • z_create_thread_00_filetest.gnogno
  • z_create_thread_01_filetest.gnogno
  • z_create_thread_02_filetest.gnogno
  • z_create_thread_03_filetest.gnogno
  • z_create_thread_04_filetest.gnogno
  • z_create_thread_05_filetest.gnogno
  • z_create_thread_06_filetest.gnogno
  • z_delete_reply_00_filetest.gnogno
  • z_delete_reply_01_filetest.gnogno
  • z_delete_reply_02_filetest.gnogno
  • z_delete_reply_03_filetest.gnogno
  • z_delete_reply_04_filetest.gnogno
  • z_delete_reply_05_filetest.gnogno
  • z_delete_reply_06_filetest.gnogno
  • z_delete_reply_07_filetest.gnogno
  • z_delete_reply_08_filetest.gnogno
  • z_delete_reply_09_filetest.gnogno
  • z_delete_thread_00_filetest.gnogno
  • z_delete_thread_01_filetest.gnogno
  • z_delete_thread_02_filetest.gnogno
  • z_delete_thread_03_filetest.gnogno
  • z_delete_thread_04_filetest.gnogno
  • z_delete_thread_05_filetest.gnogno
  • z_delete_thread_06_filetest.gnogno
  • z_edit_reply_00_filetest.gnogno
  • z_edit_reply_01_filetest.gnogno
  • z_edit_reply_02_filetest.gnogno
  • z_edit_reply_03_filetest.gnogno
  • z_edit_reply_04_filetest.gnogno
  • z_edit_reply_05_filetest.gnogno
  • z_edit_reply_06_filetest.gnogno
  • z_edit_reply_07_filetest.gnogno
  • z_edit_reply_08_filetest.gnogno
  • z_edit_thread_00_filetest.gnogno
  • z_edit_thread_01_filetest.gnogno
  • z_edit_thread_02_filetest.gnogno
  • z_edit_thread_03_filetest.gnogno
  • z_edit_thread_04_filetest.gnogno
  • z_edit_thread_05_filetest.gnogno
  • z_edit_thread_06_filetest.gnogno
  • z_edit_thread_07_filetest.gnogno
  • z_flag_reply_00_filetest.gnogno
  • z_flag_reply_01_filetest.gnogno
  • z_flag_reply_02_filetest.gnogno
  • z_flag_reply_03_filetest.gnogno
  • z_flag_reply_04_filetest.gnogno
  • z_flag_reply_05_filetest.gnogno
  • z_flag_reply_06_filetest.gnogno
  • z_flag_reply_07_filetest.gnogno
  • z_flag_reply_08_filetest.gnogno
  • z_flag_reply_09_filetest.gnogno
  • z_flag_thread_00_filetest.gnogno
  • z_flag_thread_01_filetest.gnogno
  • z_flag_thread_02_filetest.gnogno
  • z_flag_thread_03_filetest.gnogno
  • z_flag_thread_04_filetest.gnogno
  • z_flag_thread_05_filetest.gnogno
  • z_flag_thread_06_filetest.gnogno
  • z_flag_thread_07_filetest.gnogno
  • z_flag_thread_08_filetest.gnogno
  • z_freeze_board_00_filetest.gnogno
  • z_freeze_board_01_filetest.gnogno
  • z_freeze_thread_00_filetest.gnogno
  • z_freeze_thread_01_filetest.gnogno
  • z_freeze_thread_02_filetest.gnogno
  • z_get_board_id_from_name_00_filetest.gnogno
  • z_get_board_id_from_name_01_filetest.gnogno
  • z_hub_0_a_filetest.gnogno
  • z_hub_0_b_filetest.gnogno
  • z_hub_0_c_filetest.gnogno
  • z_hub_1_a_filetest.gnogno
  • z_hub_1_b_filetest.gnogno
  • z_hub_1_c_filetest.gnogno
  • z_hub_2_a_filetest.gnogno
  • z_hub_2_b_filetest.gnogno
  • z_hub_3_a_filetest.gnogno
  • z_hub_3_b_filetest.gnogno
  • z_hub_4_a_filetest.gnogno
  • z_hub_4_b_filetest.gnogno
  • z_hub_5_a_filetest.gnogno
  • z_hub_5_b_filetest.gnogno
  • z_hub_6_a_filetest.gnogno
  • z_hub_6_b_filetest.gnogno
  • z_hub_6_c_filetest.gnogno
  • z_hub_6_d_filetest.gnogno
  • z_hub_6_e_filetest.gnogno
  • z_hub_7_a_filetest.gnogno
  • z_hub_7_b_filetest.gnogno
  • z_hub_8_a_filetest.gnogno
  • z_hub_8_b_filetest.gnogno
  • z_hub_8_c_filetest.gnogno
  • z_hub_9_a_filetest.gnogno
  • z_hub_9_b_filetest.gnogno
  • z_hub_9_c_filetest.gnogno
  • z_invite_member_00_filetest.gnogno
  • z_invite_member_01_filetest.gnogno
  • z_invite_member_02_filetest.gnogno
  • z_invite_member_03_filetest.gnogno
  • z_invite_member_04_filetest.gnogno
  • z_invite_member_05_filetest.gnogno
  • z_invite_member_06_filetest.gnogno
  • z_is_banned_00_filetest.gnogno
  • z_is_banned_01_filetest.gnogno
  • z_is_member_00_filetest.gnogno
  • z_is_member_01_filetest.gnogno
  • z_lock_realm_00_filetest.gnogno
  • z_lock_realm_01_filetest.gnogno
  • z_lock_realm_02_filetest.gnogno
  • z_lock_realm_03_filetest.gnogno
  • z_lock_realm_04_filetest.gnogno
  • z_lock_realm_05_filetest.gnogno
  • z_remove_member_00_filetest.gnogno
  • z_remove_member_01_filetest.gnogno
  • z_remove_member_02_filetest.gnogno
  • z_remove_member_03_filetest.gnogno
  • z_rename_board_00_filetest.gnogno
  • z_rename_board_01_filetest.gnogno
  • z_rename_board_02_filetest.gnogno
  • z_rename_board_03_filetest.gnogno
  • z_rename_board_04_filetest.gnogno
  • z_rename_board_05_filetest.gnogno
  • z_rename_board_06_filetest.gnogno
  • z_rename_board_07_filetest.gnogno
  • z_rename_board_08_filetest.gnogno
  • z_rename_board_09_filetest.gnogno
  • z_request_invite_00_filetest.gnogno
  • z_request_invite_01_filetest.gnogno
  • z_request_invite_02_filetest.gnogno
  • z_request_invite_03_filetest.gnogno
  • z_request_invite_04_filetest.gnogno
  • z_revoke_invite_00_filetest.gnogno
  • z_revoke_invite_01_filetest.gnogno
  • z_revoke_invite_02_filetest.gnogno
  • z_set_flagging_threshold_00_filetest.gnogno
  • z_set_flagging_threshold_01_filetest.gnogno
  • z_set_flagging_threshold_02_filetest.gnogno
  • z_set_permissions_00_filetest.gnogno
  • z_set_permissions_01_filetest.gnogno
  • z_set_permissions_02_filetest.gnogno
  • z_set_realm_notice_00_filetest.gnogno
  • z_set_realm_notice_01_filetest.gnogno
  • z_set_realm_notice_02_filetest.gnogno
  • z_set_realm_notice_03_filetest.gnogno
  • z_set_required_account_amount_00_filetest.gnogno
  • z_set_required_account_amount_01_filetest.gnogno
  • z_set_required_account_amount_02_filetest.gnogno
  • z_ui_admin_users_00_filetest.gnogno
  • z_ui_board_00_filetest.gnogno
  • z_ui_board_01_filetest.gnogno
  • z_ui_board_02_filetest.gnogno
  • z_ui_board_03_filetest.gnogno
  • z_ui_board_04_filetest.gnogno
  • z_ui_board_05_filetest.gnogno
  • z_ui_board_members_00_filetest.gnogno
  • z_ui_home_00_filetest.gnogno
  • z_ui_home_01_filetest.gnogno
  • z_ui_home_02_filetest.gnogno
  • z_ui_reply_00_filetest.gnogno
  • z_ui_reply_01_filetest.gnogno
  • z_ui_reply_02_filetest.gnogno
  • z_ui_reply_03_filetest.gnogno
  • z_ui_reply_04_filetest.gnogno
  • z_ui_thread_00_filetest.gnogno
  • z_ui_thread_01_filetest.gnogno
  • z_ui_thread_02_filetest.gnogno
  • z_ui_thread_03_filetest.gnogno
  • z_ui_thread_04_filetest.gnogno
  • z_ui_thread_05_filetest.gnogno
  • z_ui_thread_06_filetest.gnogno
  • z_ui_thread_07_filetest.gnogno
  • z_ui_thread_08_filetest.gnogno
  • z_ui_thread_09_filetest.gnogno
  • z_ui_thread_10_filetest.gnogno
  • z_ui_thread_11_filetest.gnogno
  • z_ui_thread_12_filetest.gnogno
  • z_ui_thread_13_filetest.gnogno
  • z_ui_thread_14_filetest.gnogno
  • z_unban_00_filetest.gnogno
  • z_unban_01_filetest.gnogno
  • z_unban_02_filetest.gnogno
  • render.gnogno
    1package boards223import (4	"net/url"5	"strconv"6	"strings"7	"time"8

    Functions

    • AcceptInvite(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, user string)

    • AreRealmMembersLocked() bool

    • Ban(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, user string, hours uint, reason string)

    • BoardCount() int

    • ChangeMemberRole(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, member string, role string)

    • CreateBoard(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, name string, listed bool, open bool) uint64

    • CreateReply(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, threadID uint64, replyID uint64, body string) uint64

    • CreateRepost(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, threadID uint64, destinationBoardID uint64, title string, body string) uint64

    • CreateThread(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, title string, body string) uint64

    • DeleteReply(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, threadID uint64, replyID uint64)

    • DeleteThread(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, threadID uint64)

    • EditReply(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, threadID uint64, replyID uint64, body string)

    • EditThread(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, threadID uint64, title string, body string)

    • FlagReply(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, threadID uint64, replyID uint64, reason string)

    • FlagThread(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, threadID uint64, reason string)

    • FreezeBoard(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64)

    • FreezeThread(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, threadID uint64)

    • GetBoard(id uint64) (struct{id uint64; name string; aliases []string; readonly bool; threadCount int; memberCount int; creator .uverse.address; createdAt int64; updatedAt int64}, bool)

    • GetBoardIDFromName(interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, name string) (uint64, found bool)

    • GetBoards(start int, count int) []gno.land/p/gnoland/boards/exts/hub/v0.Board

    • GetComment(boardID uint64, threadID uint64, commentID uint64) (struct{id uint64; boardID uint64; threadID uint64; parentID uint64; body string; hidden bool; replyCount int; flagCount int; creator .uverse.address; createdAt int64; updatedAt int64}, bool)

    • GetComments(boardID uint64, threadID uint64, start int, count int) []gno.land/p/gnoland/boards/exts/hub/v0.Comment

    • GetFlaggingThreshold(boardID uint64) int

    • GetFlags(boardID uint64, threadID uint64, commentID uint64, start int, count int) []gno.land/p/gnoland/boards/exts/hub/v0.Flag

    • GetMembers(boardID uint64, start int, count int) []gno.land/p/gnoland/boards/exts/hub/v0.Member

    • GetReplies(boardID uint64, threadID uint64, commentID uint64, start int, count int) []gno.land/p/gnoland/boards/exts/hub/v0.Comment

    • GetReposts(boardID uint64, threadID uint64, start int, count int) []gno.land/p/gnoland/boards/exts/hub/v0.Thread

    • GetThread(boardID uint64, threadID uint64) (struct{id uint64; originalBoardID uint64; originalThreadID uint64; boardID uint64; title string; body string; hidden bool; readonly bool; commentCount int; repostCount int; flagCount int; creator .uverse.address; createdAt int64; updatedAt int64}, bool)

    • GetThreads(boardID uint64, start int, count int) []gno.land/p/gnoland/boards/exts/hub/v0.Thread

    • HasMemberRole(boardID uint64, member string, role string) bool

    • InviteMember(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, user string, role string)

    • InviteMembers(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, invites ...gno.land/r/gnoland/boards2/v0.Invite)

    • IsBanned(boardID uint64, user string) bool

    • IsBoardFrozen(boardID uint64) bool

    • IsMember(boardID uint64, user string) bool

    • IsRealmLocked() bool

    • IsThreadFrozen(boardID uint64, threadID uint64) bool

    • LockRealm(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, lockRealmMembers bool)

    • RemoveMember(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, member string)

    • RenameBoard(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, name string, newName string)

    • Render(path string) string

    • RequestInvite(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64)

    • RevokeInvite(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, user string)

    • SetFlaggingThreshold(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, threshold int)

    • SetHelp(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, content string)

    • SetPermissions(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, p interface {HasPermission func(.uverse.address, gno.land/p/gnoland/boards/v0.Permission) bool; HasRole func(.uverse.address, gno.land/p/gnoland/boards/v0.Role) bool; HasUser func(.uverse.address) bool; IterateUsers func(int, int, gno.land/p/gnoland/boards/v0.UsersIterFn) bool; RemoveUser func(.uverse.address) bool; SetUserRoles func(.uverse.address, ...gno.land/p/gnoland/boards/v0.Role); UsersCount func() int; WithPermission func(.uverse.address, gno.land/p/gnoland/boards/v0.Permission, gno.land/p/gnoland/boards/v0.Args, func())})

    • SetRealmNotice(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, message string)

    • SetRequiredAccountAmount(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, amount int64)

    • Unban(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, user string, reason string)

    • UnfreezeBoard(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64)

    • UnfreezeThread(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, boardID uint64, threadID uint64)

    Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

    Rendered

    RenderedRawgnoweb ↗

    vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.

    9 "gno.land/p/gnoland/boards/v0"
    10 "gno.land/p/jeronimoalbi/mdform/v0"
    11 "gno.land/p/jeronimoalbi/pager/v0"
    12 "gno.land/p/leon/svgbtn/v0"
    13 "gno.land/p/moul/md/v0"
    14 "gno.land/p/moul/mdtable/v0"
    15 "gno.land/p/nt/markdown/foreign/v0"
    16 "gno.land/p/nt/mux/v0"
    17)
    18
    19const (
    20 pageSizeDefault = 6
    21 pageSizeReplies = 10
    22 // pageSizeFlat is the page size of the flat "all comments" view (?flat=1).
    23 // Each comment renders exactly one <gno-foreign> block (no recursion); with
    24 // the OP (and any repost-source body) the per-page total stays well under
    25 // maxRenderedBodies, so a flat page can't hit the render cap.
    26 pageSizeFlat = 50
    27)
    28
    29// maxRenderedBodies caps user bodies wrapped in <gno-foreign> per page
    30// render, kept a margin under gnoweb's per-render foreign-block cap
    31// (foreign.MaxBlocksPerRender, sourced from chain/markdown so it can't
    32// drift from the renderer). On reaching it the tree stops descending
    33// and shows a truncation notice instead of letting the renderer blank
    34// comments past the cap. The margin absorbs the OP, repost source
    35// bodies, and chrome.
    36//
    37// Computed lazily (a func, not a package-level var) so it tracks the
    38// native cap across chain upgrades: a var initializer runs once at
    39// realm-init and persists, freezing a stale value if the underlying
    40// MaxBlocksPerRender ever changes; recomputing per render re-reads it.
    41func maxRenderedBodies() int {
    42 return foreign.MaxBlocksPerRender() - 10
    43}
    44
    45// sortToggleLink builds the asc/desc sort-toggle link for path. The label
    46// names the DESTINATION order (what you get by clicking), not the order you're
    47// currently viewing, and ?page= is reset since page N of one order is a
    48// different slice in the other. It reports whether the CURRENT order is
    49// descending, so callers can drive their own (signed-count or reverse-iterate)
    50// pagination. Other query params (e.g. flat=1) are preserved.
    51func sortToggleLink(path string) (link string, desc bool) {
    52 r := parseRealmPath(path)
    53 desc = r.Query.Get("order") == "desc"
    54 r.Query.Del("page")
    55 if desc {
    56 r.Query.Set("order", "asc")
    57 return md.Link("oldest first", r.String()), true
    58 }
    59 r.Query.Set("order", "desc")
    60 return md.Link("newest first", r.String()), false
    61}
    62
    63const menuManageBoard = "manageBoard"
    64
    65var (
    66 createBoardURI = gRealmPath + ":create-board"
    67 adminUsersURI = gRealmPath + ":admin-users"
    68 helpURI = gRealmPath + ":help"
    69)
    70
    71func Render(path string) string {
    72 var (
    73 b strings.Builder
    74 router = mux.NewRouter()
    75 )
    76
    77 router.HandleFunc("", renderBoardsList)
    78 router.HandleFunc("help", renderHelp)
    79 router.HandleFunc("admin-users", renderMembers)
    80 router.HandleFunc("create-board", renderCreateBoard)
    81 router.HandleFunc("{board}", renderBoard)
    82 router.HandleFunc("{board}/members", renderMembers)
    83 router.HandleFunc("{board}/invites", renderInvites)
    84 router.HandleFunc("{board}/banned-users", renderBannedUsers)
    85 router.HandleFunc("{board}/create-thread", renderCreateThread)
    86 router.HandleFunc("{board}/invite-member", renderInviteMember)
    87 router.HandleFunc("{board}/{thread}", renderThread)
    88 router.HandleFunc("{board}/{thread}/flag", renderFlagPost)
    89 router.HandleFunc("{board}/{thread}/flagging-reasons", renderFlaggingReasonsPost)
    90 router.HandleFunc("{board}/{thread}/reply", renderReplyPost)
    91 router.HandleFunc("{board}/{thread}/edit", renderEditThread)
    92 router.HandleFunc("{board}/{thread}/repost", renderRepostThread)
    93 router.HandleFunc("{board}/{thread}/{reply}", renderReply)
    94 router.HandleFunc("{board}/{thread}/{reply}/flag", renderFlagPost)
    95 router.HandleFunc("{board}/{thread}/{reply}/flagging-reasons", renderFlaggingReasonsPost)
    96 router.HandleFunc("{board}/{thread}/{reply}/reply", renderReplyPost)
    97 router.HandleFunc("{board}/{thread}/{reply}/edit", renderEditReply)
    98
    99 router.NotFoundHandler = func(res *mux.ResponseWriter, _ *mux.Request) {
    100 res.Write(md.Blockquote("Path not found"))
    101 }
    102
    103 // Render common realm header before resolving render path
    104 if Notice != "" {
    105 b.WriteString(infoAlert("Notice", Notice))
    106 }
    107
    108 // Render view for current path
    109 b.WriteString(router.Render(path))
    110
    111 return b.String()
    112}
    113
    114func renderHelp(res *mux.ResponseWriter, _ *mux.Request) {
    115 res.Write(md.H1("Boards Help"))
    116 if Help != "" {
    117 res.Write(Help)
    118 return
    119 }
    120
    121 link := RealmLink.Call("SetHelp", "content", "")
    122 res.Write(md.H3("Help content has not been uploaded"))
    123 res.Write("Do you want to " + md.Link("upload boards help", link) + "?")
    124}
    125
    126func renderBoardsList(res *mux.ResponseWriter, req *mux.Request) {
    127 res.Write(md.H1("Boards"))
    128 renderBoardListMenu(res, req)
    129 res.Write(md.HorizontalRule())
    130
    131 if gListedBoardsByID.Size() == 0 {
    132 res.Write(md.H3("Currently there are no boards"))
    133 res.Write("Be the first to " + md.Link("create a new board", createBoardURI) + "!")
    134 return
    135 }
    136
    137 p := newClampedPager(req.RawPath, gListedBoardsByID.Size(), pageSizeDefault)
    138
    139 render := func(_ string, v any) bool {
    140 board := v.(*boards.Board)
    141 userLink := userLink(board.Creator)
    142 date := board.CreatedAt.Format(dateFormat)
    143
    144 res.Write(md.H6(md.Link(board.Name, makeBoardURI(board))))
    145 res.Write("Created by " + userLink + " on " + date + ", #" + board.ID.String() + " \n")
    146
    147 status := strconv.Itoa(board.Threads.Size()) + " threads"
    148 if board.Readonly {
    149 status += ", read-only"
    150 }
    151
    152 res.Write(md.Bold(status) + "\n\n")
    153 return false
    154 }
    155
    156 res.Write("Sort by: ")
    157 link, desc := sortToggleLink(req.RawPath)
    158 res.Write(link + "\n\n")
    159 if desc {
    160 gListedBoardsByID.ReverseIterateByOffset(p.Offset(), p.PageSize(), render)
    161 } else {
    162 gListedBoardsByID.IterateByOffset(p.Offset(), p.PageSize(), render)
    163 }
    164
    165 if p.HasPages() {
    166 res.Write(md.HorizontalRule())
    167 res.Write(pager.Picker(p))
    168 }
    169}
    170
    171func renderBoardListMenu(res *mux.ResponseWriter, req *mux.Request) {
    172 res.Write(md.Link("Create Board", createBoardURI))
    173 res.Write(" • ")
    174 res.Write(md.Link("List Admin Users", adminUsersURI))
    175 res.Write(" • ")
    176 res.Write(md.Link("Help", helpURI))
    177 res.Write("\n\n")
    178}
    179
    180func renderCreateBoard(res *mux.ResponseWriter, _ *mux.Request) {
    181 form := mdform.New("exec", "CreateBoard")
    182 form.Input(
    183 "name",
    184 "placeholder", "Board name",
    185 "required", "true",
    186 )
    187 form.Radio(
    188 "listed",
    189 "true",
    190 "checked", "true",
    191 "description", "Should board be publicly listed?",
    192 )
    193 form.Radio(
    194 "listed",
    195 "false",
    196 )
    197 form.Radio(
    198 "open",
    199 "true",
    200 "description", "Should anyone be allowed to create threads and comments?",
    201 )
    202 form.Radio(
    203 "open",
    204 "false",
    205 "checked", "true",
    206 )
    207
    208 res.Write(md.H1("Boards: Create Board"))
    209 res.Write(md.Link("← Back to boards", gRealmPath) + "\n\n")
    210 res.Write(
    211 md.Paragraph(
    212 "Boards are by default listed by the realm but they can optionally " +
    213 "be created so they are only found by their URL.",
    214 ),
    215 )
    216 res.Write(
    217 md.Paragraph(
    218 "They can also be created to be open so anyone is allowed to create " +
    219 "new threads and also to comment on any thread within the open board.",
    220 ),
    221 )
    222 res.Write(form.String())
    223 res.Write("\n\n**Done?** " + svgbtn.ButtonWithRadius(136, 32, 4, "#E2E2E2", "#54595D", "Return to boards", gRealmPath) + "\n")
    224}
    225
    226func renderMembers(res *mux.ResponseWriter, req *mux.Request) {
    227 boardID := boards.ID(0)
    228 perms := gPerms
    229 name := req.GetVar("board")
    230 if name != "" {
    231 board, found := gBoards.GetByName(name)
    232 if !found {
    233 res.Write(md.H3("Board not found"))
    234 return
    235 }
    236
    237 boardID = board.ID
    238 perms = board.Permissions
    239
    240 res.Write(md.H1(board.Name + " Members"))
    241 res.Write(md.H3("These are the board members"))
    242 } else {
    243 res.Write(md.H1("Admin Users"))
    244 res.Write(md.H3("These are the admin users of the realm"))
    245 }
    246
    247 // Create a pager with a small page size to reduce
    248 // the number of username lookups per page.
    249 p := newClampedPager(req.RawPath, perms.UsersCount(), pageSizeDefault)
    250
    251 table := mdtable.Table{
    252 Headers: []string{"Member", "Role", "Actions"},
    253 }
    254
    255 perms.IterateUsers(p.Offset(), p.PageSize(), func(u boards.User) bool {
    256 actions := []string{
    257 md.Link("remove", RealmLink.Call(
    258 "RemoveMember",
    259 "boardID", boardID.String(),
    260 "member", u.Address.String(),
    261 )),
    262 md.Link("change role", RealmLink.Call(
    263 "ChangeMemberRole",
    264 "boardID", boardID.String(),
    265 "member", u.Address.String(),
    266 "role", "",
    267 )),
    268 }
    269
    270 table.Append([]string{
    271 userLink(u.Address),
    272 rolesToString(u.Roles),
    273 strings.Join(actions, " • "),
    274 })
    275 return false
    276 })
    277 res.Write(table.String())
    278
    279 if p.HasPages() {
    280 res.Write("\n" + pager.Picker(p))
    281 }
    282}
    283
    284func renderInvites(res *mux.ResponseWriter, req *mux.Request) {
    285 name := req.GetVar("board")
    286 board, found := gBoards.GetByName(name)
    287 if !found {
    288 res.Write(md.H3("Board not found"))
    289 return
    290 }
    291
    292 res.Write(md.H1(board.Name + " Invite Requests"))
    293
    294 requests, found := getInviteRequests(board.ID)
    295 if !found || requests.Size() == 0 {
    296 res.Write(md.H3("Board has no invite requests"))
    297 return
    298 }
    299
    300 p := newClampedPager(req.RawPath, requests.Size(), pageSizeDefault)
    301
    302 table := mdtable.Table{
    303 Headers: []string{"User", "Request Date", "Actions"},
    304 }
    305
    306 res.Write(md.H3("These users have requested to be invited to the board"))
    307 requests.ReverseIterateByOffset(p.Offset(), p.PageSize(), func(addr string, v any) bool {
    308 actions := []string{
    309 md.Link("accept", RealmLink.Call(
    310 "AcceptInvite",
    311 "boardID", board.ID.String(),
    312 "user", addr,
    313 )),
    314 md.Link("revoke", RealmLink.Call(
    315 "RevokeInvite",
    316 "boardID", board.ID.String(),
    317 "user", addr,
    318 )),
    319 }
    320
    321 table.Append([]string{
    322 userLink(address(addr)),
    323 v.(time.Time).Format(dateFormat),
    324 strings.Join(actions, " • "),
    325 })
    326 return false
    327 })
    328
    329 res.Write(table.String())
    330
    331 if p.HasPages() {
    332 res.Write("\n" + pager.Picker(p))
    333 }
    334}
    335
    336func renderBannedUsers(res *mux.ResponseWriter, req *mux.Request) {
    337 name := req.GetVar("board")
    338 board, found := gBoards.GetByName(name)
    339 if !found {
    340 res.Write(md.H3("Board not found"))
    341 return
    342 }
    343
    344 res.Write(md.H1(board.Name + " Banned Users"))
    345
    346 banned, found := getBannedUsers(board.ID)
    347 if !found || banned.Size() == 0 {
    348 res.Write(md.H3("Board has no banned users"))
    349 return
    350 }
    351
    352 p := newClampedPager(req.RawPath, banned.Size(), pageSizeDefault)
    353
    354 table := mdtable.Table{
    355 Headers: []string{"User", "Banned Until", "Actions"},
    356 }
    357
    358 res.Write(md.H3("These users have been banned from the board"))
    359 banned.ReverseIterateByOffset(p.Offset(), p.PageSize(), func(addr string, v any) bool {
    360 table.Append([]string{
    361 userLink(address(addr)),
    362 v.(time.Time).Format(dateFormat),
    363 md.Link("unban", RealmLink.Call(
    364 "Unban",
    365 "boardID", board.ID.String(),
    366 "user", addr,
    367 "reason", "",
    368 )),
    369 })
    370 return false
    371 })
    372
    373 res.Write(table.String())
    374
    375 if p.HasPages() {
    376 res.Write("\n" + pager.Picker(p))
    377 }
    378}
    379
    380func infoAlert(title, msg string) string {
    381 header := strings.TrimSpace("[!INFO] " + title)
    382 return md.Blockquote(header + "\n" + msg)
    383}
    384
    385func rolesToString(roles []boards.Role) string {
    386 if len(roles) == 0 {
    387 return ""
    388 }
    389
    390 names := make([]string, len(roles))
    391 for i, r := range roles {
    392 names[i] = string(r)
    393 }
    394 return strings.Join(names, ", ")
    395}
    396
    397func menuURL(name string) string {
    398 // TODO: Menu URL works because no other GET arguments are being used
    399 return "?menu=" + name
    400}
    401
    402func getCurrentMenu(rawURL string) string {
    403 _, rawQuery, found := strings.Cut(rawURL, "?")
    404 if !found {
    405 return ""
    406 }
    407
    408 query, _ := url.ParseQuery(rawQuery)
    409 return query.Get("menu")
    410}
    411