public_invite.gno
3.70 Kb ยท 151 lines
1package boards2
2
3import (
4 "std"
5 "time"
6
7 "gno.land/p/nt/avl"
8)
9
10// InviteMember adds a member to the realm or to a boards.
11//
12// A role can optionally be specified to be assigned to the new member.
13// Board ID is only required when inviting a member to a board.
14func InviteMember(_ realm, boardID BoardID, user std.Address, role Role) {
15 assertUserAddressIsValid(user)
16 assertMembersUpdateIsEnabled(boardID)
17
18 perms := mustGetPermissions(boardID)
19 if perms.HasUser(user) {
20 panic("user is already a member")
21 }
22
23 caller := std.PreviousRealm().Address()
24 args := Args{caller, boardID, user, role}
25 perms.WithPermission(cross, caller, PermissionMemberInvite, args, func(realm, Args) {
26 assertMembersUpdateIsEnabled(boardID)
27
28 if perms.HasUser(user) {
29 panic("user is already a member")
30 }
31
32 if err := perms.SetUserRoles(cross, user, role); err != nil {
33 panic(err)
34 }
35
36 std.Emit(
37 "MemberInvited",
38 "invitedBy", caller.String(),
39 "boardID", boardID.String(),
40 "user", user.String(),
41 "role", string(role),
42 )
43 })
44}
45
46// RequestInvite request to be invited to a board.
47func RequestInvite(_ realm, boardID BoardID) {
48 assertMembersUpdateIsEnabled(boardID)
49
50 if !std.PreviousRealm().IsUser() {
51 panic("caller must be user")
52 }
53
54 // TODO: Request a fee (returned on accept) or registered user to avoid spam?
55 // TODO: Make open invite requests optional (per board)
56
57 board := mustGetBoard(boardID)
58 user := std.PreviousRealm().Address()
59 if board.perms.HasUser(user) {
60 panic("caller is already a member")
61 }
62
63 invitee := user.String()
64 requests, found := getInviteRequests(boardID)
65 if !found {
66 requests = avl.NewTree()
67 requests.Set(invitee, time.Now())
68 gInviteRequests.Set(boardID.Key(), requests)
69 return
70 }
71
72 if requests.Has(invitee) {
73 panic("invite request already exists")
74 }
75
76 requests.Set(invitee, time.Now())
77}
78
79// AcceptInvite accepts a board invite request.
80func AcceptInvite(_ realm, boardID BoardID, user std.Address) {
81 assertMembersUpdateIsEnabled(boardID)
82 assertInviteRequestExists(boardID, user)
83
84 board := mustGetBoard(boardID)
85 if board.perms.HasUser(user) {
86 panic("user is already a member")
87 }
88
89 caller := std.PreviousRealm().Address()
90 args := Args{caller, boardID, user, RoleGuest}
91 board.perms.WithPermission(cross, caller, PermissionMemberInvite, args, func(realm, Args) {
92 assertMembersUpdateIsEnabled(boardID)
93
94 invitee := user.String()
95 requests, found := getInviteRequests(boardID)
96 if !found || !requests.Has(invitee) {
97 panic("invite request not found")
98 }
99
100 board := mustGetBoard(boardID)
101 if board.perms.HasUser(user) {
102 panic("user is already a member")
103 }
104
105 if err := board.perms.SetUserRoles(cross, user); err != nil {
106 panic(err)
107 }
108
109 requests.Remove(invitee)
110
111 std.Emit(
112 "MemberInvited",
113 "invitedBy", caller.String(),
114 "boardID", boardID.String(),
115 "user", user.String(),
116 )
117 })
118}
119
120// RevokeInvite revokes a board invite request.
121func RevokeInvite(_ realm, boardID BoardID, user std.Address) {
122 assertInviteRequestExists(boardID, user)
123
124 board := mustGetBoard(boardID)
125 caller := std.PreviousRealm().Address()
126 args := Args{boardID, user, RoleGuest}
127 board.perms.WithPermission(cross, caller, PermissionMemberInviteRevoke, args, func(realm, Args) {
128 invitee := user.String()
129 requests, found := getInviteRequests(boardID)
130 if !found || !requests.Has(invitee) {
131 panic("invite request not found")
132 }
133
134 requests.Remove(invitee)
135
136 std.Emit(
137 "InviteRevoked",
138 "revokedBy", caller.String(),
139 "boardID", boardID.String(),
140 "user", user.String(),
141 )
142 })
143}
144
145func assertInviteRequestExists(boardID BoardID, user std.Address) {
146 invitee := user.String()
147 requests, found := getInviteRequests(boardID)
148 if !found || !requests.Has(invitee) {
149 panic("invite request not found")
150 }
151}