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}