Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User typeahead enabled for non-admin project managers #1237

Open
wants to merge 19 commits into
base: develop
Choose a base branch
from

Conversation

rmunn
Copy link
Contributor

@rmunn rmunn commented Nov 14, 2024

Fix #1152.

This PR adds a new usersICanSee GQL query, which looks for:

  • All users in one of my orgs
  • All users in one of the projects I manage
  • All users in one of the non-confidential projects I'm a member of

The "Add Project Member" typeahead is now updated to use that query, which allows project managers who aren't site admins to use the typeahead to find users whose email address they don't know. E.g. if Test Manager has Test Editor as part of project A, and he also manages project B, then when he clicks on "Add Members" in project B, he can type Test Editor's name and select him to add, without knowing his email address.

@rmunn rmunn self-assigned this Nov 14, 2024
Copy link

github-actions bot commented Nov 14, 2024

UI unit Tests

12 tests  ±0   12 ✅ ±0   0s ⏱️ ±0s
 4 suites ±0    0 💤 ±0 
 1 files   ±0    0 ❌ ±0 

Results for commit 8930e88. ± Comparison against base commit c23a0bc.

♻️ This comment has been updated with latest results.

@rmunn
Copy link
Contributor Author

rmunn commented Nov 14, 2024

I've done local testing and the typeahead is working. I want to add some unit tests before calling this PR done, to make sure that the usersICanSee query is returning exactly the results it should. But the code is complete and working, so it's probably ready to review. The only changes I expect to make are:

  • Add unit tests to ensure that usersICanSee returns what it should (e.g., no accidential disclosure of confidential project members)
  • Perhaps delete the usersInMyOrg query if we don't expect to use it in the future.

@rmunn rmunn requested a review from hahn-kev November 14, 2024 06:38
Copy link

github-actions bot commented Nov 14, 2024

C# Unit Tests

98 tests  +8   98 ✅ +8   5s ⏱️ ±0s
15 suites +1    0 💤 ±0 
 1 files   ±0    0 ❌ ±0 

Results for commit 8930e88. ± Comparison against base commit c23a0bc.

♻️ This comment has been updated with latest results.

Copy link
Collaborator

@hahn-kev hahn-kev left a comment

Choose a reason for hiding this comment

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

looks good, one minor change. For testing I would actually suggest moving the query code into UsersService and then calling it directly, that way you are not doing an e2e gql test, just a simple db query test, take a look at the ProjectServiceTest as an example which interacts with the database

u.Organizations.Any(orgMember => myOrgIds.Contains(orgMember.OrgId)) ||
u.Projects.Any(projMember =>
myManagedProjectIds.Contains(projMember.ProjectId) ||
(projMember.Project != null && projMember.Project.IsConfidential == false && myProjectIds.Contains(projMember.ProjectId))));
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we want IsConfidential != true because we decided to show users for unknown projects.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in commit 44db0e3.

Now the test can be a proper unit test rather than an integration test.
This avoids having to use `try ... finally` blocks in the tests, making
them more reliable.
@rmunn rmunn requested a review from hahn-kev November 15, 2024 03:26
@rmunn
Copy link
Contributor Author

rmunn commented Nov 15, 2024

VS Code told me that IEmailService was unused, so I removed it. Turns out it was used after all, just not in that file so the code analysis didn't spot it. Commit 2d0a7c5 should turn the unit test checks green again.

Copy link
Collaborator

@hahn-kev hahn-kev left a comment

Choose a reason for hiding this comment

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

looks good, though I left a comment on the service tests that needs to be taken care of.

manager.ShouldNotBeNull();
var editor = await _lexBoxDbContext.Users.Include(u => u.Organizations).Include(u => u.Projects).FirstOrDefaultAsync(user => user.Email == "editor@test.com");
editor.ShouldNotBeNull();
await using var privateProject = await TempProjectWithoutRepo.Create(_lexBoxDbContext, true, manager.Id);
Copy link
Collaborator

Choose a reason for hiding this comment

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

