View only user (#539)
* Remove repo docs in favor of hosted docs (#537) * updated base, channel, video htmls to hide elements based on if user is staff or in the group 'admin' * added the load auth_extras * updated auth_extras * updated views.py to block api calls from deleting files from unprivileged users; The Templates needed to be updated to support the various group checks related to removing buttons an unprivileged user should not see * bumped the channel templates to remove conflict * fix linting issues * more linting --------- Co-authored-by: Merlin <4706504+MerlinScheurer@users.noreply.github.com>
This commit is contained in:
parent
446d5b7949
commit
e1fce06f97
|
@ -2,6 +2,8 @@
|
|||
|
||||
from api.src.aggs import BiggestChannel, DownloadHist, Primary, WatchProgress
|
||||
from api.src.search_processor import SearchProcess
|
||||
from django.contrib.auth.decorators import user_passes_test
|
||||
from django.utils.decorators import method_decorator
|
||||
from home.src.download.queue import PendingInteract
|
||||
from home.src.download.subscriptions import (
|
||||
ChannelSubscription,
|
||||
|
@ -39,6 +41,11 @@ from rest_framework.response import Response
|
|||
from rest_framework.views import APIView
|
||||
|
||||
|
||||
def check_admin(user):
|
||||
"""if user has access to restricted views"""
|
||||
return user.is_staff or user.groups.filter(name="admin").exists()
|
||||
|
||||
|
||||
class ApiBaseView(APIView):
|
||||
"""base view to inherit from"""
|
||||
|
||||
|
@ -109,6 +116,7 @@ class VideoApiView(ApiBaseView):
|
|||
self.get_document(video_id)
|
||||
return Response(self.response, status=self.status_code)
|
||||
|
||||
@method_decorator(user_passes_test(check_admin), name="dispatch")
|
||||
def delete(self, request, video_id):
|
||||
# pylint: disable=unused-argument
|
||||
"""delete single video"""
|
||||
|
@ -165,7 +173,6 @@ class VideoProgressView(ApiBaseView):
|
|||
message = {"position": position, "youtube_id": video_id}
|
||||
RedisArchivist().set_message(key, message)
|
||||
self.response = request.data
|
||||
|
||||
return Response(self.response)
|
||||
|
||||
def delete(self, request, video_id):
|
||||
|
@ -283,6 +290,7 @@ class ChannelApiView(ApiBaseView):
|
|||
self.get_document(channel_id)
|
||||
return Response(self.response, status=self.status_code)
|
||||
|
||||
@method_decorator(user_passes_test(check_admin), name="dispatch")
|
||||
def delete(self, request, channel_id):
|
||||
# pylint: disable=unused-argument
|
||||
"""delete channel"""
|
||||
|
@ -328,6 +336,7 @@ class ChannelApiListView(ApiBaseView):
|
|||
|
||||
return Response(self.response)
|
||||
|
||||
@method_decorator(user_passes_test(check_admin), name="dispatch")
|
||||
def post(self, request):
|
||||
"""subscribe/unsubscribe to list of channels"""
|
||||
data = request.data
|
||||
|
@ -520,6 +529,7 @@ class DownloadApiView(ApiBaseView):
|
|||
self.get_document(video_id)
|
||||
return Response(self.response, status=self.status_code)
|
||||
|
||||
@method_decorator(user_passes_test(check_admin), name="dispatch")
|
||||
def post(self, request, video_id):
|
||||
"""post to video to change status"""
|
||||
item_status = request.data.get("status")
|
||||
|
@ -540,6 +550,7 @@ class DownloadApiView(ApiBaseView):
|
|||
|
||||
return Response(request.data)
|
||||
|
||||
@method_decorator(user_passes_test(check_admin), name="dispatch")
|
||||
@staticmethod
|
||||
def delete(request, video_id):
|
||||
# pylint: disable=unused-argument
|
||||
|
@ -585,6 +596,7 @@ class DownloadApiListView(ApiBaseView):
|
|||
self.get_document_list(request)
|
||||
return Response(self.response)
|
||||
|
||||
@method_decorator(user_passes_test(check_admin), name="dispatch")
|
||||
@staticmethod
|
||||
def post(request):
|
||||
"""add list of videos to download queue"""
|
||||
|
@ -610,6 +622,7 @@ class DownloadApiListView(ApiBaseView):
|
|||
|
||||
return Response(data)
|
||||
|
||||
@method_decorator(user_passes_test(check_admin), name="dispatch")
|
||||
def delete(self, request):
|
||||
"""delete download queue"""
|
||||
query_filter = request.GET.get("filter", False)
|
||||
|
@ -661,6 +674,7 @@ class LoginApiView(ObtainAuthToken):
|
|||
return Response({"token": token.key, "user_id": user.pk})
|
||||
|
||||
|
||||
@method_decorator(user_passes_test(check_admin), name="dispatch")
|
||||
class SnapshotApiListView(ApiBaseView):
|
||||
"""resolves to /api/snapshot/
|
||||
GET: returns snapshot config plus list of existing snapshots
|
||||
|
@ -684,6 +698,7 @@ class SnapshotApiListView(ApiBaseView):
|
|||
return Response(response)
|
||||
|
||||
|
||||
@method_decorator(user_passes_test(check_admin), name="dispatch")
|
||||
class SnapshotApiView(ApiBaseView):
|
||||
"""resolves to /api/snapshot/<snapshot-id>/
|
||||
GET: return a single snapshot
|
||||
|
@ -738,6 +753,7 @@ class TaskListView(ApiBaseView):
|
|||
return Response(all_results)
|
||||
|
||||
|
||||
@method_decorator(user_passes_test(check_admin), name="dispatch")
|
||||
class TaskNameListView(ApiBaseView):
|
||||
"""resolves to /api/task-name/<task-name>/
|
||||
GET: return a list of stored results of task
|
||||
|
@ -776,6 +792,7 @@ class TaskNameListView(ApiBaseView):
|
|||
return Response({"message": message})
|
||||
|
||||
|
||||
@method_decorator(user_passes_test(check_admin), name="dispatch")
|
||||
class TaskIDView(ApiBaseView):
|
||||
"""resolves to /api/task-id/<task-id>/
|
||||
GET: return details of task id
|
||||
|
@ -827,6 +844,7 @@ class TaskIDView(ApiBaseView):
|
|||
return f"message:{task_conf.get('group')}:{task_id.split('-')[0]}"
|
||||
|
||||
|
||||
@method_decorator(user_passes_test(check_admin), name="dispatch")
|
||||
class RefreshView(ApiBaseView):
|
||||
"""resolves to /api/refresh/
|
||||
GET: get refresh progress
|
||||
|
@ -948,6 +966,7 @@ class SearchView(ApiBaseView):
|
|||
return Response(search_results)
|
||||
|
||||
|
||||
@method_decorator(user_passes_test(check_admin), name="dispatch")
|
||||
class TokenView(ApiBaseView):
|
||||
"""resolves to /api/token/
|
||||
DELETE: revoke the token
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{% load static %}
|
||||
{% load auth_extras %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
@ -57,9 +58,11 @@
|
|||
<a href="{% url 'playlist' %}">
|
||||
<div class="nav-item">playlists</div>
|
||||
</a>
|
||||
{% if request.user|has_group:"admin" or request.user.is_staff %}
|
||||
<a href="{% url 'downloads' %}">
|
||||
<div class="nav-item">downloads</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="nav-icons">
|
||||
<a href="{% url 'search' %}">
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
{% load static %}
|
||||
{% load humanize %}
|
||||
{% block content %}
|
||||
{% load auth_extras %}
|
||||
<div class="boxed-content">
|
||||
<div class="title-split">
|
||||
<div class="title-bar">
|
||||
<h1>Channels</h1>
|
||||
</div>
|
||||
{% if request.user|has_group:"admin" or request.user.is_staff %}
|
||||
<div class="title-split-form">
|
||||
<img id="animate-icon" onclick="showForm()" src="{% static 'img/icon-add.svg' %}" alt="add-icon" title="Subscribe to Channels">
|
||||
<div class="show-form">
|
||||
|
@ -17,6 +19,7 @@
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="notifications" data="subscription"></div>
|
||||
<div class="view-controls">
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
{% block content %}
|
||||
{% load static %}
|
||||
{% load humanize %}
|
||||
{% load auth_extras %}
|
||||
|
||||
<div class="boxed-content">
|
||||
<div class="channel-banner">
|
||||
<a href="/channel/{{ channel_info.channel_id }}/"><img src="/cache/channels/{{ channel_info.channel_id }}_banner.jpg" alt="channel_banner"></a>
|
||||
|
@ -38,7 +40,9 @@
|
|||
<p>Subscribers: {{ channel_info.channel_subs|intcomma }}</p>
|
||||
{% endif %}
|
||||
{% if channel_info.channel_subscribed %}
|
||||
{% if request.user|has_group:"admin" or request.user.is_staff %}
|
||||
<button class="unsubscribe" type="button" data-type="channel" data-subscribe="" data-id="{{ channel_info.channel_id }}" onclick="subscribeStatus(this)" title="Unsubscribe from {{ channel_info.channel_name }}">Unsubscribe</button>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<button type="button" data-type="channel" data-subscribe="true" data-id="{{ channel_info.channel_id }}" onclick="subscribeStatus(this)" title="Subscribe to {{ channel_info.channel_name }}">Subscribe</button>
|
||||
{% endif %}
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
<a href="{% url 'channel_id' playlist.playlist_channel_id %}"><h3>{{ playlist.playlist_channel }}</h3></a>
|
||||
<a href="{% url 'playlist_id' playlist.playlist_id %}"><h2>{{ playlist.playlist_name }}</h2></a>
|
||||
<p>Last refreshed: {{ playlist.playlist_last_refresh }}</p>
|
||||
{% if playlist.playlist_subscribed %}
|
||||
{% if playlist.playlist_subscribed and request.user|has_group:"admin" or request.user.is_staff %}
|
||||
<button class="unsubscribe" type="button" data-type="playlist" data-subscribe="" data-id="{{ playlist.playlist_id }}" onclick="subscribeStatus(this)" title="Unsubscribe from {{ playlist.playlist_name }}">Unsubscribe</button>
|
||||
{% else %}
|
||||
<button type="button" data-type="playlist" data-subscribe="true" data-id="{{ playlist.playlist_id }}" onclick="subscribeStatus(this)" title="Subscribe to {{ playlist.playlist_name }}">Subscribe</button>
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
{% extends "home/base.html" %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
{% load auth_extras %}
|
||||
|
||||
<div class="boxed-content">
|
||||
<div class="title-split">
|
||||
<div class="title-bar">
|
||||
<h1>Playlists</h1>
|
||||
</div>
|
||||
{% if request.user|has_group:"admin" or request.user.is_staff %}
|
||||
|
||||
<div class="title-split-form">
|
||||
<img id="animate-icon" onclick="showForm()" src="{% static 'img/icon-add.svg' %}" alt="add-icon" title="Subscribe to Playlists">
|
||||
<div class="show-form">
|
||||
|
@ -16,6 +20,8 @@
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
<div id="notifications" data="subscription"></div>
|
||||
<div class="view-controls">
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
{% load static %}
|
||||
{% load humanize %}
|
||||
{% block content %}
|
||||
{% load auth_extras %}
|
||||
|
||||
<div class="boxed-content">
|
||||
<div class="title-bar">
|
||||
<h1>{{ playlist_info.playlist_name }}</h1>
|
||||
|
@ -27,7 +29,9 @@
|
|||
<p>Last refreshed: {{ playlist_info.playlist_last_refresh }}</p>
|
||||
<p>Playlist:
|
||||
{% if playlist_info.playlist_subscribed %}
|
||||
{% if request.user|has_group:"admin" or request.user.is_staff %}
|
||||
<button class="unsubscribe" type="button" data-type="playlist" data-subscribe="" data-id="{{ playlist_info.playlist_id }}" onclick="subscribeStatus(this)" title="Unsubscribe from {{ playlist_info.playlist_name }}">Unsubscribe</button>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<button type="button" data-type="playlist" data-subscribe="true" data-id="{{ playlist_info.playlist_id }}" onclick="subscribeStatus(this)" title="Subscribe to {{ playlist_info.playlist_name }}">Subscribe</button>
|
||||
{% endif %}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
{% block content %}
|
||||
{% load static %}
|
||||
{% load humanize %}
|
||||
{% load auth_extras %}
|
||||
<div id="player" class="player-wrapper">
|
||||
<div class="video-main">
|
||||
<div class="video-modal"><span class="video-modal-text"></span></div>
|
||||
|
@ -81,15 +82,19 @@
|
|||
{% if reindex %}
|
||||
<p>Reindex scheduled</p>
|
||||
{% else %}
|
||||
{% if request.user|has_group:"admin" or request.user.is_staff %}
|
||||
<div id="reindex-button" class="button-box">
|
||||
<button data-id="{{ video.youtube_id }}" data-type="video" onclick="reindex(this)" title="Reindex {{ video.title }}">Reindex</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if request.user|has_group:"admin" or request.user.is_staff %}
|
||||
<a download="" href="{{ video.media_url }}"><button id="download-item">Download File</button></a>
|
||||
<button onclick="deleteConfirm()" id="delete-item">Delete Video</button>
|
||||
<div class="delete-confirm" id="delete-button">
|
||||
<span>Are you sure? </span><button class="danger-button" onclick="deleteVideo(this)" data-id="{{ video.youtube_id }}" data-redirect = "{{ video.channel.channel_id }}">Delete</button> <button onclick="cancelDelete()">Cancel</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-box-item">
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter(name="has_group")
|
||||
def has_group(user, group_name):
|
||||
return user.groups.filter(name=group_name).exists()
|
Loading…
Reference in New Issue