Django Role based permissions varies on different project - django

Hi i am working on Django to build project management app, in that i have 100s of users & 50 plus projects.
where single user are involved in multiple projects with different role. now how to give project-role based permission ??
For example.
Let say user "Arnold" is working on "[project-A as Manager, project-B as Vendor , project-C as Artist]",
*As a manager arnold will get all permissions in project-A,
*As a vendor arnold will get read-only permissions in project-B,
*As a Artist arnold will get read,write and update permissions in project-C,
So now tell me how can i design model relation as mentioned above ?

Here's how I'd approach it.
Start with standard User object from django (I always use that for my User and then abstract out from there).
I'd then create a Roles object. Role has a name like Vendor, Owner, Artist, etc.
Then I'd create a junction object between User, Role, and Project.
class Role(...):
name = models.CharField(...)
class Project(...):
...
class ProjectParticipant(...):
user = models.ForeignKey(User)
role = models.ForeignKey(Role)
project = models.ForeignKey(Project)
Then I could create a custom #user_passes_test permission rule in the views that checks to make sure that the user has appropriate relationship to the project. I am assuming that you'll have a view which exposes the project and then within that expose different actions by role on ProjectParticipant.

Related

Many-to-many relationship between Django User, Permissions, and another entity

Consider a Django web app for CompanyXYZ that provides goods and services to many organizations. Users of the app will be affiliated with one or more of those organizations, and have different roles (and be permitted access to different data) within each. So, imagine a schema like this:
Users>---UserOrg----<Org
V
|
UserOrgPermissions
|
^
Permissions
Permissions relate to services provided by the company, and in general look like: “Can order X”, “Can view X orders”, “Can order Y”, “Can view Y orders”, “Can order Z”...etc. Users should be able to log on to CompanyXYZ’s site once, and then choose from among his/her affiliated organizations to view summary data and/or place orders, depending on his/her permissions at a given organization.
From an admin perspective, I need to be able to create organizations, create users, assign users to organizations, and assign permissions to users for each of his/her organizations.
I’m fairly new to Django, so I'm not sure if this is even doable. How would I start?
That would be something like this:
class Permission(models.Model):
pass
class Org(models.Model):
pass
class UserOrg(models.Model):
org = models.Foreignkey('Org')
user = models.Foreignkey('User')
permissions = models.ManyToManyField(Permission)
class User(models.Model):
orgs = models.ManyToManyField(Org, through=UserOrg)
I suggest you to either read the docs or start with their tutorial for beginners.
Django provides you almost all for you needs. Try to learn about users first. Avoid to create users from scrach, you can simple use or customize the Django User models. then, permissions and organizations can be solved with groups.

The right way to set up permissions for "workspaces" in Django?

I am trying to create a site where users work together in "workspaces". A workspace is like an account for a group of users.
Each workspace will have a number of users. There are two user groups: "superusers" and "regular users".
A user may be a member of more than one workspace. The user can never belong to both user groups in the same workspace, but the user can be a "superuser" in one workspace and a "regular user" in another.
I am trying to find out whether I can create this type of setup using the out-of-the-box permissions framework in Django, or whether the best solution is to create my own supporting tables?
My own solution would be a data model like this:
#(assume default User model)
class Workspace(models.Model):
workspace_name = models.CharField(max_length=100)
class WorkspaceUser(models.Model):
user = models.ForeignKey(User)
workspace = models.ForeignKey(Workspace)
usertype = models.CharField(max_length=100) #for simplicity, would only have two options
Is this a sensible way to do it, or can I utilize the out-of-the-box framework to achieve the same instead?
No, the built-in permissions framework is just for the model level - ie "user can modify workspaces generally" rather than "user can modify this specific workspace".
Your solution looks sensible. One addition would be to add an explicit many-to-many declaration using the WorkspaceUser as the through table:
class Workspace(models.Model):
workspace_name = models.CharField(max_length=100)
users = models.ManyToManyField(User, through='WorkspaceUser')
This doesn't change the table structure but gives you the ability to do my_user.workspace_set.all() to get all workspaces for a user or my_workspace.users.all() to get all users for a workspace.

Rolling out own permission app or modifying django permission