this test passes even if the project is not confidential, maybe the editor needs to be added to the project? So we probably want a couple tests, non manager members, seeing and not seeing members of projects based on if they're confidential or not, and then a test for a non member and they shouldn't see anything even for a non confidential project.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, that's not actually testing what I intended it to test until the editor is in the project. So what we want is some tests to verify the following:

  • Admin can see everyone (which is a little pointless since they can already just query users and the frontend takes that into account, so maybe this test isn't necessary? It would require a code change anyway)
  • Org members can see everyone in their org, and also anyone they share a public project with
  • Project managers can see everyone in their projects, confidential or not, and also have the same rights as "normal" users in the projects they don't manage (can see public, can not see private)
  • Non-managers can only see people they share public projects with (and org membership)

I think instead of using the users and projects from the seed data for this, I should have a test class constructor that sets up a specific set of projects and users, and a Dispose method on the test class that tears down all those projects and users. Then I can write the tests to the specific set of projects I created, without worrying about any changes I made to the seed data messing things up. (I once added some users to the sena-3 project and managed to make my tests start failing until I reset the data to the original seeded state. We don't want the tests to be that fragile).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Commit af79417 tests more scenarios for projects, but doesn't actually include org membership in the test. So I'll need to add a few more users in a couple different orgs to really make these tests complete.

myieye
myieye previously approved these changes Nov 15, 2024
Copy link
Contributor

@myieye myieye left a comment

Choose a reason for hiding this comment

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

I agree with Kevin's request for the tests to be improved a bit, but otherwise this looks good to me 👍.

I pushed a few minor improvements:

  • There were still a few things that wanted a rename
  • Adapted the GenerateGqlSchema task/method so it keeps working
  • Started hiding typeahead results that are duplicates of existing members (not quite specific to this PR, but relevant)

@rmunn
Copy link
Contributor Author

rmunn commented Nov 19, 2024

Commit e037ab9 tries to say "we don't care about the order, just that the user list matches". But this is still flaky, because WithoutStrictOrdering is only applying to the top level of the expected array. It's still enforcing strict ordering lower down, with the result that sometimes a test passes, and other times that same test fails because user Marian was expected to be in projects [Sherwood, Nottingham] but was in projects [Nottingham, Sherwood] instead. Even though we don't actually care about the projects list of the returned user object; this test only cares that the users returned include Maid Marian but not the Sheriff of Nottingham.

Instead of passing increasingly-complex test options, I'll write a new helper function to extract only the names from the expected list and just compare two lists of strings. (Which will also help with output when a test fails: right now it's spitting out dozens of properties, including the nested properties of the projects in a user's membership list and so on, resulting in test output that's truly hard to read.)

@rmunn
Copy link
Contributor Author

rmunn commented Nov 19, 2024

Commit 3ac2011 adds a single failing test: a user who's a member of one private project but no orgs. You'd expect usersICanSee to return yourself, but currently it doesn't.

Right now that doesn't matter because the frontend filters out existing project members (including the member who can't see himself in the query), so he wouldn't be able to see himself in the frontend typeahead results even if the query was returning the right thing. But we probably do want the usersICanSee query to include yourself no matter what, otherwise it's not living up to its name. So I wrote a failing test for that edge case: Alan a Dale can't see himself in the usersICanSee query because he's not an org. (Little John could see himself because he could see the membership of the Outlaws organization, which includes him. Which is why Alan a Dale was not included in the Outlaws org, in order to exercise this edge case).

A member of private projects should be able to see himself, but
currently he cannot. He could if he was in an org, but he cannot see
himself if he's in one private project but no orgs.
@rmunn rmunn force-pushed the feat/typeahead-for-non-admins branch from 096d825 to 3ac2011 Compare November 19, 2024 05:57
@rmunn
Copy link
Contributor Author

rmunn commented Nov 19, 2024

@hahn-kev @myieye - I've rewritten the UserServiceTests pretty extensively, to set up a set of projects, orgs, and users used only for those tests. Would you let me know if the tests are clear and easy to understand, or if there's anything unclear about them? In particular, I'm hoping that the project and org memberships are pretty obvious when you're reading the tests, without having to scroll up to look at the InitializeAsync method to remind yourself of who is a member of which project. Did I achieve that goal?

Copy link
Collaborator

@hahn-kev hahn-kev left a comment

Choose a reason for hiding this comment

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

looks good other than the new assertion package, lets remove it for now and discuss which one to use in our team meeting

@@ -27,6 +27,7 @@
</Otherwise>
</Choose>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0"/>
Copy link
Collaborator

Choose a reason for hiding this comment

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

we're already using Shouldly in this project, we should just stick with one assertion package. Maybe we should discuss the 2 different packages we're using and settle on one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fluent assertions gave the nice convenient Should().BeEquivalentTo method which worked on enumerables, whereas the Shouldly assertions didn't have that. However now that I have my helper method I can probably rewrite it to use Shouldly.

@myieye myieye removed their request for review November 19, 2024 08:00
@myieye
Copy link
Contributor

myieye commented Nov 19, 2024

LGTM 👍
So, I'll step away from this PR and let @hahn-kev approve when he's happy with the package choice.

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.

Change add member dialog to search based on all users you can see
3 participants