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