public_ban.gno
2.85 Kb ยท 117 lines
1package boards2
2
3import (
4 "chain"
5 "chain/runtime"
6 "strings"
7 "time"
8
9 "gno.land/p/gnoland/boards"
10 "gno.land/p/nt/avl"
11)
12
13// Constants for different banning periods.
14const (
15 BanDay = uint(24)
16 BanWeek = BanDay * 7
17 BanYear = BanDay * 365
18)
19
20// Ban bans a user from a board for a period of time.
21// Only invited guest members and external users can be banned.
22// Banning board owners, admins and moderators is not allowed.
23func Ban(_ realm, boardID boards.ID, user address, hours uint, reason string) {
24 assertAddressIsValid(user)
25
26 if hours == 0 {
27 panic("ban period in hours is required")
28 }
29
30 reason = strings.TrimSpace(reason)
31 if reason == "" {
32 panic("ban reason is required")
33 }
34
35 board := mustGetBoard(boardID)
36 caller := runtime.PreviousRealm().Address()
37 until := time.Now().Add(time.Minute * 60 * time.Duration(hours))
38 args := boards.Args{boardID, user, until, reason}
39 board.Permissions.WithPermission(cross, caller, PermissionUserBan, args, func(realm) {
40 // When banning invited members make sure they are guests, otherwise
41 // disallow banning. Only guest or external users can be banned.
42 if board.Permissions.HasUser(user) && !board.Permissions.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", board.ID.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 boards.ID, user address, reason string) {
67 assertAddressIsValid(user)
68
69 board := mustGetBoard(boardID)
70 caller := runtime.PreviousRealm().Address()
71 args := boards.Args{boardID, user, reason}
72 board.Permissions.WithPermission(cross, caller, PermissionUserUnban, args, func(realm) {
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", board.ID.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 boards.ID, 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 boards.ID, 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}