Commit e589e0ea authored by Calum Mackervoy's avatar Calum Mackervoy

working version

parent 73528fb6
Pipeline #7309 passed with stage
in 1 minute and 25 seconds
......@@ -152,6 +152,18 @@ $ python3 manage.py runserver
To use DjangoLDP in your models you just need to extend djangoldp.Model
If you define a Meta for your Model, you will [need to explicitly inherit Model.Meta](https://docs.djangoproject.com/fr/2.2/topics/db/models/#meta-inheritance) in order to inherit the default settings, e.g. `default_permissions`
```python
from djangoldp.models import Model, LDPMetaMixin
class Todo(Model):
name = models.CharField(max_length=255)
class Meta(Model.Meta):
```
See "Custom Meta options" below to see some helpful ways you can tweak the behaviour of DjangoLDP
Your model will be automatically detected and registered with an LDPViewSet and corresponding URLs, as well as being registered with the Django admin panel. If you register your model with the admin panel manually, make sure to extend the GuardedModelAdmin so that the model is registered with [Django-Guardian object permissions](https://django-guardian.readthedocs.io/en/stable/userguide/admin-integration.html)
......
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2020-02-21 11:27
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('djangoldp', '0004_auto_20200221_1118'),
]
operations = [
migrations.AlterModelOptions(
name='ldpsource',
options={'default_permissions': ('add', 'change', 'delete', 'view', 'control'), 'ordering': ('federation',)},
),
]
......@@ -165,7 +165,7 @@ class Model(models.Model):
class LDPSource(Model):
federation = models.CharField(max_length=255)
class Meta:
class Meta(Model.Meta):
rdf_type = 'ldp:Container'
ordering = ('federation',)
container_path = 'sources'
......
from django.core.exceptions import PermissionDenied
from django.db.models.base import ModelBase
from rest_framework.permissions import BasePermission
from rest_framework.permissions import DjangoObjectPermissions
from guardian.shortcuts import get_perms
class LDPPermissions(BasePermission):
class LDPPermissions(DjangoObjectPermissions):
"""
Default permissions
Anon: None
......@@ -61,7 +61,7 @@ class LDPPermissions(BasePermission):
else:
if obj and hasattr(model._meta, 'owner_field') and (
getattr(obj, getattr(model._meta, 'owner_field')) == user
or getattr(obj, getattr(model._meta, 'owner_field')) == user.urlid
or (hasattr(user, 'urlid') and getattr(obj, getattr(model._meta, 'owner_field')) == user.urlid)
or getattr(obj, getattr(model._meta, 'owner_field')) == user.id):
perms = perms + owner_perms
......@@ -74,6 +74,7 @@ class LDPPermissions(BasePermission):
# Only used on Model.get_permissions to translate permissions to LDP
return [perm for perm in permissions if perm in self.user_permissions(user, obj_or_model)]
# perms_map defines the permissions required for different methods
perms_map = {
'GET': ['%(app_label)s.view_%(model_name)s'],
'OPTIONS': [],
......@@ -116,8 +117,10 @@ class LDPPermissions(BasePermission):
obj = Model.resolve_id(request._request.path)
model = view.model
# get permissions required
perms = self.get_permissions(request.method, model)
# compare them with the permissions I have
for perm in perms:
if not perm.split('.')[1].split('_')[0] in self.user_permissions(request.user, model, obj):
return False
......@@ -135,9 +138,11 @@ class LDPPermissions(BasePermission):
User have permission on request: Continue
User does not have permission: 403
"""
# get permissions required
perms = self.get_permissions(request.method, obj)
model = obj
# compare them with the permissions I have
for perm in perms:
if not perm.split('.')[1].split('_')[0] in self.user_permissions(request.user, model, obj):
return False
......
......@@ -15,7 +15,7 @@ class Skill(Model):
def recent_jobs(self):
return self.joboffer_set.filter(date__gte=date.today())
class Meta:
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
owner_perms = ['inherit', 'change', 'delete', 'control']
......@@ -35,7 +35,7 @@ class JobOffer(Model):
def some_skill(self):
return self.skills.all().first()
class Meta:
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'change', 'add']
owner_perms = ['inherit', 'delete', 'control']
......@@ -50,17 +50,18 @@ class Conversation(models.Model):
author_user = models.ForeignKey(settings.AUTH_USER_MODEL)
peer_user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name="peers_conv")
class Meta:
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
owner_perms = ['inherit', 'change', 'delete', 'control']
owner_field = 'author_user'
class Resource(Model):
joboffers = models.ManyToManyField(JobOffer, blank=True, related_name='resources')
description = models.CharField(max_length=255)
class Meta:
class Meta(Model.Meta):
anonymous_perms = ['view', 'add', 'delete', 'change', 'control']
authenticated_perms = ['inherit']
owner_perms = ['inherit']
......@@ -73,7 +74,7 @@ class UserProfile(Model):
description = models.CharField(max_length=255, blank=True, null=True)
user = models.OneToOneField(settings.AUTH_USER_MODEL)
class Meta:
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit']
owner_perms = ['inherit', 'change', 'control']
......@@ -85,7 +86,7 @@ class Message(models.Model):
conversation = models.ForeignKey(Conversation, on_delete=models.DO_NOTHING)
author_user = models.ForeignKey(settings.AUTH_USER_MODEL)
class Meta:
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
owner_perms = ['inherit', 'change', 'delete', 'control']
......@@ -95,7 +96,7 @@ class Dummy(models.Model):
some = models.CharField(max_length=255, blank=True, null=True)
slug = models.SlugField(blank=True, null=True, unique=True)
class Meta:
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
owner_perms = ['inherit', 'change', 'delete', 'control']
......@@ -104,7 +105,7 @@ class Dummy(models.Model):
class LDPDummy(Model):
some = models.CharField(max_length=255, blank=True, null=True)
class Meta:
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
owner_perms = ['inherit', 'change', 'delete', 'control']
......@@ -115,17 +116,20 @@ class PermissionlessDummy(Model):
some = models.CharField(max_length=255, blank=True, null=True)
slug = models.SlugField(blank=True, null=True, unique=True)
class Meta:
class Meta(Model.Meta):
anonymous_perms = []
authenticated_perms = []
owner_perms = []
permissions = (
('custom_permission_permissionlessdummy', 'Custom Permission'),
)
class Invoice(Model):
title = models.CharField(max_length=255, blank=True, null=True)
date = models.DateField(blank=True, null=True)
class Meta:
class Meta(Model.Meta):
depth = 2
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
......@@ -137,7 +141,7 @@ class Batch(Model):
invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE, related_name='batches')
title = models.CharField(max_length=255, blank=True, null=True)
class Meta:
class Meta(Model.Meta):
serializer_fields = ['@id', 'title', 'invoice', 'tasks']
anonymous_perms = ['view', 'add']
authenticated_perms = ['inherit', 'add']
......@@ -150,7 +154,7 @@ class Task(models.Model):
batch = models.ForeignKey(Batch, on_delete=models.CASCADE, related_name='tasks')
title = models.CharField(max_length=255)
class Meta:
class Meta(Model.Meta):
serializer_fields = ['@id', 'title', 'batch']
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
......@@ -162,7 +166,7 @@ class Post(Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True)
peer_user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name="peers_post")
class Meta:
class Meta(Model.Meta):
auto_author = 'author'
anonymous_perms = ['view', 'add', 'delete', 'add', 'change', 'control']
authenticated_perms = ['inherit']
......@@ -173,7 +177,7 @@ class Circle(Model):
description = models.CharField(max_length=255)
team = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True)
class Meta:
class Meta(Model.Meta):
nested_fields = ["team"]
anonymous_perms = ['view', 'add', 'delete', 'add', 'change', 'control']
authenticated_perms = ["inherit"]
......
......@@ -62,19 +62,18 @@ from django.test.runner import DiscoverRunner
test_runner = DiscoverRunner(verbosity=1)
failures = test_runner.run_tests([
'djangoldp.tests.tests_ldp_model',
# 'djangoldp.tests.tests_save',
# 'djangoldp.tests.tests_user_permissions',
'djangoldp.tests.tests_ldp_model',
'djangoldp.tests.tests_save',
'djangoldp.tests.tests_user_permissions',
'djangoldp.tests.tests_guardian',
# 'djangoldp.tests.tests_anonymous_permissions',
'djangoldp.tests.tests_update',
'djangoldp.tests.tests_auto_author',
'djangoldp.tests.tests_get',
'djangoldp.tests.tests_delete',
'djangoldp.tests.tests_sources',
'djangoldp.tests.tests_pagination',
'djangoldp.tests.tests_anonymous_permissions',
'djangoldp.tests.tests_update',
'djangoldp.tests.tests_auto_author',
'djangoldp.tests.tests_get',
'djangoldp.tests.tests_delete',
'djangoldp.tests.tests_sources',
'djangoldp.tests.tests_pagination',
# 'djangoldp.tests.tests_temp'
])
if failures:
sys.exit(failures)
......@@ -4,6 +4,7 @@ from rest_framework.test import APIClient, APITestCase
from guardian.shortcuts import assign_perm
from .models import PermissionlessDummy
from djangoldp.permissions import LDPPermissions
class TestsGuardian(APITestCase):
......@@ -80,3 +81,12 @@ class TestsGuardian(APITestCase):
response = self.client.patch('/permissionless-dummys/{}/'.format(dummy_without.slug), data=json.dumps(body),
content_type='application/ld+json')
self.assertEqual(response.status_code, 403)
# test that custom permissions are returned on a model
def test_custom_permissions(self):
self.setUpLoggedInUser()
self.setUpGuardianDummyWithPerms(['custom_permission'])
permissions = LDPPermissions()
result = permissions.user_permissions(self.user, self.dummy)
self.assertIn('custom_permission', result)
......@@ -13,6 +13,9 @@ class Update(TestCase):
def setUp(self):
self.factory = APIRequestFactory()
self.client = APIClient()
self.user = get_user_model().objects.create_user(username='john', email='jlennon@beatles.com',
password='glass onion')
self.client.force_authenticate(user=self.user)
def tearDown(self):
pass
......@@ -340,9 +343,8 @@ class Update(TestCase):
self.assertIn('conversation_set', response.data)
def test_missing_field_should_not_be_removed_with_fk_relation(self):
user = get_user_model().objects.create(username="alex", password="test")
peer = get_user_model().objects.create(username="sylvain", password="test2")
conversation = Conversation.objects.create(author_user=user, peer_user=peer,
conversation = Conversation.objects.create(author_user=self.user, peer_user=peer,
description="conversation description")
body = [
{
......@@ -356,9 +358,8 @@ class Update(TestCase):
self.assertIn('peer_user', response.data)
def test_empty_field_should_be_removed_with_fk_relation(self):
user = get_user_model().objects.create(username="alex", password="test")
peer = get_user_model().objects.create(username="sylvain", password="test2")
conversation = Conversation.objects.create(author_user=user, peer_user=peer,
conversation = Conversation.objects.create(author_user=self.user, peer_user=peer,
description="conversation description")
body = [
{
......@@ -485,15 +486,14 @@ class Update(TestCase):
self.assertEqual(response.data['joboffers']['ldp:contains'][0]['title'], "first title")
def test_update_with_new_fk_relation(self):
user = get_user_model().objects.create(username="alex", password="test")
conversation = Conversation.objects.create(author_user=user,
conversation = Conversation.objects.create(author_user=self.user,
description="conversation description")
body = [
{
'@id': "/conversations/{}/".format(conversation.pk),
'http://happy-dev.fr/owl/#description': "conversation update",
'http://happy-dev.fr/owl/#peer_user': {
'@id': 'http://happy-dev.fr/users/{}'.format(user.pk),
'@id': 'http://happy-dev.fr/users/{}'.format(self.user.pk),
}
}
]
......@@ -505,7 +505,7 @@ class Update(TestCase):
conversation = Conversation.objects.get(pk=conversation.pk)
self.assertIsNotNone(conversation.peer_user)
user = get_user_model().objects.get(pk=user.pk)
user = get_user_model().objects.get(pk=self.user.pk)
self.assertEqual(user.peers_conv.count(), 1)
def test_m2m_user_link_federated(self):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment