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}