Added django-guardian, set owner permissions on post save, testing, CSS fixes

pull/26/head
Piero Toffanin 2016-10-04 16:36:08 -04:00
rodzic d686e63c40
commit 90cc52ff2d
16 zmienionych plików z 112 dodań i 15 usunięć

Wyświetl plik

@ -1 +1,8 @@
from django.contrib import admin
from guardian.admin import GuardedModelAdmin
from .models import Project
class ProjectAdmin(GuardedModelAdmin):
pass
admin.site.register(Project, ProjectAdmin)

Wyświetl plik

@ -11,7 +11,7 @@ class ProjectSerializer(serializers.HyperlinkedModelSerializer):
class ProjectViewSet(viewsets.ModelViewSet):
"""
Projects the current user has access to, including the ability to create new ones.
Projects the current user has access to.
"""
queryset = models.Project.objects.all()
serializer_class = ProjectSerializer

Wyświetl plik

@ -1,7 +1,7 @@
from __future__ import unicode_literals
from django.apps import AppConfig
import .signals
class MainConfig(AppConfig):
name = 'main'

Wyświetl plik

@ -20,7 +20,7 @@
# password: test1234
password: pbkdf2_sha256$30000$pFwIz88hEEZ4$siNaZefZB3bb0DlemWNOkj6+tCq3I3LW+IgVw5VsRmE=
last_login: null
is_superuser: true
is_superuser: false
username: testuser2
first_name: ''
last_name: ''
@ -29,4 +29,20 @@
is_active: true
date_joined: '2016-09-11T22:26:52.582858+00:00'
groups: []
user_permissions: []
- model: auth.user
pk: 3
fields:
# password: test1234
password: pbkdf2_sha256$30000$pFwIz88hEEZ4$siNaZefZB3bb0DlemWNOkj6+tCq3I3LW+IgVw5VsRmE=
last_login: null
is_superuser: false
username: testuser3
first_name: ''
last_name: ''
email: test2@mail.com
is_staff: true
is_active: true
date_joined: '2016-09-11T22:26:52.582858+00:00'
groups: []
user_permissions: []

Wyświetl plik

@ -1,10 +1,15 @@
from __future__ import unicode_literals
from django.db import models
from django.db.models import signals
from django.utils import timezone
from django.contrib.auth.models import User
from django.contrib.postgres import fields
from nodeodm.models import ProcessingNode
from django.dispatch import receiver
from guardian.shortcuts import get_perms_for_model, assign_perm
from guardian.models import UserObjectPermissionBase
from guardian.models import GroupObjectPermissionBase
def assets_directory_path(taskId, projectId, filename):
# files will be uploaded to MEDIA_ROOT/project_<id>/task_<id>/<filename>
@ -14,12 +19,37 @@ def assets_directory_path(taskId, projectId, filename):
class Project(models.Model):
owner = models.ForeignKey(User, on_delete=models.PROTECT, help_text="The person who created the project")
name = models.CharField(max_length=255, help_text="A label used to describe the project")
description = models.TextField(null=True, help_text="More in-depth description of the project")
description = models.TextField(null=True, blank=True, help_text="More in-depth description of the project")
created_at = models.DateTimeField(default=timezone.now, help_text="Creation date")
def __str__(self):
return self.name
class Meta:
permissions = (
('view_project', 'Can view project'),
)
@receiver(signals.post_save, sender=Project, dispatch_uid="project_post_save")
def project_post_save(sender, instance, created, **kwargs):
"""
Automatically assigns all permissions to the owner. If the owner changes
it's up to the user/developer to remove the previous owner's permissions.
"""
for perm in get_perms_for_model(sender).all():
assign_perm(perm.codename, instance.owner, instance)
class ProjectUserObjectPermission(UserObjectPermissionBase):
content_object = models.ForeignKey(Project)
class ProjectGroupObjectPermission(GroupObjectPermissionBase):
content_object = models.ForeignKey(Project)
# from guardian.shortcuts import get_objects_for_user
# ...
# videos = get_objects_for_user(request.user, "view_video", Video.objects.all())
def gcp_directory_path(task, filename):
return assets_directory_path(task.id, task.project.id, filename)

