Skip to content

Conversation

migmartri
Copy link
Member

@migmartri migmartri commented Oct 30, 2023

First cut of an invite system where a user can invite others to join a given organization. Closes #401

  • Senders can create, revoke, and list sent invitations.
  • Receivers, on login, will get added to their invited organization automatically.

NOTE: The auto-acceptance mechanism is just a first pass to simplify the implementation. In the future, we'll give control to the receiver to accept or decline offers explicitly #401. For now, we think this is okay because users are usually invited withing their own Chainloop instance

CLI Changes

Org Invite commands

$ chainloop org invite
User Invitations management

Usage:
  chainloop organization invite [command]

Aliases:
  invite, invitations

Available Commands:
  create      Invite a User to an Organization
  revoke      Revoke a pending invitation
  sent        List sent invitations
$ chainloop org invite sent
┌──────────────────────────────────────┬────────────────────┬───────────────────────┬──────────┬─────────────────────┐
│ ID                                   │ ORG NAME           │ RECEIVER EMAIL        │ STATUS   │ CREATED AT          │
├──────────────────────────────────────┼────────────────────┼───────────────────────┼──────────┼─────────────────────┤
│ 19c33588-ab57-4251-8518-e48f99d70472 │ flamboyant_jemison │ sarah@chainloop.local │ accepted │ 30 Oct 23 20:44 UTC │
├──────────────────────────────────────┼────────────────────┼───────────────────────┼──────────┼─────────────────────┤
│ 880da13c-3ae1-4ec0-9e87-0ae4eafe8e09 │ flamboyant_jemison │ foo@gmail.com         │ pending  │ 31 Oct 23 11:20 UTC │
└──────────────────────────────────────┴────────────────────┴───────────────────────┴──────────┴─────────────────────┘
$ chainloop org invite create --receiver dyson@cyberdyne.io --organization 1ac42a05-b909-4c0d-bb98-14c532e42dfc 
┌──────────────────────────────────────┬────────────────────┬────────────────────┬─────────┬─────────────────────┐
│ ID                                   │ ORG NAME           │ RECEIVER EMAIL     │ STATUS  │ CREATED AT          │
├──────────────────────────────────────┼────────────────────┼────────────────────┼─────────┼─────────────────────┤
│ a91f36eb-ff94-453b-ba15-d05385697aea │ flamboyant_jemison │ dyson@cyberdyne.io │ pending │ 31 Oct 23 11:28 UTC │
└──────────────────────────────────────┴────────────────────┴────────────────────┴─────────┴─────────────────────┘
$ chainloop org invite revoke --id 880da13c-3ae1-4ec0-9e87-0ae4eafe8e09
INF Invite Revoked!

biz layer

Creation logic

The handler implementation will a) run static validations, b) check if the user has permission to invite to the given org, c) check that an invitation doesn't exist already, and 4) create an entry in the DB in a pending state.

Revocation logic, in fact, will soft-delete the item by setting a deleted_at timestamp.

Auto-acceptance logic

An user, on login will get automatically added to the organizations they have been invited to. These will appear in the org list command

$ chainloop org ls                                                                              
┌──────────────────────────────────────┬────────────────────┬─────────┬─────────────────────┐
│ ORG ID                               │ ORG NAME           │ CURRENT │ JOINED AT           │
├──────────────────────────────────────┼────────────────────┼─────────┼─────────────────────┤
│ 46c1ae14-5c64-4e87-8f7f-cff4de9cfca5 │ magical_solomon    │ true    │ 30 Oct 23 20:44 UTC │
├──────────────────────────────────────┼────────────────────┼─────────┼─────────────────────┤
│ 1ac42a05-b909-4c0d-bb98-14c532e42dfc │ flamboyant_jemison │ false   │ 30 Oct 23 20:44 UTC │
└──────────────────────────────────────┴────────────────────┴─────────┴─────────────────────┘

Which then can be chosen using chainloop org set --id ...

data layer

It adds an org_invites persistence table.

image

Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
@migmartri migmartri marked this pull request as ready for review October 31, 2023 11:40
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Copy link
Member Author

@migmartri migmartri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for reviewers. I left some comments in the PR as guidance of what's worth reviewing and not autogenerated.

Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Copy link
Member

@danlishka danlishka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make sure we validate deleted_at before creating a membership. Apart from that LGTM!


func newOrganizationInvitationSentCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "sent",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just list like we do in other places?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I didn't want to put list is so it doesn't get confused with listing all invitations for an org, since this command returns only the invites,you as an user sent.

In any case, I've renamed it to list and made it clear in the description of the command what it does.

Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was about to post a similar comment, even though not quite the same.

If we use sent, maybe instead of "creating" and invite, we "send" it


// user is not a member of the org, create the membership
if !alreadyMember {
uc.logger.Infow("msg", "Adding member", "invite_id", invite.ID.String(), "org_id", invite.Org.ID, "user_id", user.ID)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we checking deleted_at?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The invites queries skip automatically the deleted entries..

https://github.com/chainloop-dev/chainloop/pull/404/files#diff-1d9d80f114bb28dba41c49e4c69ca79251075b74ddade6f6400d8f61a232ae30R95

So invites, err := uc.repo.PendingInvites(ctx, receiverEmail) will skip those

Is that the deletedAt you were talking about, or any other soft-deleted entity?

Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
@migmartri migmartri merged commit f92c4c3 into chainloop-dev:main Oct 31, 2023
@migmartri migmartri deleted the invite-system branch October 31, 2023 13:51
Copy link
Contributor

@buccarel buccarel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Organization invitations system
3 participants