public_ban.gno
2.81 Kb · 116 lines
1package boards2
2
3import (
4 "chain"
5 "strings"
6 "time"
7
8 "gno.land/p/gnoland/boards"
9 "gno.land/p/nt/bptree/v0"
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(cur realm, boardID boards.ID, 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 := cur.Previous().Address()
36 until := time.Now().Add(time.Minute * 60 * time.Duration(hours))
37 args := boards.Args{boardID, user, until, reason}
38 board.Permissions.WithPermission(caller, PermissionUserBan, args, func() {
39 // When banning invited members make sure they are guests, otherwise
40 // disallow banning. Only guest or external users can be banned.
41 if board.Permissions.HasUser(user) && !board.Permissions.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 = bptree.NewBPTree32()
48 gBannedUsers.Set(boardID.Key(), banned)
49 }
50
51 banned.Set(user.String(), until)
52
53 chain.Emit(
54 "UserBanned",
55 "bannedBy", caller.String(),
56 "boardID", board.ID.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(cur realm, boardID boards.ID, user address, reason string) {
66 assertAddressIsValid(user)
67
68 board := mustGetBoard(boardID)
69 caller := cur.Previous().Address()
70 args := boards.Args{boardID, user, reason}
71 board.Permissions.WithPermission(caller, PermissionUserUnban, args, func() {
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 chain.Emit(
80 "UserUnbanned",
81 "bannedBy", caller.String(),
82 "boardID", board.ID.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 boards.ID, user address) bool {
91 banned, found := getBannedUsers(boardID)
92 return found && banned.Has(user.String())
93}
94
95func assertAddressIsValid(addr address) {
96 if !addr.IsValid() {
97 panic("invalid address: " + addr.String())
98 }
99}
100
101func assertUserIsNotBanned(boardID boards.ID, user 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}