Wyświetl plik

@ -19,6 +19,8 @@
/* HEADER */
/* SIDEBAR */
/* POPUP */ }
.admin-area #changelist-filter {
display: none; }
.admin-area a:link, .admin-area a:visited {
color: #447e9b;
text-decoration: none; }

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -3,6 +3,10 @@
*/
.admin-area{
#changelist-filter{
display: none;
}
a:link, a:visited {
color: #447e9b;
text-decoration: none;

Wyświetl plik

@ -72,8 +72,8 @@
.admin-area .colMS .aligned .vLargeTextField, .admin-area .colMS .aligned .vXMLLargeTextField {
width: 350px; }
.admin-area form .aligned ul {
margin-left: 160px;
padding-left: 10px; }
margin-left: 6px;
padding-left: 3px; }
.admin-area form .aligned ul.radiolist {
display: inline-block;
margin: 0;
@ -302,8 +302,8 @@
background-image: url(../img/search.svg); }
.admin-area form .related-widget-wrapper ul {
display: inline-block;
margin-left: 0;
padding-left: 0; }
margin-left: 6px;
padding-left: 3px; }
.admin-area .clearable-file-input input {
margin-top: 0; }

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -105,8 +105,8 @@
}
form .aligned ul {
margin-left: 160px;
padding-left: 10px;
margin-left: 6px;
padding-left: 3px;
}
form .aligned ul.radiolist {
@ -489,8 +489,8 @@
form .related-widget-wrapper ul {
display: inline-block;
margin-left: 0;
padding-left: 0;
margin-left: 6px;
padding-left: 3px;
}
.clearable-file-input input {

Wyświetl plik

@ -24,6 +24,7 @@
{% block extra-headers %}{% endblock %}
<link rel="stylesheet" type="text/css" href="{% static 'app/css/main.css' %}" />
<script src="{% static 'app/js/vendor/modernizr-2.8.3.min.js' %}"></script>
<script src="{% static 'app/js/vendor/knockout-3.4.0.js' %}"></script>
<script src="{% static 'app/js/vendor/jquery-1.11.2.min.js' %}"></script>
<title>{{title|default:"Login"}} - WebODM</title>
</head>

Wyświetl plik

@ -84,3 +84,32 @@ class TestApp(TestCase):
res = c.get('/processingnode/abc/')
self.assertTrue(res.status_code == 404)
def test_projects(self):
# Get a normal user
user = User.objects.get(pk=2)
self.assertFalse(user.is_superuser)
# Create a new project
p = Project(owner=user, name="test")
p.save()
# Have the proper permissions been set?
self.assertTrue(user.has_perm("view_project", p))
self.assertTrue(user.has_perm("add_project", p))
self.assertTrue(user.has_perm("change_project", p))
self.assertTrue(user.has_perm("delete_project", p))
# Get a superuser
superUser = User.objects.get(pk=1)
self.assertTrue(superUser.is_superuser)
# He should also have permissions, although not explicitly set
self.assertTrue(superUser.has_perm("delete_project", p))
# Get another user
anotherUser = User.objects.get(pk=3)
self.assertFalse(anotherUser.is_superuser)
# Should not have permission
self.assertFalse(anotherUser.has_perm("delete_project", p))

Wyświetl plik

@ -15,7 +15,7 @@ def dashboard(request):
no_processingnodes = ProcessingNode.objects.count() == 0
# Create first project automatically
if Project.objects.count() == 0:
if Project.objects.filter(owner=request.user).count() == 0:
proj = Project(owner=request.user, name=_("First Project"))
proj.save()

Wyświetl plik

@ -8,6 +8,8 @@ cryptography==1.5
Django==1.10
django-common-helpers==0.8.0
django-filter==0.15.2
django-guardian==1.4.6
django-knockout==0.3.2
djangorestframework==3.4.7
enum34==1.1.6
fido==3.2.0

Wyświetl plik

@ -38,6 +38,7 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'guardian',
'rest_framework',
'app',
'nodeodm',
@ -111,6 +112,11 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
# Hook guardian
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', # this is default
'guardian.backends.ObjectPermissionBackend',
)
# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/