add object permissions with guardian; users only have access to their own streams/restreamconfigs
This commit is contained in:
parent
b16e9c955c
commit
730889b9a1
|
@ -0,0 +1,10 @@
|
|||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db.models import Q
|
||||
from guardian.models import UserObjectPermission
|
||||
from guardian.models import GroupObjectPermission
|
||||
|
||||
|
||||
def remove_obj_perms_connected_with_user(sender, instance, **kwargs):
|
||||
filters = Q(content_type=ContentType.objects.get_for_model(instance), object_pk=instance.pk)
|
||||
UserObjectPermission.objects.filter(filters).delete()
|
||||
GroupObjectPermission.objects.filter(filters).delete()
|
|
@ -36,6 +36,7 @@ INSTALLED_APPS = [
|
|||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'guardian',
|
||||
'django_registration',
|
||||
'bootstrap4',
|
||||
'fa',
|
||||
|
@ -55,6 +56,11 @@ MIDDLEWARE = [
|
|||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
'guardian.backends.ObjectPermissionBackend',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'portier.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
django>=3.0
|
||||
django-registration>=3.1
|
||||
django-bootstrap4
|
||||
django-guardian
|
||||
django-fa
|
||||
celery>=4.4
|
||||
gunicorn>=20
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
from django.contrib import admin
|
||||
from guardian.admin import GuardedModelAdmin
|
||||
from .models import RestreamConfig
|
||||
|
||||
|
||||
class RestreamConfigAdmin(admin.ModelAdmin):
|
||||
class RestreamConfigAdmin(GuardedModelAdmin):
|
||||
fields = ['name', 'active', 'stream', 'target']
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
from django.forms import ModelForm
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from . import models
|
||||
|
||||
|
||||
class RestreamConfigFilteredStreamForm(ModelForm):
|
||||
class Meta:
|
||||
model = models.RestreamConfig
|
||||
fields = ['name', 'stream', 'target', 'active']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
user = kwargs.pop('user', None)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# limit the stream selection to user-accessible streams
|
||||
self.fields['stream'].queryset = get_objects_for_user(user, 'rtmp.view_stream')
|
|
@ -1,6 +1,8 @@
|
|||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.db.models.signals import pre_delete
|
||||
from portier.common import handlers
|
||||
|
||||
from rtmp.models import Stream
|
||||
|
||||
|
@ -23,3 +25,6 @@ class RestreamConfig(models.Model):
|
|||
|
||||
def __str__(self):
|
||||
return '{} to {}'.format(self.stream, self.name)
|
||||
|
||||
|
||||
pre_delete.connect(handlers.remove_obj_perms_connected_with_user, sender=RestreamConfig)
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
{% load i18n %}
|
||||
{% load bootstrap4 %}
|
||||
{% load font_awesome %}
|
||||
{% load guardian_tags %}
|
||||
|
||||
{% block 'content' %}
|
||||
<h6>{% trans "restreamconfig_configuration_header" %}</h6>
|
||||
<hr class="my-4">
|
||||
|
@ -19,15 +21,20 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
{% for object in object_list %}
|
||||
{% get_obj_perms user for object as "obj_perms" %}
|
||||
{% if "view_restreamconfig" in obj_perms %}
|
||||
<tr>
|
||||
<th scope="ro">{{ object.name }}</th>
|
||||
<td align="right">
|
||||
<div class="btn-group" role="group">
|
||||
<a href="{% url 'restream:restreamconfig_detail' pk=object.pk %}" type="button" class="btn btn-sm btn-primary">{% trans "details" %}</a>
|
||||
{% if "delete_restreamconfig" in obj_perms %}
|
||||
<a href="{% url 'restream:restreamconfig_delete' pk=object.pk %}" type="button" class="btn btn-sm btn-danger">{% fa 'trash' %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -2,27 +2,54 @@ from django.urls import reverse_lazy
|
|||
from django.contrib.auth.decorators import login_required
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.generic import ListView, DetailView, CreateView, DeleteView
|
||||
from guardian.decorators import permission_required_or_403
|
||||
from guardian.shortcuts import assign_perm
|
||||
|
||||
from . import models
|
||||
from . import forms
|
||||
|
||||
|
||||
@method_decorator(login_required, name='dispatch')
|
||||
@method_decorator(permission_required_or_403('restream.add_restreamconfig'),
|
||||
name='dispatch')
|
||||
class RestreamConfigList(ListView):
|
||||
model = models.RestreamConfig
|
||||
|
||||
|
||||
@method_decorator(login_required, name='dispatch')
|
||||
@method_decorator(permission_required_or_403('restream.view_restreamconfig',
|
||||
(models.RestreamConfig, 'pk', 'pk')),
|
||||
name='dispatch')
|
||||
class RestreamConfigDetail(DetailView):
|
||||
model = models.RestreamConfig
|
||||
|
||||
|
||||
@method_decorator(login_required, name='dispatch')
|
||||
@method_decorator(permission_required_or_403('restream.add_restreamconfig'),
|
||||
name='dispatch')
|
||||
class RestreamConfigCreate(CreateView):
|
||||
model = models.RestreamConfig
|
||||
fields = ["name", "stream", "target", "active"]
|
||||
form_class = forms.RestreamConfigFilteredStreamForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs['user'] = self.request.user
|
||||
return kwargs
|
||||
|
||||
def form_valid(self, form):
|
||||
valid = super().form_valid(form)
|
||||
if valid:
|
||||
user = self.request.user
|
||||
assign_perm('view_restreamconfig', user, self.object)
|
||||
assign_perm('change_restreamconfig', user, self.object)
|
||||
assign_perm('delete_restreamconfig', user, self.object)
|
||||
return valid
|
||||
|
||||
|
||||
@method_decorator(login_required, name='dispatch')
|
||||
@method_decorator(permission_required_or_403('restream.delete_restreamconfig',
|
||||
(models.RestreamConfig, 'pk', 'pk')),
|
||||
name='dispatch')
|
||||
class RestreamConfigDelete(DeleteView):
|
||||
model = models.RestreamConfig
|
||||
success_url = reverse_lazy('restream:restreamconfig_list')
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
from django.contrib import admin
|
||||
from guardian.admin import GuardedModelAdmin
|
||||
from .models import Application, Stream
|
||||
|
||||
|
||||
class ApplicationAdmin(admin.ModelAdmin):
|
||||
class ApplicationAdmin(GuardedModelAdmin):
|
||||
fields = ['name']
|
||||
|
||||
|
||||
class StreamAdmin(admin.ModelAdmin):
|
||||
class StreamAdmin(GuardedModelAdmin):
|
||||
fields = ['application', 'stream', 'name', 'publish_counter']
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import uuid
|
||||
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
import uuid
|
||||
from django.db.models.signals import pre_delete
|
||||
from portier.common import handlers
|
||||
|
||||
from . import signals
|
||||
|
||||
|
@ -66,3 +69,7 @@ class Stream(models.Model):
|
|||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
pre_delete.connect(handlers.remove_obj_perms_connected_with_user, sender=Application)
|
||||
pre_delete.connect(handlers.remove_obj_perms_connected_with_user, sender=Stream)
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
{% load i18n %}
|
||||
{% load bootstrap4 %}
|
||||
{% load font_awesome %}
|
||||
{% load guardian_tags %}
|
||||
|
||||
{% block 'content' %}
|
||||
<h6>{% trans "stream_configuration_header" %}</h6>
|
||||
<hr class="my-4">
|
||||
|
@ -19,15 +21,20 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
{% for object in object_list %}
|
||||
{% get_obj_perms user for object as "obj_perms" %}
|
||||
{% if "view_stream" in obj_perms %}
|
||||
<tr>
|
||||
<th scope="ro">{{ object.name }}</th>
|
||||
<td align="right">
|
||||
<div class="btn-group" role="group">
|
||||
<a href="{% url 'rtmp:stream_detail' pk=object.pk %}" type="button" class="btn btn-sm btn-primary">{% trans "details" %}</a>
|
||||
{% if "delete_stream" in obj_perms %}
|
||||
<a href="{% url 'rtmp:stream_delete' pk=object.pk %}" type="button" class="btn btn-sm btn-danger">{% fa 'trash' %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -9,6 +9,8 @@ from django.contrib.admin.utils import NestedObjects
|
|||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import ListView, DetailView, CreateView, DeleteView
|
||||
from guardian.decorators import permission_required_or_403
|
||||
from guardian.shortcuts import assign_perm
|
||||
|
||||
from . import models
|
||||
|
||||
|
@ -48,22 +50,41 @@ def callback_srs(request):
|
|||
|
||||
|
||||
@method_decorator(login_required, name='dispatch')
|
||||
@method_decorator(permission_required_or_403('rtmp.add_stream'),
|
||||
name='dispatch')
|
||||
class StreamList(ListView):
|
||||
model = models.Stream
|
||||
|
||||
|
||||
@method_decorator(login_required, name='dispatch')
|
||||
@method_decorator(permission_required_or_403('rtmp.view_stream',
|
||||
(models.Stream, 'pk', 'pk')),
|
||||
name='dispatch')
|
||||
class StreamDetail(DetailView):
|
||||
model = models.Stream
|
||||
|
||||
|
||||
@method_decorator(login_required, name='dispatch')
|
||||
@method_decorator(permission_required_or_403('rtmp.add_stream'),
|
||||
name='dispatch')
|
||||
class StreamCreate(CreateView):
|
||||
model = models.Stream
|
||||
fields = ["name", "application"]
|
||||
|
||||
def form_valid(self, form):
|
||||
valid = super().form_valid(form)
|
||||
if valid:
|
||||
user = self.request.user
|
||||
assign_perm('view_stream', user, self.object)
|
||||
assign_perm('change_stream', user, self.object)
|
||||
assign_perm('delete_stream', user, self.object)
|
||||
return valid
|
||||
|
||||
|
||||
@method_decorator(login_required, name='dispatch')
|
||||
@method_decorator(permission_required_or_403('rtmp.delete_stream',
|
||||
(models.Stream, 'pk', 'pk')),
|
||||
name='dispatch')
|
||||
class StreamDelete(DeleteView):
|
||||
model = models.Stream
|
||||
success_url = reverse_lazy('rtmp:stream_list')
|
||||
|
|
Loading…
Reference in New Issue