Skip to content
This repository was archived by the owner on Feb 28, 2021. It is now read-only.

Add a member to an org#450

Merged
MeBrei merged 1 commit intoupstreamfrom
merle/add-member
May 20, 2020
Merged

Add a member to an org#450
MeBrei merged 1 commit intoupstreamfrom
merle/add-member

Conversation

@MeBrei
Copy link
Copy Markdown
Contributor

@MeBrei MeBrei commented May 13, 2020

Add the functionality to add a member to an existing org.

Todos:

  • add more runtime tests
    • bad author scenario, where the said author would pay the fee
    • no org scenario, where the said author would pay the fee
    • no user associated scenario, where the said author would pay the fee
  • add end-to-end tests
  • add cli functionality
  • error out if an existing member is added again

In a follow up, the functionality to remove a member should be added

@MeBrei MeBrei requested a review from xla May 13, 2020 11:17
@xla xla changed the base branch from master to upstream May 13, 2020 11:19
@MeBrei MeBrei self-assigned this May 13, 2020
Copy link
Copy Markdown
Contributor

@NunoAlexandre NunoAlexandre left a comment

Choose a reason for hiding this comment

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

My preemptive look 👍

Going great so far!

One remark: The new message is called RegisterMember, which I find confusing. It's not really registering a user, it's adding an existing user to the members of an org. I would, therefore, prefer to call it "AddOrgMember", which will also be less likely to collide with future messages. Note how the fn you added to Org is named add_member already.

Edit: @cloudhead I see that the spec calls it comes from the spec, 3.3 register-member.

pub user_id: Id,
}

/// Register a member of an org on the Radicle Registry with the given ID.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// Register a member of an org on the Radicle Registry with the given ID.
/// Register a member of an org with the given ID.

It is unclear which entity the ID is referring to though, in both versions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is why I advised to name it handle to make it clear that it is a user.

///
#[derive(Decode, Encode, Clone, Debug, Eq, PartialEq)]
pub struct RegisterMember {
// The member to register, unique in the org.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is the "unique in the org" necessary? For a moment I wondered if that was actually a state-dependent validation. Is it? If it isn't, then I would drop this bit here since Ids are already unique in nature. If it is, then we should have that under the state-dependent validations above.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Isn't this to express that the member can only be registered once per org? Making the tuple (org_id, user_handle) unique?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

it's referring to the member being unique within the org, ie a member can't be added twice

Copy link
Copy Markdown
Contributor

@xla xla left a comment

Choose a reason for hiding this comment

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

Great stuffz! Would distinct handle from other ids and more inline.

@xla
Copy link
Copy Markdown
Contributor

xla commented May 13, 2020

One remark: The new message is called RegisterMember, which I find confusing. It's not really registering a user, it's adding an existing user to the members of an org. I would, therefore, prefer to call it "AddOrgMember", which will also be less likely to collide with future messages. Note how the fn you added to Org is named add_member already.

Edit: @cloudhead I see that the spec calls it comes from the spec, 3.3 register-member.

Semantically registering a member is correct, as it is with org, user and (org/user, projectname) a unique entry in the registry. We don't need to qualify with Org here as there is no other concept of member and the add_member fn is for adding to the actual list, not about the external API.

@NunoAlexandre
Copy link
Copy Markdown
Contributor

One remark: The new message is called RegisterMember, which I find confusing. It's not really registering a user, it's adding an existing user to the members of an org. I would, therefore, prefer to call it "AddOrgMember", which will also be less likely to collide with future messages. Note how the fn you added to Org is named add_member already.
Edit: @cloudhead I see that the spec calls it comes from the spec, 3.3 register-member.

Semantically registering a member is correct, as it is with org, user and (org/user, projectname) a unique entry in the registry. We don't need to qualify with Org here as there is no other concept of member and the add_member fn is for adding to the actual list, not about the external API.

I don't disagree with you, but present "register member" to an org vs "add member" to an org to any number of users and I am pretty sure which one will be simpler to understand.

@xla
Copy link
Copy Markdown
Contributor

xla commented May 13, 2020

I don't disagree with you, but present "register member" to an org vs "add member" to an org to any number of users and I am pretty sure which one will be simpler to understand.

In this context we are talking about the semantics of the chain and not what is presented to the user in the UI.

@NunoAlexandre
Copy link
Copy Markdown
Contributor

I don't disagree with you, but present "register member" to an org vs "add member" to an org to any number of users and I am pretty sure which one will be simpler to understand.

In this context we are talking about the semantics of the chain and not what is presented to the user in the UI.

I know :) But why have two terminologies when "add member" works for both audiences? While registering an org / project / user actually registers new entities into the chain, "register a member" simply links two entities that are already registered.

@xla
Copy link
Copy Markdown
Contributor

xla commented May 19, 2020

Part of radicle-dev/radicle-upstream#349

@MeBrei
Copy link
Copy Markdown
Contributor Author

MeBrei commented May 19, 2020

I don't disagree with you, but present "register member" to an org vs "add member" to an org to any number of users and I am pretty sure which one will be simpler to understand.

In this context we are talking about the semantics of the chain and not what is presented to the user in the UI.

I know :) But why have two terminologies when "add member" works for both audiences? While registering an org / project / user actually registers new entities into the chain, "register a member" simply links two entities that are already registered.

How can we come to a decision on this discussion? @NunoAlexandre @xla @cloudhead