I am working on a project which needs a separate admin interface. The django admin interface is for the super super user, there will be companies who will sign up for our app and then they will have their own admin interface. Everything is set and done despite the permission. We want model level permission that's what Django provides.
What I did is:
class CompanyGroup(models.Model):
name = models.CharField(max_length=254)
permissions = models.ManyToManyField(Permissions)
Now this list all the permissions of the site itself. So, Should I start working on my own permission app or I can modify django Permissions to provide object level permissions for only some models.
Thanks
Try one of the several existing 'row level' / 'per object' permissions apps for Django:
http://django-guardian.readthedocs.org/en/v1.2/
http://django-object-permissions.readthedocs.org/en/latest/
...there are probably others, those are just the first two in Google
We are using django-guardian in current project at work, seems fine.
I am assuming that you need to control access to sub-sets of each model's objects, depending on which company the current user belongs to (i.e. you don't want people from Company A to see items from Company B). For this reason you need row level permissions.
You probably also need to limit the permissions of all 'company users' to only certain actions:
You do not need to create a CompanyGroup class.
Instead just enable the admin site, log in as super user and create a django.contrib.auth.models.Group which contains the global permissions applicable to company users.
then ensure when you create any new company user logins that they are added to that Group

how to create django groups and handle permission dynamically

I am using django-userena application to handle user-registration, user-profile and log-in. Now I'm writing an application where -
A user can create a course(course is like a profile where we store information about course).
Other users can register for this course. Registration requires course creator's approval.
Only course creator can edit the course page and he can create an assignment for the course.
All users who registered for the course can see course page and assignment of the course(Read-only).
A course creator can provide permission to other users to edit all assignments of a course.
One way out is -- Create two groups creator and modifier. Now creator group can edit course page and modifier's member can modify assignments of that particular course. Problem with this solution is once we add a user to creator group it automatically gets permission to edit all courses. Similarly a member of modifier group can edit all assignments of all courses. This is not required.
How should I architect this application?
An alternative is django-authority, which can check permissions dynamically by methods rather than persisting them in DB.
The difference Django-guardian is, in your example, when an user moves to another course you will have to deassign the permission on the old group and assign the new one explicitly.
With authority, a function can_edit_course(user, course) (pseudocode) and the access decided in runtime.
You can either have two different groups attached to each course and create them when the course is created:
class Course(models.Model):
creators = models.ForeignKey(Group)
modifiers = models.ForeignKey(Group)
So this way you can set permssion to this group. And you can use django-guardian to assign and check for this permission.
Something like this:
assign_perm('edit_course', group, course)
and then check user if he can edit this course ( it will check group permission from user group automatically )
user.has_perm("edit_course",course)
What you basically want is row-level permission.
You might get some idea from row level permissions in django
Other way is you can keep two fields on your model Course..
class Course(models.Model):
creator = models.ForeignKey(User)
modifiers = models.ManyToManyField(User)
So, check if the user is the creator and then only allow to edit the course.
Check is user is in course.modifiers.all() and then allow him to modify.
Creator will have access to another page where is can add the modifiers for the course.

Django Auth, Users and Permissions

I have a Organization and Employee models
class Organization(models.Model):
is_active = models.BooleanField()
name = models.CharField(u'Name', max_length = 255)
...
class Employee(models.Model):
user = models.OneToOneField(User)
organization = models.ForeignKey(Organization)
...
Will it be good if I use AUTH_PROFILE_MODULE, so Employee becomes user profile?
This way I can use Django permission system to set employees permissions, like
can see all documents
can see own organization documents
can see his own documents
Is is OK to have a permissions that are not a global one like "can see all documents"?
And what If I also want to have a permissions per Organization? How to do this? And how to distinguish permissions per Organization and per Employee?
Edit: I'm using Django 1.4
In short, yes, you're ok.
Because:
1) Using AUTH_PROFILE_MODULE=Employee will make Employee instance to be available for instance in this way:
def view(request):
employee_instance = request.user.get_profile()
2) Using custom permissions is easy, see: https://docs.djangoproject.com/en/dev/topics/auth/#custom-permissions
Edit:
having custom permissions on organizations is possible as well, probably best if you create permissions programatically, like mentioned in the manual, this way:
content_type = ContentType.objects.get(app_label='myapp', model='Organization')
permission = Permission.objects.create(codename='can_do_something', name='Can Do something',
content_type=content_type)
now, you have permission aware organization model, you just assign it to your user.
To clarify more:
Django auth system is sort of a fixed ACL. You assign roles to a user (or group) and that's pretty much it. Django offers helper wrapper function to easily filter out users who don't have a given permission. If you need to decide at runtime and/or in more generic way, whether an object has permission to do something, you either need full blown ACL system (and which django.auth is not) or you code that kind of behavior yourself. This depends on your needs and obviously on the need to manage those permissions. In the OP's case, the behavior is fixed, therefore I would recommend just coding this in and be happy. But the needs may vary and so does the solution. Django auth is good at assigning static permissions to user, gropu or a "profile" object. What that means to your app is up to you in the end.
So in this case, the good solution would be to have a fixed set of permissions like "can view own documents" or "can view organization documents" that is assigned to user/group. And you app should decide, what it means and serve documents accordingly, taking either runtime state in the account or using models structure to determine the proper data set to serve.