-
Notifications
You must be signed in to change notification settings - Fork 4
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
Improve Project-User Management and Accessibility #275
base: main
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for ami-dev canceled.
|
✅ Deploy Preview for ami-storybook canceled.
|
|
All queries should include objects from public projects as well. |
Changes in This PR
|
Closes #402 |
Me and @mohamedelabbas1996 had a chat about this today, regarding some frontend perspectives:
We decided to discuss more in the team on the meeting tomorrow about next steps! :) |
Thanks for collaborating on this PR @mohamedelabbas1996 and @annavik! I look forward to reviewing your commits and suggestions. |
Frontend updates pushed. Me and @mohamedelabbas1996 solved it by adding tabs to the header: |
ui/src/pages/projects/projects.tsx
Outdated
const { pagination, setPage } = usePagination() | ||
const filters = | ||
user.loggedIn && selectedTab === TABS.USER_PROJECTS | ||
? [{ field: 'public', value: 'false' }] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mohamedelabbas1996 here is where the params we pass to the backend can be tweaked if needed
For the filter param name If you change the filter name, I added a comment (to the PR) so you can see where in the FE code to tweak. |
@mohamedelabbas1996 there is a chance for some inconstancy when retrieving "my projects" since there is both a project owner and project members. Some ideas to address this:
My recommendation is to add a new reusable method to to Project QuerySet class that can be used everywhere. It takes a little more code to setup a QuerySet for a model the first time, but it's a pattern that I would like to continue using because it keeps the logic in one place. Here is one example for the SourceImage model. You define a QuerySet, a Manager and then assign the manager to the Model. Lines 1170 to 1171 in 14e9ec0
Lines 1194 to 1196 in 14e9ec0
Line 1233 in 14e9ec0
|
Now project members can be managed from the Admin page |
I opted to add the owner to members if not already exists and then we can just filter by members |
Added the model manager. Thanks for the recommendation! |
ami/main/api/views.py
Outdated
user_id = self.request.query_params.get("user_id") | ||
if user_id: | ||
user = User.objects.filter(pk=user_id).first() | ||
if not (user == self.request.user or is_active_staff(self.request.user)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Active "staff" is actually everyone who has edit permissions. Superusers are a different boolean field. But how about we simplify and just check for the matching user for now? Since superusers can see anything in the Django admin.
ami/main/api/views.py
Outdated
project = serializer.save(owner=self.request.user) | ||
|
||
# Add owner to project members if not already a member | ||
if not project.members.filter(id=self.request.user.id).exists(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would move this check to the model Project.save() method instead, because there are other places where the owner can be set or changed. Like if you add a project in the Django admin, the owner is not made a member.
""" | ||
Filters projects to include only those where the given user is a member. | ||
""" | ||
return self.filter(members=user) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you made this queryset method (thank you!), it's pretty easy to filter by member or owner.
self.filter(models.Q(members=user) | models.Q(owner=user)).distinct()
@final | ||
class Project(BaseModel): | ||
""" """ | ||
|
||
name = models.CharField(max_length=_POST_TITLE_MAX_LENGTH) | ||
description = models.TextField() | ||
image = models.ImageField(upload_to="projects", blank=True, null=True) | ||
|
||
owner = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name="projects") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm glad we kept owner in this PR
@@ -882,3 +882,25 @@ def test_project_devices(self): | |||
exepcted_device_ids = {device.id for device in Device.objects.filter(project=project)} | |||
response_device_ids = {device.get("id") for device in response_data["results"]} | |||
self.assertEqual(response_device_ids, exepcted_device_ids) | |||
|
|||
|
|||
class TestProjectOwnerAutoAssignment(APITestCase): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the tests! remember that is_staff
is different than is_superuser
. We are using is_staff
to give a user edit permissions to everything in the app. is_superuser
are the only users who can delete some objects (like jobs). We should review this in the next permission PRs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mihow Thank you for the clarification!
ui/src/pages/projects/projects.tsx
Outdated
const { user } = useUser() | ||
const { userInfo} = useUserInfo() | ||
|
||
const [selectedTab, setSelectedTab] = useState( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@annavik can we add a URL path or param so we can link to all projects when necessary? With the new feature, if someone sends someone else the projects link, they likely won't see the same projects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mihow I 've tried to move adding project owner to members to Project.save method. It works well from the api but it doesn't auto-add the owner if we create a project from the admin page
@@ -0,0 +1,25 @@ | |||
# Generated by Django 4.2.2 on 2023-10-11 02:15 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more thing, will you squash these migrations into one or two? python manage.py squashmigrations first_one last_one
. That will remove some clutter and extra steps when we merge into main (instead of adding the field, then renaming the field). I only do this for migrations that haven't modified live data yet (migrations in an branch like these).
24fcfa8
to
2f9e5f7
Compare
This pull request enhances how projects and project members (users) are managed and accessed. It introduces a many-to-many relationship between projects and members, ensuring that users are automatically assigned to a project when they create it. Django admin panel is updated to allow manual assignment of members to a project. A filtering by
user_id
is added to the/projects
to filter projects that the current user is involved in.My Projects tab is added at the top of the home page to make it easier for users to find and access their projects.