@MeBrei MeBrei marked this pull request as ready for review May 20, 2020 07:45
@NunoAlexandre NunoAlexandre self-requested a review May 20, 2020 08:47
Copy link
Copy Markdown
Contributor

@NunoAlexandre NunoAlexandre left a comment

Choose a reason for hiding this comment

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

Looking great, @MeBrei! 🚀

I left some comments but mostly small stuff.

Register(Register),
/// Unregister an org.
Unregister(Unregister),
/// Register a new member under the org.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// Register a new member under the org.
/// Register a new member under an org.


register_member_fut.await?.result?;
println!(
"✓ User {} is now registered under Org {}.",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
"✓ User {} is now registered under Org {}.",
"✓ User {} is now a member of the Org {}.",

assert_eq!(org_registered_tx.result, Ok(()));

// The org needs funds to submit transactions.
let org = client.get_org(org_id.clone()).await.unwrap().unwrap();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

since we already get the org here, it wouldn't hurt to assert that it does not contain user_id in its list of members at this point.

);

let org: Org = client.get_org(org_id.clone()).await.unwrap().unwrap();
assert!(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would still prefer the check here to be more specific and check that the org now has two members, the author user which registered it and this new user_id.


#[cfg_attr(
feature = "std",
error("a member with the same ID already exists within the org.")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion:

Suggested change
error("a member with the same ID already exists within the org.")
error("already a member of the org")

Copy link
Copy Markdown
Contributor

@NunoAlexandre NunoAlexandre May 20, 2020

Choose a reason for hiding this comment

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

to be clear, this was just a suggestion, since DuplicateMember could reflect that the vec Org::members has duplicates, when the error is to say "you are trying to add a user to the members of an org but they are already a member".

That said, if we go ahead with this change, I'd suggest extending the error message to this, (sorry for the double comment):

error("the user is already a member of the org")

};
let tx_applied = submit_ok(&client, &author, message.clone()).await;

assert_eq!(tx_applied.result, Err(RegistryError::InexistentOrg.into()));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We need to check that author has paid the tx fee

}

#[async_std::test]
async fn register_nonexistent_member() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I got confused with the name for a sec, maybe:

Suggested change
async fn register_nonexistent_member() {
async fn register_nonexistent_user() {

return Err(RegistryError::InsufficientSenderPermissions.into());
}

if None == store::Users::get(message.user_id.clone()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
if None == store::Users::get(message.user_id.clone()) {
if store::Users::get(message.user_id.clone()).is_none() {

return Err(RegistryError::DuplicateMember.into());
}

store::Orgs::insert(message.org_id.clone(), org.add_member(message.user_id.clone()));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We mostly try to separate such lines, like so:

Suggested change
store::Orgs::insert(message.org_id.clone(), org.add_member(message.user_id.clone()));
let org_with_member = org.add_member(message.user_id.clone());
store::Orgs::insert(message.org_id.clone(), org_with_member);

pub enum Event {
CheckpointCreated(CheckpointId),
CheckpointSet(ProjectName, Id, CheckpointId),
MemberRegistered(Id, Id),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Forgot this one! Since the types are ambiguous, I'd rather change this to:

Suggested change
MemberRegistered(Id, Id),
MemberRegistered { user_id: Id, org_id: Id },

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

seems like the macro does not support variants with named fields :/

@geigerzaehler geigerzaehler self-requested a review May 20, 2020 09:59
@geigerzaehler
Copy link
Copy Markdown

@MeBrei: Could you ping me once this is ready? I’d also like to have a brief look at this

Copy link
Copy Markdown
Contributor

@NunoAlexandre NunoAlexandre left a comment

Choose a reason for hiding this comment

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

Awesome 🚀

just a comment left from me: #450 (comment)

Copy link
Copy Markdown

@geigerzaehler geigerzaehler left a comment

Choose a reason for hiding this comment

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

Great work 🎆 Just two requests to make the documentation comprehensive.

///
/// The identified org must exit.
///
/// A user associated with the author must exist.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Two validations are missing

  • The user user_id must exist
  • user_id must not already be a member of the org.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two validations are missing

  • The user user_id must exist

It says already:

A user associated with the author must exist.

we could change that to:

A user associated with the author must exist and be identified by user_id

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Isn’t the user associated with the author different from user_id?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes, will change it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

changed in 8322c12


/// Register a new member for an org on the Registry with the given user ID.
///
/// # State-dependent validations
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Could you also list the state changes?

/// # State changes
/// If successful, `user_id` is added to [Org::members] of `org_id`.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added in 8322c12

Copy link
Copy Markdown
Contributor

@xla xla left a comment

Choose a reason for hiding this comment

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

🔹 💜 ⤴️ 💈

Copy link
Copy Markdown

@geigerzaehler geigerzaehler left a comment

Choose a reason for hiding this comment

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

👏

Co-authored-by: Nuno Alexandre <hi@nunoalexandre.com>
Co-authored-by: Alexander Simmerl <a.simmerl@gmail.com>
@MeBrei MeBrei force-pushed the merle/add-member branch from 61a33a8 to 59b7fa0 Compare May 20, 2020 16:02
@MeBrei MeBrei merged commit 2bf1b82 into upstream May 20, 2020
@MeBrei MeBrei deleted the merle/add-member branch May 20, 2020 16:15
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants