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