-
Notifications
You must be signed in to change notification settings - Fork 6
Framework for User Permissions & Roles #693
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
Conversation
✅ Deploy Preview for ami-dev canceled.
|
This looks really promising, great work @mohamedelabbas1996. I will review asap! |
…ssions - Added ProjectMixin to require for all project-related entities - Ensured project_id is extracted only from URLs matching /projects/<id>/, otherwise falls back to query params - Implemented permission inheritance from the associated project object - Exposed user_permissions field in responses to reflect entity permissions
@mihow currently setting |
created_at = models.DateTimeField(auto_now_add=True) | ||
updated_at = models.DateTimeField(auto_now=True) | ||
|
||
def get_project(self): |
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.
Follow up proposal for objects that are shared between multiple projects (have a many2many): check for many2many, if instance belongs to multiple projects, they must be a superuser or permission denied. If a single project, then return that project as usual.
known many2many
Pipeline
Processing Service
Taxa
TaxaList
from ami.main.api.views import DefaultViewSet | ||
from ami.utils.fields import url_boolean_param | ||
from ami.utils.requests import get_active_project, project_id_doc_param | ||
from ami.utils.requests import project_id_doc_param |
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.
Can the decorator be moved to the mixin?
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 tried moving it to the mixin but it did not work, it seems that it should be used with a Viewset class
""" | ||
Set the user to the current user. | ||
""" | ||
# Get an instance for the model without saving |
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.
Is there a pre-save method? or a way to make this reusable in the DefaultViewSet?
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.
moved it to the DefaultViewset
ami/users/roles.py
Outdated
assign_perm(perm, user, project) | ||
|
||
@classmethod | ||
def un_assign_user(cls, user, project): |
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.
"unassign"
From our call, the two most important roles to start with are:
Identifier role
Project manager role
|
Discussion for next iteration after UI is ready:
|
ami/users/roles.py
Outdated
@classmethod | ||
def assign_user(cls, user, project): | ||
# Get or create the Group | ||
group_name = f"{project.pk}_{project.name}_{cls.__name__}" |
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 proposal:
class Project
permission_groups = manytomany(Group, through=ProjectRoleGroup)
class ProjectRoleGroup
project_id
group_id
role_slug
project_role_group = ProjectRoleGroup.objects.get(project=1, role_slug="dfds", group_id=2)
|
||
@classmethod | ||
def assign_user(cls, user, project): | ||
# Get or create the Group |
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.
Add a @todo comment about making this a formal relationship between groups, roles & project
ami/main/signals.py
Outdated
logger.info(f"Project name: {instance.name}") | ||
|
||
for group in groups: | ||
logger.info(f"Old permissions group name: {group.name}") |
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.
Will you remove this log statement and instead add the old group name to this log statement later on? Then it will only be logged if its actually being modified:
logger.info(f"Changing permission group name from {group.name} to: {new_group_name}")
Testing Feb 25thSummaryI have tested for 6 different permission scenarios. For the testing, I have assigned myself different roles from admin and then interacted with the app in different ways. Works really well now, great work! Just had some minor questions. Questions
Test resultsNot logged in Basic member Identifier Project manager Staff Superadmin |
Thanks so much for doing another round of tests!
|
Now a project appears in the "My Projects" tab if the user assigned to a role in the given project. |
try: | ||
with transaction.atomic(): # Ensure DB consistency | ||
for group in Group.objects.filter(pk__in=pk_set): | ||
parts = group.name.split("_") # Expected format: {project_id}_{project_name}_{Role} |
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.
Will you keep track of any function that is using the group name to relate to projects? So we can refactor at the same time
…rojects and roles, pending future refactor to formal relationships
Follow-up notes:
|
@mihow write announcement message about the new roles & project assignements |
Summary
This PR introduces fine-grained object-level permissions for the Project model and related entities using Django Guardian. It establishes a roles and permissions framework, including Project Manager, Basic Member, and Identifier roles, with appropriate permissions for each.
List of Changes
project_id
query parameter made optional for all project related entities views.Related Issues
Closes #703 #219
Detailed Description
This PR implements a fine-grained permissions framework for the Project model and its related entities:
Job, Deployment, SourceImageCollection, S3StorageSource, Site, Device, Identification. This ensures that access is properly restricted and prevents unauthorized modifications to project-related entities.
Roles and Permissions:
Deployment Notes
manage.py assign_roles --source "Identifiers CSV file URL "
to reset permissions and assign roles for existing project owners and members and assign identifier, project manager roles to users based on a CSV file.Checklist
Follow-up PRs: