public_ban.gno

2.79 Kb ยท 117 lines
  1package boards2
  2
  3import (
  4	"chain"
  5	"chain/runtime"
  6	"strings"
  7	"time"
  8
  9	"gno.land/p/nt/avl"
 10)
 11
 12// Constants for different banning periods.
 13const (
 14	BanDay  = uint(24)
 15	BanWeek = BanDay * 7
 16	BanYear = BanDay * 365
 17)
 18
 19// Ban bans a user from a board for a period of time.
 20// Only invited guest members and external users can be banned.
 21// Banning board owners, admins and moderators is not allowed.
 22func Ban(_ realm, boardID BoardID, user address, hours uint, reason string) {
 23	assertAddressIsValid(user)
 24
 25	if hours == 0 {
 26		panic("ban period in hours is required")
 27	}
 28
 29	reason = strings.TrimSpace(reason)
 30	if reason == "" {
 31		panic("ban reason is required")
 32	}
 33
 34	board := mustGetBoard(boardID)
 35	caller := runtime.PreviousRealm().Address()
 36	until := time.Now().Add(time.Minute * 60 * time.Duration(hours))
 37	args := Args{boardID, user, until, reason}
 38	board.perms.WithPermission(caller, PermissionUserBan, args, func(Args) {
 39		// When banning invited members make sure they are guests, otherwise
 40		// disallow banning. Only guest or external users can be banned.
 41		board := mustGetBoard(boardID)
 42		if board.perms.HasUser(user) && !board.perms.HasRole(user, RoleGuest) {
 43			panic("owner, admin and moderator banning is not allowed")
 44		}
 45
 46		banned, found := getBannedUsers(boardID)
 47		if !found {
 48			banned = avl.NewTree()
 49			gBannedUsers.Set(boardID.Key(), banned)
 50		}
 51
 52		banned.Set(user.String(), until)
 53
 54		chain.Emit(
 55			"UserBanned",
 56			"bannedBy", caller.String(),
 57			"boardID", boardID.String(),
 58			"user", user.String(),
 59			"until", until.Format(time.RFC3339),
 60			"reason", reason,
 61		)
 62	})
 63}
 64
 65// Unban unbans a user from a board.
 66func Unban(_ realm, boardID BoardID, user address, reason string) {
 67	assertAddressIsValid(user)
 68
 69	board := mustGetBoard(boardID)
 70	caller := runtime.PreviousRealm().Address()
 71	args := Args{boardID, user, reason}
 72	board.perms.WithPermission(caller, PermissionUserUnban, args, func(Args) {
 73		banned, found := getBannedUsers(boardID)
 74		if !found || !banned.Has(user.String()) {
 75			panic("user is not banned")
 76		}
 77
 78		banned.Remove(user.String())
 79
 80		chain.Emit(
 81			"UserUnbanned",
 82			"bannedBy", caller.String(),
 83			"boardID", boardID.String(),
 84			"user", user.String(),
 85			"reason", reason,
 86		)
 87	})
 88}
 89
 90// IsBanned checks if a user is banned from a board.
 91func IsBanned(boardID BoardID, user address) bool {
 92	banned, found := getBannedUsers(boardID)
 93	return found && banned.Has(user.String())
 94}
 95
 96func assertAddressIsValid(addr address) {
 97	if !addr.IsValid() {
 98		panic("invalid address: " + addr.String())
 99	}
100}
101
102func assertUserIsNotBanned(boardID BoardID, user address) {
103	banned, found := getBannedUsers(boardID)
104	if !found {
105		return
106	}
107
108	v, found := banned.Get(user.String())
109	if !found {
110		return
111	}
112
113	until := v.(time.Time)
114	if time.Now().Before(until) {
115		panic(user.String() + " is banned until " + until.Format(dateFormat))
116	}
117}