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

Checking permission of tweaked direct-foreign-keys #784

Open
bauergeorg opened this issue Aug 22, 2022 · 3 comments
Open

Checking permission of tweaked direct-foreign-keys #784

bauergeorg opened this issue Aug 22, 2022 · 3 comments

Comments

@bauergeorg
Copy link

Hi folks,

I found that wonderfull example to add a special key to the permission.

Here is my example (users/models.py):

class DeploymentUserObjectPermission(UserObjectPermissionBase):
    content_object = models.ForeignKey(Deployment, on_delete=models.CASCADE)

class DeploymentGroupObjectPermission(GroupObjectPermissionBase):
    content_object = models.ForeignKey(Deployment, on_delete=models.CASCADE)

class ProjectUserObjectPermission(UserObjectPermissionBase):
    content_object = models.ForeignKey(Project, on_delete=models.CASCADE)
    type = models.ForeignKey(DeploymentType, on_delete=models.CASCADE)

class ProjectGroupObjectPermission(GroupObjectPermissionBase):
    content_object = models.ForeignKey(Project, on_delete=models.CASCADE)
    type = models.ForeignKey(DeploymentType, on_delete=models.CASCADE)

Here are the models of my app: (software/models.py):

# Release, RC, Develop, Test
class DeploymentType(models.Model):
	name = models.CharField(max_length=100, default='unknown')
	description = models.TextField()
	image = models.ImageField(default='default_deploymenttype.jpg', upload_to='deploymenttype_pics')

	def __str__(self):
		return self.name

class Project(models.Model):
	title = models.CharField(max_length=100)
	description = models.TextField()
	date_created = models.DateTimeField(default=timezone.now)
	author = models.ForeignKey(User, on_delete=models.CASCADE)
	image = models.ImageField(default='default_project.jpg', upload_to='project_pics')

	def __str__(self):
		return self.title

class Deployment(models.Model):
	title = models.CharField(max_length=100)
	project = models.ForeignKey(Project, on_delete=models.CASCADE)
	file = models.FileField(null=True,blank=True,upload_to='Files')
	content = models.TextField()
	date_posted = models.DateTimeField(default=timezone.now)
	author = models.ForeignKey(User, on_delete=models.CASCADE)
	type = models.ForeignKey(DeploymentType, on_delete=models.CASCADE)

	def __str__(self):
		return self.title

A Deployment is a part of a Project. Every Deployment has a type (RC, Release, Test, Develop, ...).

I wan't to filter List Views and grant access by setting special permissions. But how? Can someone help me?

@bauergeorg
Copy link
Author

For detailed explaination:
I have users. They could be a member of a group. I can set Group/User permission for every specific deployment. And I want to set User/Group permissions for a project with a special type.

a) How could I ask guardian (in a elegant way) to list all deployments and projects by the logged in user?
b) How could I ask guardian (in a elegant way) to restrict site access?

@bauergeorg
Copy link
Author

By the meantime I tried to solve the problem with own functions:

def filter_auth_user_deployments(user, inputs):
    # init empty list
    result_list = []

    deployments_with_permission = auth_user_deployments(user)

    # filter deployments with permission
    for input in inputs:
        if input in deployments_with_permission:
            result_list.append(input)

    return result_list

# project permission managament
def auth_user_projects(user):
    ''' returns a queryset of projects allowed for auth user '''
    # init an empty project list
    project_list = []

    # get checker
    checker = ObjectPermissionChecker(user)

    # get all projects
    projects = Project.objects.all()
    # prefetch the permissions
    checker.prefetch_perms(projects)

    # scan all projects
    for project in projects:
        # if user has permission to this project
        if checker.has_perm('software.view_project', project):
            # add to list
            project_list.append(project.pk)
    
    # get all deployments
    deployments = Deployment.objects.all()
    # prefetch the permissions
    checker.prefetch_perms(deployments)

    # scan all deployments
    for deployment in deployments:
        # if user has permission to a deployment of a project
        if checker.has_perm('software.view_deployment', deployment):
            # add to project list
            if deployment.project.pk not in project_list:
                project_list.append(deployment.project.pk)

    # filter by a variable captured from url, for example
    return projects.filter(pk__in=project_list)

# deployment permission managament
def auth_user_deployments(user):
    ''' returns a queryset of deployments allowed for auth user  '''
    # init an empty deployment list
    deployment_list = []

    # get checker
    checker = ObjectPermissionChecker(user)

    # init empty permission list of structs:
    # {'project':<title>, 'codename':<perm_codename>, 'type':<name>}
    auth_user_projects_list = []

    # check user permission
    user_permission = ProjectUserObjectPermission.objects.filter(user=user)
    for values in user_permission.values():
        project = Project.objects.get(id=values['content_object_id'])
        perm_codename = Permission.objects.get(id=values['permission_id']).codename
        type = DeploymentType.objects.get(id=values['type_id'])
        add_struct = {'project':project.title, 'codename':perm_codename, 'type':type.name}
        # add
        auth_user_projects_list.append(add_struct)

    # check group permission

    # get groups
    groups = user.groups.all()

    for group in groups:
        # check group permission
        group_permission = ProjectGroupObjectPermission.objects.filter(group=group)
        for values in group_permission.values():
            project = Project.objects.get(id=values['content_object_id'])
            perm_codename = Permission.objects.get(id=values['permission_id']).codename
            type = DeploymentType.objects.get(id=values['type_id'])
            add_struct = {'project':project.title, 'codename':perm_codename, 'type':type.name}
            # add
            auth_user_projects_list.append(add_struct)

    # get all deployments
    deployments = Deployment.objects.all()
    # Prefetch the permissions
    checker.prefetch_perms(deployments)
    
    # scan all deployments
    for deployment in deployments:      
        # if user has permission to this deployment
        if checker.has_perm('software.view_deployment', deployment):
            # add to list
            deployment_list.append(deployment.pk)
        # if user has permission to this project
        else:
            for auth_user_projects in auth_user_projects_list:
                if auth_user_projects['project'] == deployment.project.title and auth_user_projects['codename'] == 'view_project' and auth_user_projects['type'] == deployment.type.name:
                    deployment_list.append(deployment.pk)
                    break

    # filter by a variable captured from url, for example
    return deployments.filter(pk__in=deployment_list)```

@kmmbvnr
Copy link

kmmbvnr commented May 6, 2024

Isn't django-guaradian shortcut get-objects-for-user supports all required scenarious even with custom fk permissions models?

https://django-guardian.readthedocs.io/en/stable/api/guardian.shortcuts.html#get-objects-for-user

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

No branches or pull requests

2 participants