Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • djangoldp-packages/djangoldp
  • decentral1se/djangoldp
  • femmefaytale/djangoldp
  • jvtrudel/djangoldp
4 results
Show changes
Showing
with 1170 additions and 12344 deletions
# Generated by Django 4.2.3 on 2023-08-31 15:27
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('djangoldp', '0015_auto_20210125_1847'),
]
operations = [
migrations.AlterModelOptions(
name='activity',
options={'default_permissions': {'delete', 'change', 'view', 'add', 'control'}},
),
migrations.AlterModelOptions(
name='follower',
options={'default_permissions': {'delete', 'change', 'view', 'add', 'control'}},
),
migrations.AlterModelOptions(
name='ldpsource',
options={'default_permissions': {'delete', 'change', 'view', 'add', 'control'}, 'ordering': ('federation',)},
),
migrations.AlterModelOptions(
name='scheduledactivity',
options={'default_permissions': {'delete', 'change', 'view', 'add', 'control'}},
),
]
# Generated by Django 4.2.3 on 2023-09-03 20:26
from django.db import migrations
import djangoldp.fields
class Migration(migrations.Migration):
dependencies = [
('djangoldp', '0016_alter_activity_options_alter_follower_options_and_more'),
]
operations = [
migrations.AlterField(
model_name='activity',
name='urlid',
field=djangoldp.fields.LDPUrlField(blank=True, db_index=True, null=True, unique=True),
),
migrations.AlterField(
model_name='follower',
name='urlid',
field=djangoldp.fields.LDPUrlField(blank=True, db_index=True, null=True, unique=True),
),
migrations.AlterField(
model_name='ldpsource',
name='urlid',
field=djangoldp.fields.LDPUrlField(blank=True, db_index=True, null=True, unique=True),
),
]
# Generated by Django 4.2.3 on 2023-10-17 19:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('djangoldp', '0017_alter_activity_urlid_alter_follower_urlid_and_more'),
]
operations = [
migrations.AlterField(
model_name='activity',
name='payload',
field=models.TextField(),
),
migrations.AlterField(
model_name='activity',
name='response_body',
field=models.TextField(null=True),
),
]
import json
import logging
import uuid
from urllib.parse import urlparse
from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.core.exceptions import ObjectDoesNotExist, ValidationError, FieldDoesNotExist
from django.db import models
from django.db.models import BinaryField, DateTimeField
from django.db.models.base import ModelBase
from django.db.models.signals import post_save
from django.db.models.signals import post_save, pre_save, pre_delete, m2m_changed
from django.dispatch import receiver
from django.urls import reverse_lazy, get_resolver
from django.urls import get_resolver
from django.utils.datastructures import MultiValueDictKeyError
from django.utils.decorators import classonlymethod
from guardian.shortcuts import assign_perm
from rest_framework.utils import model_meta
from djangoldp.fields import LDPUrlField
from djangoldp.permissions import LDPPermissions
import logging
from djangoldp.permissions import DEFAULT_DJANGOLDP_PERMISSIONS, OwnerPermissions, InheritPermissions, ReadOnly
logger = logging.getLogger('djangoldp')
Group._meta.serializer_fields = ['name', 'user_set']
Group._meta.rdf_type = 'foaf:Group'
# Group._meta.rdf_context = {'user_set': 'foaf:member'}
Group._meta.permission_classes = [(OwnerPermissions&ReadOnly)|InheritPermissions]
Group._meta.owner_field = 'user'
Group._meta.inherit_permissions = []
class LDPModelManager(models.Manager):
def local(self):
......@@ -30,44 +34,21 @@ class LDPModelManager(models.Manager):
internal_ids = [x.pk for x in queryset if not Model.is_external(x)]
return queryset.filter(pk__in=internal_ids)
def nested_fields(self):
'''parses the relations on the model, and returns a list of nested field names'''
nested_fields = set()
# include all many-to-many relations
for field_name, relation_info in model_meta.get_field_info(self.model).relations.items():
if relation_info.to_many:
if field_name is not None:
nested_fields.add(field_name)
# include all nested fields explicitly included on the model
nested_fields.update(set(Model.get_meta(self.model, 'nested_fields', set())))
# exclude anything marked explicitly to be excluded
nested_fields = nested_fields.difference(set(Model.get_meta(self.model, 'nested_fields_exclude', set())))
return list(nested_fields)
def fields(self):
return self.nested_fields()
class Model(models.Model):
urlid = LDPUrlField(blank=True, null=True, unique=True)
urlid = LDPUrlField(blank=True, null=True, unique=True, db_index=True)
is_backlink = models.BooleanField(default=False, help_text='set automatically to indicate the Model is a backlink')
allow_create_backlink = models.BooleanField(default=True,
help_text='set to False to disable backlink creation after Model save')
objects = LDPModelManager()
nested = LDPModelManager()
class Meta:
default_permissions = DEFAULT_DJANGOLDP_PERMISSIONS
abstract = True
depth = 0
def __init__(self, *args, **kwargs):
super(Model, self).__init__(*args, **kwargs)
@classmethod
def get_view_set(cls):
'''returns the view_set defined in the model Meta or the LDPViewSet class'''
view_set = getattr(cls._meta, 'view_set', getattr(cls.Meta, 'view_set', None))
if view_set is None:
from djangoldp.views import LDPViewSet
view_set = LDPViewSet
return view_set
@classmethod
def get_container_path(cls):
'''returns the url path which is used to access actions on this model (e.g. /users/)'''
......@@ -82,7 +63,7 @@ class Model(models.Model):
@classonlymethod
def absolute_url(cls, instance_or_model):
if isinstance(instance_or_model, ModelBase) or instance_or_model.urlid is None or instance_or_model.urlid == '':
if isinstance(instance_or_model, ModelBase) or not instance_or_model.urlid:
return '{}{}'.format(settings.SITE_URL, Model.resource(instance_or_model))
else:
return instance_or_model.urlid
......@@ -105,16 +86,24 @@ class Model(models.Model):
@classonlymethod
def slug_field(cls, instance_or_model):
if isinstance(instance_or_model, ModelBase):
object_name = instance_or_model.__name__.lower()
model = instance_or_model
else:
object_name = instance_or_model._meta.object_name.lower()
model = type(instance_or_model)
# Use cached value if present
if hasattr(model, "_slug_field"):
return model._slug_field
object_name = model.__name__.lower()
view_name = '{}-detail'.format(object_name)
try:
slug_field = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][1][0])
except MultiValueDictKeyError:
slug_field = Model.get_meta(instance_or_model, 'lookup_field', 'pk')
slug_field = getattr(model._meta, 'lookup_field', 'pk')
if slug_field.startswith('/'):
slug_field = slug_field[1:]
model._slug_field = slug_field
return slug_field
@classonlymethod
......@@ -129,11 +118,6 @@ class Model(models.Model):
return path
class Meta:
default_permissions = ('add', 'change', 'delete', 'view', 'control')
abstract = True
depth = 0
@classonlymethod
def resolve_id(cls, id):
'''
......@@ -153,7 +137,7 @@ class Model(models.Model):
@classonlymethod
def resolve_parent(cls, path):
split = path.strip('/').split('/')
parent_path = "/".join(split[0:len(split) - 1])
parent_path = "/".join(split[:-1])
return Model.resolve_id(parent_path)
@classonlymethod
......@@ -170,8 +154,8 @@ class Model(models.Model):
:param path: a URL path to check
:return: the container model and resolved id in a tuple
'''
if settings.BASE_URL in path:
path = path[len(settings.BASE_URL):]
if path.startswith(settings.BASE_URL):
path = path.replace(settings.BASE_URL, '')
container = cls.resolve_container(path)
try:
resolve_id = cls.resolve_id(path)
......@@ -220,46 +204,19 @@ class Model(models.Model):
raise ObjectDoesNotExist
return Model.get_or_create(model, urlid, **kwargs)
@classonlymethod
def get_model_rdf_type(cls, model):
if model is get_user_model():
return "foaf:user"
else:
return Model.get_meta(model, "rdf_type")
@classonlymethod
def get_subclass_with_rdf_type(cls, type):
#TODO: deprecate
'''returns Model subclass with Meta.rdf_type matching parameterised type, or None'''
if type == 'foaf:user':
return get_user_model()
for subcls in Model.__subclasses__():
if Model.get_meta(subcls, 'rdf_type') == type:
if getattr(subcls._meta, "rdf_type", None) == type:
return subcls
return None
@classonlymethod
def get_permission_classes(cls, related_model, default_permissions_classes):
'''returns the permission_classes set in the models Meta class'''
return cls.get_meta(related_model, 'permission_classes', default_permissions_classes)
@classonlymethod
def get_meta(cls, model_class, meta_name, default=None):
'''returns the models Meta class'''
if hasattr(model_class, 'Meta'):
meta = getattr(model_class.Meta, meta_name, default)
else:
meta = default
return getattr(model_class._meta, meta_name, meta)
@staticmethod
def get_permissions(obj_or_model, context, filter):
permissions = filter
for permission_class in Model.get_permission_classes(obj_or_model, [LDPPermissions]):
permissions = permission_class().filter_user_perms(context, obj_or_model, permissions)
return [{'mode': {'@type': name.split('_')[0]}} for name in permissions]
@classmethod
def is_external(cls, value):
'''
......@@ -267,19 +224,24 @@ class Model(models.Model):
:return: True if the urlid is external to the server, False otherwise
'''
try:
if not value:
return False
if not isinstance(value, str):
value = value.urlid
return value is not None and not value.startswith(settings.SITE_URL)
# This expects all @ids to start with http which mlight not be universal. Maybe needs a fix.
return value.startswith('http') and not value.startswith(settings.SITE_URL)
except:
return False
#TODO: this breaks the serializer, which probably assumes that traditional models don't have a urlid.
# models.Model.urlid = property(lambda self: '{}{}'.format(settings.SITE_URL, Model.resource(self)))
class LDPSource(Model):
federation = models.CharField(max_length=255)
class Meta(Model.Meta):
rdf_type = 'ldp:Container'
rdf_type = 'sib:federatedContainer'
ordering = ('federation',)
container_path = 'sources'
lookup_field = 'federation'
......@@ -292,42 +254,40 @@ class Activity(Model):
'''Models an ActivityStreams Activity'''
local_id = LDPUrlField(help_text='/inbox or /outbox url (local - this server)') # /inbox or /outbox full url
external_id = LDPUrlField(null=True, help_text='the /inbox or /outbox url (from the sender or receiver)')
payload = BinaryField()
payload = models.TextField()
response_location = LDPUrlField(null=True, blank=True, help_text='Location saved activity can be found')
response_code = models.CharField(null=True, blank=True, help_text='Response code sent by receiver', max_length=8)
response_body = BinaryField(null=True)
response_body = models.TextField(null=True)
type = models.CharField(null=True, blank=True, help_text='the ActivityStreams type of the Activity',
max_length=64)
is_finished = models.BooleanField(default=True)
created_at = DateTimeField(auto_now_add=True)
created_at = models.DateTimeField(auto_now_add=True)
success = models.BooleanField(default=False, help_text='set to True when an Activity is successfully delivered')
class Meta(Model.Meta):
container_path = "activities"
rdf_type = 'as:Activity'
def _bytes_to_json(self, obj):
if hasattr(obj, 'tobytes'):
obj = obj.tobytes()
if obj is None or obj == b'':
return {}
return json.loads(obj)
disable_url = True
def to_activitystream(self):
return self._bytes_to_json(self.payload)
return json.loads(self.payload)
def response_to_json(self):
return self._bytes_to_json(self.response_body)
return self.to_activitystream()
# temporary database-side storage used for scheduled tasks in the ActivityQueue
class ScheduledActivity(Activity):
failed_attempts = models.PositiveIntegerField(default=0, help_text='a log of how many failed retries have been made sending the activity')
failed_attempts = models.PositiveIntegerField(default=0,
help_text='a log of how many failed retries have been made sending the activity')
def save(self, *args, **kwargs):
self.is_finished = False
super(ScheduledActivity, self).save(*args, **kwargs)
class Meta(Model.Meta):
disable_url = True
class Follower(Model):
'''Models a subscription on a model. When the model is saved, an Update activity will be sent to the inbox'''
......@@ -338,32 +298,74 @@ class Follower(Model):
def __str__(self):
return 'Inbox ' + str(self.inbox) + ' on ' + str(self.object)
class Meta(Model.Meta):
disable_url = True
class DynamicNestedField:
'''
Used to define a method as a nested_field.
Usage:
LDPUser.circles = lambda self: Circle.objects.filter(members__user=self)
LDPUser.circles.field = DynamicNestedField(Circle, 'circles')
'''
related_query_name = None
one_to_many = False
many_to_many = True
many_to_one = False
one_to_one = False
read_only = True
name = ''
def __init__(self, model:models.Model|None, remote_name:str, name:str='', remote:object|None=None) -> None:
self.model = model
self.name = name
if remote:
self.remote_field = remote
else:
self.remote_field = DynamicNestedField(None, '', remote_name, self)
@receiver([post_save])
def auto_urlid(sender, instance, **kwargs):
if isinstance(instance, Model):
changed = False
if getattr(instance, Model.slug_field(instance), None) is None:
setattr(instance, Model.slug_field(instance), instance.pk)
instance.save()
if (instance.urlid is None or instance.urlid == '' or 'None' in instance.urlid):
changed = True
if (not instance.urlid or 'None' in instance.urlid):
instance.urlid = instance.get_absolute_url()
changed = True
if changed:
instance.save()
@receiver(post_save)
def create_role_groups(sender, instance, created, **kwargs):
if created:
for name, params in getattr(instance._meta, 'permission_roles', {}).items():
group, x = Group.objects.get_or_create(name=f'LDP_{instance._meta.model_name}_{name}_{instance.id}')
setattr(instance, name, group)
instance.save()
if params.get('add_author'):
assert hasattr(instance._meta, 'auto_author'), "add_author requires to also define auto_author"
author = getattr(instance, instance._meta.auto_author)
if author:
group.user_set.add(author)
for permission in params.get('perms', []):
assign_perm(f'{permission}_{instance._meta.model_name}', group, instance)
if 'djangoldp_account' not in settings.DJANGOLDP_PACKAGES:
def webid(self):
# an external user should have urlid set
webid = getattr(self, 'urlid', None)
if webid is not None and urlparse(settings.BASE_URL).netloc != urlparse(webid).netloc:
webid = self.urlid
# local user use user-detail URL with primary key
else:
webid = '{0}{1}'.format(settings.BASE_URL, reverse_lazy('user-detail', kwargs={'pk': self.pk}))
return webid
get_user_model().webid = webid
def invalidate_cache_if_has_entry(entry):
from djangoldp.serializers import GLOBAL_SERIALIZER_CACHE
if GLOBAL_SERIALIZER_CACHE.has(entry):
GLOBAL_SERIALIZER_CACHE.invalidate(entry)
def invalidate_model_cache_if_has_entry(model):
entry = getattr(model._meta, 'label', None)
invalidate_cache_if_has_entry(entry)
@receiver([pre_save, pre_delete])
def invalidate_caches(sender, instance, **kwargs):
invalidate_model_cache_if_has_entry(sender)
@receiver(post_save, sender=User)
def update_perms(sender, instance, created, **kwargs):
LDPPermissions.invalidate_cache()
@receiver([m2m_changed])
def invalidate_caches_m2m(sender, instance, action, *args, **kwargs):
invalidate_model_cache_if_has_entry(kwargs['model'])
\ No newline at end of file
from rest_framework.pagination import LimitOffsetPagination
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
class LDPOffsetPagination(LimitOffsetPagination):
def get_paginated_response(self, data):
next_url = self.get_next_link()
previous_url = self.get_previous_link()
links = []
for url, label in ((previous_url, 'prev'), (next_url, 'next')):
if url is not None:
links.append('<{}>; rel="{}"'.format(url, label))
headers = {'Link': ', '.join(links)} if links else {}
return Response(data, headers=headers)
class LDPPagination(PageNumberPagination):
page_query_param = 'p'
page_size_query_param = 'limit'
class LDPPagination(LimitOffsetPagination):
def get_paginated_response(self, data):
next_url = self.get_next_link()
previous_url = self.get_previous_link()
......
This diff is collapsed.
......@@ -19,10 +19,11 @@ def get_prefetch_fields(model, serializer, depth, prepend_string=''):
# get a list of all fields which would be serialized on this model
# TODO: dynamically generating serializer fields is necessary to retrieve many-to-many fields at depth > 0,
# but the _all_ default has issues detecting reverse many-to-many fields
# meta_args = {'model': model, 'depth': 0, 'fields': Model.get_meta(model, 'serializer_fields', '__all__')}
# meta_args = {'model': model, 'depth': 0, 'fields': getattr(model._meta, 'serializer_fields', '__all__')}
# meta_class = type('Meta', (), meta_args)
# serializer = (type(LDPSerializer)('TestSerializer', (LDPSerializer,), {'Meta': meta_class}))()
serializer_fields = set([f for f in serializer.get_fields()])
empty_containers = getattr(model._meta, 'empty_containers', [])
# we are only interested in foreign keys (and many-to-many relationships)
model_relations = model_meta.get_field_info(model).relations
......@@ -33,7 +34,7 @@ def get_prefetch_fields(model, serializer, depth, prepend_string=''):
continue
# nested fields should be added if serialized
if field_name in serializer_fields:
if field_name in serializer_fields and field_name not in empty_containers:
fields.add((prepend_string + field_name))
# and they should also have their immediate foreign keys prefetched if depth not reached
......
This diff is collapsed.
<!DOCTYPE html>
<html>
<head>
<title>Swagger</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@3/swagger-ui.css">
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script>
<script>
const ui = SwaggerUIBundle({
url: "{% url 'schema' %}",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
],
layout: "BaseLayout",
requestInterceptor: (request) => {
request.headers['X-CSRFToken'] = "{{ csrf_token }}"
return request;
}
})
</script>
</body>
</html>
\ No newline at end of file
"""
This module is meant to be used as a testing LDP package.
It contains configuration elements imported by a djangoldp-package
when the django server is setup.
"""
# define an extra variables
MYPACKAGEVAR = 'ok'
USE_I18N = False
# register an extra middleware
MIDDLEWARE = [
'djangoldp.tests.dummy.middleware.DummyMiddleware'
]
# register an extra installed app
INSTALLED_APPS = [
'djangoldp.tests.dummy.apps.DummyConfig'
]
SECRET_KEY = "$r&)p-4k@h5b!1yrft6&q%j)_p$lxqh6#)jeeu0z1iag&y&wdu"
from django.conf.urls import re_path
from djangoldp.permissions import LDPPermissions
from djangoldp.tests.models import Skill, JobOffer, Message, Conversation, Dummy, PermissionlessDummy, Task, DateModel
from django.urls import path
from djangoldp.tests.models import Message, Conversation, Dummy, PermissionlessDummy, Task, DateModel, LDPDummy
from djangoldp.permissions import ACLPermissions
from djangoldp.views import LDPViewSet
urlpatterns = [
re_path(r'^messages/', LDPViewSet.urls(model=Message, permission_classes=[LDPPermissions], fields=["@id", "text", "conversation"], nested_fields=['conversation'])),
re_path(r'^conversations/', LDPViewSet.urls(model=Conversation, nested_fields=["message_set"], permission_classes=[LDPPermissions])),
re_path(r'^tasks/', LDPViewSet.urls(model=Task, permission_classes=[LDPPermissions])),
re_path(r'^dates/', LDPViewSet.urls(model=DateModel, permission_classes=[LDPPermissions])),
re_path(r'^dummys/', LDPViewSet.urls(model=Dummy, permission_classes=[LDPPermissions], lookup_field='slug',)),
re_path(r'^permissionless-dummys/', LDPViewSet.urls(model=PermissionlessDummy, permission_classes=[LDPPermissions], lookup_field='slug',)),
path('messages/', LDPViewSet.urls(model=Message, fields=["@id", "text", "conversation"], nested_fields=['conversation'])),
path('tasks/', LDPViewSet.urls(model=Task)),
path('conversations/', LDPViewSet.urls(model=Conversation, nested_fields=["message_set", "observers"])),
path('dummys/', LDPViewSet.urls(model=Dummy, lookup_field='slug',)),
path('permissionless-dummys/', LDPViewSet.urls(model=PermissionlessDummy, lookup_field='slug', permission_classes=[ACLPermissions])),
]
"""This module contains apps for testing."""
from django.apps import AppConfig
class DummyConfig(AppConfig):
# 'djangoldp.tests' is already registered as an installed app (it simulates a LDP package)
name = 'djangoldp.tests.dummy'
"""This module contains a dummy middleware for djangoldp testing."""
class DummyMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
source diff could not be displayed: it is too large. Options to address this: view the blob.
This diff is collapsed.
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import AbstractUser, Group
from django.db import models
from django.db.models import BinaryField, DateField
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.datetime_safe import date
from djangoldp.fields import LDPUrlField
from djangoldp.models import Model
from djangoldp.permissions import LDPPermissions
from djangoldp.models import Model, DynamicNestedField
from djangoldp.permissions import ACLPermissions, AuthenticatedOnly, ReadOnly, \
ReadAndCreate, AnonymousReadOnly, OwnerPermissions, InheritPermissions
from .permissions import Only2WordsForToto, ReadOnlyStartsWithA
class User(AbstractUser, Model):
class User(AbstractUser, Model):
class Meta(AbstractUser.Meta, Model.Meta):
ordering = ['pk']
serializer_fields = ['@id', 'username', 'first_name', 'last_name', 'email', 'userprofile',
'conversation_set', 'circle_set', 'projects']
anonymous_perms = ['view', 'add']
authenticated_perms = ['inherit', 'change']
owner_perms = ['inherit']
'conversation_set','groups', 'projects', 'owned_circles']
permission_classes = [ReadAndCreate|OwnerPermissions]
rdf_type = 'foaf:user'
nested_fields = ['owned_circles']
class Skill(Model):
......@@ -31,11 +30,12 @@ class Skill(Model):
return self.joboffer_set.filter(date__gte=date.today())
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
owner_perms = ['inherit', 'change', 'delete', 'control']
serializer_fields = ["@id", "title", "recent_jobs", "slug"]
ordering = ['pk']
permission_classes = [AnonymousReadOnly,ReadAndCreate|OwnerPermissions]
serializer_fields = ["@id", "title", "recent_jobs", "slug", "obligatoire"]
nested_fields = ['joboffer_set']
lookup_field = 'slug'
rdf_type = 'hd:skill'
class JobOffer(Model):
......@@ -51,12 +51,15 @@ class JobOffer(Model):
return self.skills.all().first()
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'change', 'add']
owner_perms = ['inherit', 'delete', 'control']
ordering = ['pk']
permission_classes = [AnonymousReadOnly, ReadOnly|OwnerPermissions]
serializer_fields = ["@id", "title", "skills", "recent_skills", "resources", "slug", "some_skill", "urlid"]
nested_fields = ['skills', 'resources', 'recent_skills']
container_path = "job-offers/"
lookup_field = 'slug'
rdf_type = 'hd:joboffer'
JobOffer.recent_skills.field = DynamicNestedField(Skill, 'recent_skills')
class Conversation(models.Model):
......@@ -64,11 +67,12 @@ class Conversation(models.Model):
author_user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
peer_user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name="peers_conv",
on_delete=models.DO_NOTHING)
observers = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='observed_conversations')
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
owner_perms = ['inherit', 'change', 'delete', 'control']
ordering = ['pk']
permission_classes = [AnonymousReadOnly,ReadAndCreate|OwnerPermissions]
nested_fields=["message_set", "observers"]
owner_field = 'author_user'
......@@ -77,33 +81,99 @@ class Resource(Model):
description = models.CharField(max_length=255)
class Meta(Model.Meta):
anonymous_perms = ['view', 'add', 'delete', 'change', 'control']
authenticated_perms = ['inherit']
owner_perms = ['inherit']
ordering = ['pk']
serializer_fields = ["@id", "joboffers"]
nested_fields = ['joboffers']
depth = 1
rdf_type = 'hd:Resource'
# a resource in which only the owner has permissions (for testing owner permissions)
class OwnedResource(Model):
description = models.CharField(max_length=255, blank=True, null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name="owned_resources",
on_delete=models.CASCADE)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [OwnerPermissions]
owner_field = 'user'
serializer_fields = ['@id', 'description', 'user']
nested_fields = ['owned_resources']
depth = 1
class OwnedResourceVariant(Model):
description = models.CharField(max_length=255, blank=True, null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name="owned_variant_resources",
on_delete=models.CASCADE)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [ReadOnly|OwnerPermissions]
owner_field = 'user'
serializer_fields = ['@id', 'description', 'user']
depth = 1
class OwnedResourceNestedOwnership(Model):
description = models.CharField(max_length=255, blank=True, null=True)
parent = models.ForeignKey(OwnedResource, blank=True, null=True, related_name="owned_resources",
on_delete=models.CASCADE)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [OwnerPermissions]
owner_field = 'parent__user'
serializer_fields = ['@id', 'description', 'parent']
nested_fields = ['owned_resources']
depth = 1
class OwnedResourceTwiceNestedOwnership(Model):
description = models.CharField(max_length=255, blank=True, null=True)
parent = models.ForeignKey(OwnedResourceNestedOwnership, blank=True, null=True, related_name="owned_resources",
on_delete=models.CASCADE)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [OwnerPermissions]
owner_field = 'parent__parent__user'
serializer_fields = ['@id', 'description', 'parent']
depth = 1
class UserProfile(Model):
description = models.CharField(max_length=255, blank=True, null=True)
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='userprofile', on_delete=models.CASCADE)
slug = models.SlugField(blank=True, null=True, unique=True)
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit']
owner_perms = ['inherit', 'change', 'control']
ordering = ['pk']
permission_classes = [AuthenticatedOnly,ReadOnly|OwnerPermissions]
owner_field = 'user'
lookup_field = 'slug'
serializer_fields = ['@id', 'description', 'settings', 'user']
depth = 1
class NotificationSetting(Model):
user = models.OneToOneField(UserProfile, on_delete=models.CASCADE, related_name="settings")
receiveMail = models.BooleanField(default=True)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [ReadAndCreate|OwnerPermissions]
class Message(models.Model):
text = models.CharField(max_length=255, blank=True, null=True)
conversation = models.ForeignKey(Conversation, on_delete=models.DO_NOTHING)
author_user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
owner_perms = ['inherit', 'change', 'delete', 'control']
ordering = ['pk']
permission_classes = [AnonymousReadOnly,ReadAndCreate|OwnerPermissions]
class Dummy(models.Model):
......@@ -111,46 +181,74 @@ class Dummy(models.Model):
slug = models.SlugField(blank=True, null=True, unique=True)
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
owner_perms = ['inherit', 'change', 'delete', 'control']
ordering = ['pk']
permission_classes = [AnonymousReadOnly,ReadAndCreate|OwnerPermissions]
class LDPDummy(Model):
some = models.CharField(max_length=255, blank=True, null=True)
class Meta(Model.Meta):
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
owner_perms = ['inherit', 'change', 'delete', 'control']
ordering = ['pk']
permission_classes = [AnonymousReadOnly,ReadAndCreate|OwnerPermissions]
nested_fields = ['anons']
# model used in django-guardian permission tests (no anonymous etc permissions set)
# model used in django-guardian permission tests (no permission to anyone except suuperusers)
class PermissionlessDummy(Model):
some = models.CharField(max_length=255, blank=True, null=True)
slug = models.SlugField(blank=True, null=True, unique=True)
parent = models.ForeignKey(LDPDummy, on_delete=models.DO_NOTHING, related_name="anons", blank=True, null=True)
class Meta(Model.Meta):
anonymous_perms = []
authenticated_perms = []
owner_perms = []
permissions = (
('custom_permission_permissionlessdummy', 'Custom Permission'),
)
ordering = ['pk']
permission_classes = [ACLPermissions]
lookup_field='slug'
permissions = (('custom_permission_permissionlessdummy', 'Custom Permission'),)
class Post(Model):
content = models.CharField(max_length=255)
author = models.ForeignKey(UserProfile, blank=True, null=True, on_delete=models.SET_NULL)
author = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
peer_user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name="peers_post",
on_delete=models.SET_NULL)
class Meta(Model.Meta):
ordering = ['pk']
auto_author = 'author'
auto_author_field = 'userprofile'
anonymous_perms = ['view', 'add', 'delete', 'add', 'change', 'control']
authenticated_perms = ['inherit']
owner_perms = ['inherit']
rdf_type = 'hd:post'
class AnonymousReadOnlyPost(Model):
content = models.CharField(max_length=255)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [AnonymousReadOnly]
class AuthenticatedOnlyPost(Model):
content = models.CharField(max_length=255)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [AuthenticatedOnly]
class ReadOnlyPost(Model):
content = models.CharField(max_length=255)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [ReadOnly]
class ReadAndCreatePost(Model):
content = models.CharField(max_length=255)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [ReadAndCreate]
class ANDPermissionsDummy(Model):
title = models.CharField(max_length=255)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [ReadOnlyStartsWithA&Only2WordsForToto]
class ORPermissionsDummy(Model):
title = models.CharField(max_length=255)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [ReadOnlyStartsWithA|Only2WordsForToto]
class Invoice(Model):
......@@ -158,22 +256,73 @@ class Invoice(Model):
date = models.DateField(blank=True, null=True)
class Meta(Model.Meta):
ordering = ['pk']
depth = 2
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
owner_perms = ['inherit', 'change', 'delete', 'control']
permission_classes = [AnonymousReadOnly,ReadAndCreate|OwnerPermissions]
nested_fields = ['batches']
class Circle(Model):
name = models.CharField(max_length=255, blank=True)
description = models.CharField(max_length=255, blank=True)
team = models.ManyToManyField(settings.AUTH_USER_MODEL, through="CircleMember", blank=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="owned_circles", on_delete=models.DO_NOTHING, null=True, blank=True)
members = models.OneToOneField(Group, related_name="circle", on_delete=models.SET_NULL, null=True, blank=True)
admins = models.OneToOneField(Group, related_name="admin_circle", on_delete=models.SET_NULL, null=True, blank=True)
class Meta(Model.Meta):
ordering = ['pk']
auto_author = 'owner'
depth = 1
permission_classes = [AnonymousReadOnly,ReadAndCreate|OwnerPermissions|ACLPermissions]
permission_roles = {
'members': {'perms': ['view'], 'add_author': True},
'admins': {'perms': ['view', 'change', 'control'], 'add_author': True},
}
serializer_fields = ['@id', 'name', 'description', 'members', 'owner', 'space']
rdf_type = 'hd:circle'
Group._meta.inherit_permissions += ['circle','admin_circle']
Group._meta.serializer_fields += ['circle', 'admin_circle']
class RestrictedCircle(Model):
name = models.CharField(max_length=255, blank=True)
description = models.CharField(max_length=255, blank=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="owned_restrictedcircles", on_delete=models.DO_NOTHING, null=True, blank=True)
members = models.ForeignKey(Group, related_name="restrictedcircles", on_delete=models.SET_NULL, null=True, blank=True)
admins = models.ForeignKey(Group, related_name="admin_restrictedcircles", on_delete=models.SET_NULL, null=True, blank=True)
class Meta(Model.Meta):
anonymous_perms = ['view', 'add', 'delete', 'add', 'change', 'control']
authenticated_perms = ["inherit"]
ordering = ['pk']
auto_author = 'owner'
permission_classes = [ACLPermissions]
permission_roles = {
'members': {'perms': ['view'], 'add_author': True},
'admins': {'perms': ['view', 'change', 'control'], 'add_author': True},
}
rdf_type = 'hd:circle'
class RestrictedResource(Model):
content = models.CharField(max_length=255, blank=True)
circle = models.ForeignKey(RestrictedCircle, on_delete=models.CASCADE)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [InheritPermissions]
inherit_permissions = ['circle']
class DoubleInheritModel(Model):
content = models.CharField(max_length=255, blank=True)
ro_ancestor = models.ForeignKey(ReadOnlyPost, on_delete=models.CASCADE, null=True, blank=True)
circle = models.ForeignKey(RestrictedCircle, on_delete=models.CASCADE, null=True, blank=True)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [InheritPermissions]
inherit_permissions = ['circle', 'ro_ancestor']
class Space(Model):
name = models.CharField(max_length=255, blank=True)
circle = models.OneToOneField(to=Circle, null=True, blank=True, on_delete=models.CASCADE, related_name='space')
class Meta(Model.Meta):
ordering = ['pk']
class Batch(Model):
......@@ -181,24 +330,11 @@ class Batch(Model):
title = models.CharField(max_length=255, blank=True, null=True)
class Meta(Model.Meta):
ordering = ['pk']
serializer_fields = ['@id', 'title', 'invoice', 'tasks']
anonymous_perms = ['view', 'add']
authenticated_perms = ['inherit', 'add']
owner_perms = ['inherit', 'change', 'delete', 'control']
permission_classes = [ReadAndCreate|OwnerPermissions]
depth = 1
class CircleMember(Model):
circle = models.ForeignKey(Circle, on_delete=models.CASCADE, related_name='members')
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="circles")
is_admin = models.BooleanField(default=False)
class Meta(Model.Meta):
container_path = "circle-members/"
anonymous_perms = ['view', 'add', 'delete', 'add', 'change', 'control']
authenticated_perms = ['inherit']
unique_together = ['user', 'circle']
rdf_type = 'hd:circlemember'
rdf_type = 'hd:batch'
class Task(models.Model):
......@@ -206,20 +342,30 @@ class Task(models.Model):
title = models.CharField(max_length=255)
class Meta(Model.Meta):
ordering = ['pk']
serializer_fields = ['@id', 'title', 'batch']
anonymous_perms = ['view']
authenticated_perms = ['inherit', 'add']
owner_perms = ['inherit', 'change', 'delete', 'control']
permission_classes = [AnonymousReadOnly,ReadAndCreate|OwnerPermissions]
class ModelTask(Model, Task):
class Meta(Model.Meta):
ordering = ['pk']
STATUS_CHOICES = [
('Public', 'Public'),
('Private', 'Private'),
('Archived', 'Archived'),
]
class Project(Model):
description = models.CharField(max_length=255, null=True, blank=False)
team = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='projects')
status = models.CharField(max_length=8, choices=STATUS_CHOICES, default='Private', null=True, blank=True)
members = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='projects')
class Meta(Model.Meta):
anonymous_perms = ['view', 'add', 'delete', 'add', 'change', 'control']
authenticated_perms = ["inherit"]
ordering = ['pk']
rdf_type = 'hd:project'
nested_fields = ['members']
class DateModel(Model):
......@@ -227,6 +373,7 @@ class DateModel(Model):
value = models.DateField()
class Meta(Model.Meta):
ordering = ['pk']
rdf_type = "hd:date"
serializer_fields_exclude = ['excluded']
......@@ -235,9 +382,21 @@ class DateChild(Model):
parent = models.ForeignKey(DateModel, on_delete=models.CASCADE, related_name='children')
class Meta(Model.Meta):
ordering = ['pk']
rdf_type = 'hd:datechild'
@receiver(post_save, sender=User)
def update_perms(sender, instance, created, **kwargs):
LDPPermissions.invalidate_cache()
class MyAbstractModel(Model):
defaultsomething = models.CharField(max_length=255, blank=True)
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [ACLPermissions]
abstract = True
rdf_type = "wow:defaultrdftype"
class NoSuperUsersAllowedModel(Model):
class Meta(Model.Meta):
ordering = ['pk']
permission_classes = [ACLPermissions]
\ No newline at end of file