forked from rc/aircox
- various __all__
- serializer: track search, reorder module files - autocomplete: allow simple string value selection - playlist editor: - ui & flow improve - init data - save user settings - autocomplete - fix bugs - discard changes
This commit is contained in:
@ -1,10 +1,11 @@
|
||||
from .article import Article
|
||||
from .page import Category, Page, StaticPage, Comment, NavItem
|
||||
from .program import Program, Stream, Schedule
|
||||
from .episode import Episode, Diffusion
|
||||
from .log import Log
|
||||
from .sound import Sound, Track
|
||||
from .station import Station, Port
|
||||
from .article import *
|
||||
from .page import *
|
||||
from .program import *
|
||||
from .episode import *
|
||||
from .log import *
|
||||
from .sound import *
|
||||
from .station import *
|
||||
from .user_settings import *
|
||||
|
||||
from . import signals
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .page import Page, PageQuerySet
|
||||
from .program import Program, ProgramChildQuerySet
|
||||
from .page import Page
|
||||
from .program import ProgramChildQuerySet
|
||||
|
||||
|
||||
__all__ = ('Article',)
|
||||
|
||||
|
||||
class Article(Page):
|
||||
|
@ -9,12 +9,12 @@ from django.utils.functional import cached_property
|
||||
from easy_thumbnails.files import get_thumbnailer
|
||||
|
||||
from aircox import settings, utils
|
||||
from .program import Program, ProgramChildQuerySet, \
|
||||
from .program import ProgramChildQuerySet, \
|
||||
BaseRerun, BaseRerunQuerySet, Schedule
|
||||
from .page import Page, PageQuerySet
|
||||
from .page import Page
|
||||
|
||||
|
||||
__all__ = ['Episode', 'Diffusion', 'DiffusionQuerySet']
|
||||
__all__ = ('Episode', 'Diffusion', 'DiffusionQuerySet')
|
||||
|
||||
|
||||
class Episode(Page):
|
||||
@ -31,9 +31,9 @@ class Episode(Page):
|
||||
""" Return serialized data about podcasts. """
|
||||
from ..serializers import PodcastSerializer
|
||||
podcasts = [PodcastSerializer(s).data
|
||||
for s in self.sound_set.public().order_by('type') ]
|
||||
for s in self.sound_set.public().order_by('type')]
|
||||
if self.cover:
|
||||
options = {'size': (128,128), 'crop':'scale'}
|
||||
options = {'size': (128, 128), 'crop': 'scale'}
|
||||
cover = get_thumbnailer(self.cover).get_thumbnail(options).url
|
||||
else:
|
||||
cover = None
|
||||
@ -84,7 +84,7 @@ class DiffusionQuerySet(BaseRerunQuerySet):
|
||||
def episode(self, episode=None, id=None):
|
||||
""" Diffusions for this episode """
|
||||
return self.filter(episode=episode) if id is None else \
|
||||
self.filter(episode__id=id)
|
||||
self.filter(episode__id=id)
|
||||
|
||||
def on_air(self):
|
||||
""" On air diffusions """
|
||||
@ -104,13 +104,13 @@ class DiffusionQuerySet(BaseRerunQuerySet):
|
||||
end = tz.datetime.combine(date, datetime.time(23, 59, 59, 999))
|
||||
# start = tz.get_current_timezone().localize(start)
|
||||
# end = tz.get_current_timezone().localize(end)
|
||||
qs = self.filter(start__range = (start, end))
|
||||
qs = self.filter(start__range=(start, end))
|
||||
return qs.order_by('start') if order else qs
|
||||
|
||||
def at(self, date, order=True):
|
||||
""" Return diffusions at specified date or datetime """
|
||||
return self.now(date, order) if isinstance(date, tz.datetime) else \
|
||||
self.date(date, order)
|
||||
self.date(date, order)
|
||||
|
||||
def after(self, date=None):
|
||||
"""
|
||||
@ -201,7 +201,7 @@ class Diffusion(BaseRerun):
|
||||
|
||||
def __str__(self):
|
||||
str_ = '{episode} - {date}'.format(
|
||||
self=self, episode=self.episode and self.episode.title,
|
||||
episode=self.episode and self.episode.title,
|
||||
date=self.local_start.strftime('%Y/%m/%d %H:%M%z'),
|
||||
)
|
||||
if self.initial:
|
||||
@ -324,5 +324,3 @@ class Diffusion(BaseRerun):
|
||||
'end': self.end,
|
||||
'episode': getattr(self, 'episode', None),
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,7 +20,7 @@ from .station import Station
|
||||
logger = logging.getLogger('aircox')
|
||||
|
||||
|
||||
__all__ = ['Log', 'LogQuerySet', 'LogArchiver']
|
||||
__all__ = ('Log', 'LogQuerySet', 'LogArchiver')
|
||||
|
||||
|
||||
class LogQuerySet(models.QuerySet):
|
||||
@ -31,7 +31,7 @@ class LogQuerySet(models.QuerySet):
|
||||
def date(self, date):
|
||||
start = tz.datetime.combine(date, datetime.time())
|
||||
end = tz.datetime.combine(date, datetime.time(23, 59, 59, 999))
|
||||
return self.filter(date__range = (start, end))
|
||||
return self.filter(date__range=(start, end))
|
||||
# this filter does not work with mysql
|
||||
# return self.filter(date__date=date)
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
from enum import IntEnum
|
||||
import re
|
||||
|
||||
from django.db import models
|
||||
@ -18,7 +17,8 @@ from model_utils.managers import InheritanceQuerySet
|
||||
from .station import Station
|
||||
|
||||
|
||||
__all__ = ['Category', 'PageQuerySet', 'Page', 'Comment', 'NavItem']
|
||||
__all__ = ('Category', 'PageQuerySet',
|
||||
'Page', 'StaticPage', 'Comment', 'NavItem')
|
||||
|
||||
|
||||
headline_re = re.compile(r'(<p>)?'
|
||||
|
@ -1,6 +1,5 @@
|
||||
import calendar
|
||||
from collections import OrderedDict
|
||||
import datetime
|
||||
from enum import IntEnum
|
||||
import logging
|
||||
import os
|
||||
@ -10,7 +9,7 @@ import pytz
|
||||
from django.conf import settings as conf
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.db.models import F, Q
|
||||
from django.db.models import F
|
||||
from django.db.models.functions import Concat, Substr
|
||||
from django.utils import timezone as tz
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@ -24,8 +23,8 @@ from .station import Station
|
||||
logger = logging.getLogger('aircox')
|
||||
|
||||
|
||||
__all__ = ['Program', 'ProgramQuerySet', 'Stream', 'Schedule',
|
||||
'ProgramChildQuerySet', 'BaseRerun', 'BaseRerunQuerySet']
|
||||
__all__ = ('Program', 'ProgramQuerySet', 'Stream', 'Schedule',
|
||||
'ProgramChildQuerySet', 'BaseRerun', 'BaseRerunQuerySet')
|
||||
|
||||
|
||||
class ProgramQuerySet(PageQuerySet):
|
||||
|
@ -2,7 +2,7 @@ import pytz
|
||||
|
||||
from django.contrib.auth.models import User, Group, Permission
|
||||
from django.db import transaction
|
||||
from django.db.models import F, signals
|
||||
from django.db.models import signals
|
||||
from django.dispatch import receiver
|
||||
from django.utils import timezone as tz
|
||||
|
||||
|
@ -1,17 +1,14 @@
|
||||
from enum import IntEnum
|
||||
import logging
|
||||
import os
|
||||
|
||||
from django.conf import settings as conf
|
||||
from django.db import models
|
||||
from django.db.models import Q, Value as V
|
||||
from django.db.models.functions import Concat
|
||||
from django.db.models import Q
|
||||
from django.utils import timezone as tz
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
from aircox import settings
|
||||
from .program import Program
|
||||
from .episode import Episode
|
||||
|
||||
@ -19,7 +16,7 @@ from .episode import Episode
|
||||
logger = logging.getLogger('aircox')
|
||||
|
||||
|
||||
__all__ = ['Sound', 'SoundQuerySet', 'Track']
|
||||
__all__ = ('Sound', 'SoundQuerySet', 'Track')
|
||||
|
||||
|
||||
class SoundQuerySet(models.QuerySet):
|
||||
|
@ -8,7 +8,7 @@ from filer.fields.image import FilerImageField
|
||||
from .. import settings
|
||||
|
||||
|
||||
__all__ = ['Station', 'StationQuerySet', 'Port']
|
||||
__all__ = ('Station', 'StationQuerySet', 'Port')
|
||||
|
||||
|
||||
class StationQuerySet(models.QuerySet):
|
||||
|
16
aircox/models/user_settings.py
Normal file
16
aircox/models/user_settings.py
Normal file
@ -0,0 +1,16 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class UserSettings(models.Model):
|
||||
"""
|
||||
Store user's settings.
|
||||
"""
|
||||
user = models.OneToOneField(
|
||||
User, models.CASCADE, verbose_name=_('User'),
|
||||
related_name='aircox_settings')
|
||||
playlist_editor_columns = models.JSONField(
|
||||
_('Playlist Editor Columns'))
|
||||
playlist_editor_sep = models.CharField(
|
||||
_('Playlist Editor Separator'), max_length=16)
|
3
aircox/serializers/__init__.py
Normal file
3
aircox/serializers/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
from .log import *
|
||||
from .sound import *
|
||||
from .admin import *
|
30
aircox/serializers/admin.py
Normal file
30
aircox/serializers/admin.py
Normal file
@ -0,0 +1,30 @@
|
||||
from rest_framework import serializers
|
||||
from taggit.serializers import TagListSerializerField, TaggitSerializer
|
||||
|
||||
from ..models import Track, UserSettings
|
||||
|
||||
|
||||
__all__ = ('TrackSerializer', 'UserSettingsSerializer')
|
||||
|
||||
|
||||
class TrackSerializer(TaggitSerializer, serializers.ModelSerializer):
|
||||
tags = TagListSerializerField()
|
||||
|
||||
class Meta:
|
||||
model = Track
|
||||
fields = ('pk', 'artist', 'title', 'album', 'year', 'position',
|
||||
'info', 'tags', 'episode', 'sound')
|
||||
|
||||
|
||||
class UserSettingsSerializer(serializers.ModelSerializer):
|
||||
# TODO: validate fields values (playlist_editor_columns at least)
|
||||
class Meta:
|
||||
model = UserSettings
|
||||
fields = ('playlist_editor_columns', 'playlist_editor_sep')
|
||||
|
||||
def create(self, validated_data):
|
||||
user = self.context.get('user')
|
||||
if user:
|
||||
validated_data['user_id'] = user.id
|
||||
return super().create(validated_data)
|
||||
|
@ -1,12 +1,9 @@
|
||||
from rest_framework import serializers
|
||||
from taggit.serializers import TagListSerializerField, TaggitSerializer
|
||||
|
||||
from .models import Diffusion, Log, Sound, Track
|
||||
from ..models import Diffusion, Log
|
||||
|
||||
|
||||
__all__ = ['LogInfo', 'LogInfoSerializer', 'SoundSerializer',
|
||||
'PodcastSerializer',
|
||||
'AdminTrackSerializer']
|
||||
__all__ = ('LogInfo', 'LogInfoSerializer')
|
||||
|
||||
|
||||
class LogInfo:
|
||||
@ -54,30 +51,3 @@ class LogInfoSerializer(serializers.Serializer):
|
||||
info = serializers.CharField(max_length=200, required=False)
|
||||
url = serializers.URLField(required=False)
|
||||
cover = serializers.URLField(required=False)
|
||||
|
||||
|
||||
class SoundSerializer(serializers.ModelSerializer):
|
||||
file = serializers.FileField(use_url=False)
|
||||
|
||||
class Meta:
|
||||
model = Sound
|
||||
fields = ['pk', 'name', 'program', 'episode', 'type', 'file',
|
||||
'duration', 'mtime', 'is_good_quality', 'is_public', 'url']
|
||||
|
||||
|
||||
class PodcastSerializer(serializers.ModelSerializer):
|
||||
# serializers.HyperlinkedIdentityField(view_name='sound', format='html')
|
||||
|
||||
class Meta:
|
||||
model = Sound
|
||||
fields = ['pk', 'name', 'program', 'episode', 'type',
|
||||
'duration', 'mtime', 'url', 'is_downloadable']
|
||||
|
||||
|
||||
class AdminTrackSerializer(TaggitSerializer, serializers.ModelSerializer):
|
||||
tags = TagListSerializerField()
|
||||
|
||||
class Meta:
|
||||
model = Track
|
||||
fields = ('pk', 'artist', 'title', 'album', 'year', 'position',
|
||||
'info', 'tags', 'episode', 'sound')
|
21
aircox/serializers/sound.py
Normal file
21
aircox/serializers/sound.py
Normal file
@ -0,0 +1,21 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from ..models import Sound
|
||||
|
||||
|
||||
class SoundSerializer(serializers.ModelSerializer):
|
||||
file = serializers.FileField(use_url=False)
|
||||
|
||||
class Meta:
|
||||
model = Sound
|
||||
fields = ['pk', 'name', 'program', 'episode', 'type', 'file',
|
||||
'duration', 'mtime', 'is_good_quality', 'is_public', 'url']
|
||||
|
||||
|
||||
class PodcastSerializer(serializers.ModelSerializer):
|
||||
# serializers.HyperlinkedIdentityField(view_name='sound', format='html')
|
||||
|
||||
class Meta:
|
||||
model = Sound
|
||||
fields = ['pk', 'name', 'program', 'episode', 'type',
|
||||
'duration', 'mtime', 'url', 'is_downloadable']
|
@ -16,7 +16,7 @@
|
||||
\**********************/
|
||||
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _assets_styles_scss__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./assets/styles.scss */ \"./src/assets/styles.scss\");\n/* harmony import */ var _assets_admin_scss__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./assets/admin.scss */ \"./src/assets/admin.scss\");\n/* harmony import */ var _index_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./index.js */ \"./src/index.js\");\n/* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./app */ \"./src/app.js\");\n/* harmony import */ var _components__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./components */ \"./src/components/index.js\");\n\n\n\n\n\nconst AdminApp = {\n ..._app__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n components: {\n ..._app__WEBPACK_IMPORTED_MODULE_3__[\"default\"].components,\n ..._components__WEBPACK_IMPORTED_MODULE_4__.admin\n }\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = (AdminApp);\nwindow.App = AdminApp;\n\n//# sourceURL=webpack://aircox-assets/./src/admin.js?");
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _assets_styles_scss__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./assets/styles.scss */ \"./src/assets/styles.scss\");\n/* harmony import */ var _assets_admin_scss__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./assets/admin.scss */ \"./src/assets/admin.scss\");\n/* harmony import */ var _index_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./index.js */ \"./src/index.js\");\n/* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./app */ \"./src/app.js\");\n/* harmony import */ var _components__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./components */ \"./src/components/index.js\");\n/* harmony import */ var _track__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./track */ \"./src/track.js\");\n\n\n\n\n\n\nconst AdminApp = {\n ..._app__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n components: {\n ..._app__WEBPACK_IMPORTED_MODULE_3__[\"default\"].components,\n ..._components__WEBPACK_IMPORTED_MODULE_4__.admin\n },\n data() {\n return {\n ...super.data,\n Track: _track__WEBPACK_IMPORTED_MODULE_5__[\"default\"]\n };\n }\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = (AdminApp);\nwindow.App = AdminApp;\n\n//# sourceURL=webpack://aircox-assets/./src/admin.js?");
|
||||
|
||||
/***/ }),
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,17 +1,16 @@
|
||||
{% comment %}Inline block to edit playlists{% endcomment %}
|
||||
{% load aircox aircox_admin static i18n %}
|
||||
|
||||
{# include "adminsortable2/edit_inline/tabular-django-4.1.html" #}
|
||||
{% with inline_admin_formset as admin_formset %}
|
||||
{% with admin_formset.formset as formset %}
|
||||
|
||||
<script id="{{ formset.prefix }}-init-data">
|
||||
{{ formset|inline_data|json }}
|
||||
</script>
|
||||
<div id="inline-tracks" class="box mb-5">
|
||||
{{ admin_formset.non_form_errors }}
|
||||
|
||||
<a-playlist-editor data-el="{{ formset.prefix }}-init-data"
|
||||
<a-playlist-editor
|
||||
:labels="{% track_inline_labels %}"
|
||||
:init-data="{% track_inline_data formset=formset %}"
|
||||
settings-url="{% url "api:user-settings" %}"
|
||||
data-prefix="{{ formset.prefix }}-">
|
||||
<template #title>
|
||||
<h5 class="title is-4">{% trans "Playlist" %}</h5>
|
||||
@ -57,13 +56,21 @@
|
||||
{% if not field.widget.is_hidden and not field.is_readonly %}
|
||||
<template v-slot:row-{{ field.name }}="{item,col,row,value,attr,emit}">
|
||||
<div class="field">
|
||||
{% if field.name in 'artist,title,album' %}
|
||||
<a-autocomplete
|
||||
:input-class="['input', item.error(attr) ? 'is-danger' : 'half-field']"
|
||||
url="{% url 'api:track-autocomplete' %}?{{ field.name }}=${query}&field={{ field.name }}"
|
||||
{% else %}
|
||||
<div class="control">
|
||||
<input type="{{ widget.type }}"
|
||||
:class="['input', item.error(attr) ? 'is-danger' : 'half-field']"
|
||||
{% endif %}
|
||||
:name="'{{ formset.prefix }}-' + row + '-{{ field.name }}'"
|
||||
v-model="item.data[attr]"
|
||||
@change="emit('change', col)"/>
|
||||
{% if field.name not in 'artist,title,album' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<p v-for="error in item.error(attr)" class="help is-danger">
|
||||
[[ error ]] !
|
||||
</p>
|
||||
|
@ -1,5 +1,14 @@
|
||||
import json
|
||||
from django import template
|
||||
from django.contrib import admin
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _, gettext as __
|
||||
|
||||
from aircox.serializers.admin import UserSettingsSerializer
|
||||
|
||||
|
||||
__all__ = ('register', 'do_get_admin_tools', 'do_track_inline_data',
|
||||
'do_track_inline_column_labels')
|
||||
|
||||
|
||||
register = template.Library()
|
||||
@ -10,8 +19,14 @@ def do_get_admin_tools():
|
||||
return admin.site.get_tools()
|
||||
|
||||
|
||||
@register.filter(name='inline_data')
|
||||
def do_inline_data(formset):
|
||||
@register.simple_tag(name='track_inline_data', takes_context=True)
|
||||
def do_track_inline_data(context, formset, safe_string=False):
|
||||
"""
|
||||
Return initial data for playlist editor as dict. Keys are:
|
||||
- ``items``: list of items. Extra keys:
|
||||
- ``__error__``: dict of form fields errors
|
||||
- ``settings``: user's settings
|
||||
"""
|
||||
items = []
|
||||
for form in formset.forms:
|
||||
item = {name: form[name].value()
|
||||
@ -23,5 +38,23 @@ def do_inline_data(formset):
|
||||
if tags and not isinstance(tags, str):
|
||||
item['tags'] = ', '.join(tag.name for tag in tags)
|
||||
items.append(item)
|
||||
return {"items": items}
|
||||
|
||||
|
||||
data = {"items": items}
|
||||
user = context['request'].user
|
||||
settings = getattr(user, 'aircox_settings', None)
|
||||
data['settings'] = settings and UserSettingsSerializer(settings).data
|
||||
source = json.dumps(data)
|
||||
return safe_string and mark_safe(source) or source
|
||||
|
||||
|
||||
@register.simple_tag(name='track_inline_labels')
|
||||
def do_track_inline_labels():
|
||||
""" Return labels for columns in playlist editor as dict """
|
||||
return json.dumps({
|
||||
'artist': __('Artist'), 'album': __('Album'), 'title': __('Title'),
|
||||
'tags': __('Tags'), 'year': __('Year'),
|
||||
'save_settings': __('Save Settings'),
|
||||
'discard_changes': __('Discard changes'),
|
||||
'columns': __('Columns'),
|
||||
})
|
||||
|
||||
|
@ -24,10 +24,14 @@ register_converter(WeekConverter, 'week')
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register('sound', viewsets.SoundViewSet, basename='sound')
|
||||
router.register('track', viewsets.TrackROViewSet, basename='track')
|
||||
|
||||
|
||||
api = [
|
||||
path('logs/', views.LogListAPIView.as_view(), name='live'),
|
||||
path('user/settings/', viewsets.UserSettingsViewSet.as_view(
|
||||
{'get': 'retrieve', 'post': 'update', 'put': 'update'}),
|
||||
name='user-settings'),
|
||||
] + router.urls
|
||||
|
||||
|
||||
|
@ -62,6 +62,7 @@ class BaseView(TemplateResponseMixin, ContextMixin):
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
# FIXME: rename to sth like [Base]?StationAPIView
|
||||
class BaseAPIView:
|
||||
@property
|
||||
def station(self):
|
||||
|
@ -1,13 +1,18 @@
|
||||
from django.db.models import Q
|
||||
|
||||
from rest_framework import viewsets
|
||||
from rest_framework import status, viewsets
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from django_filters import rest_framework as filters
|
||||
|
||||
from .models import Sound
|
||||
from .serializers import SoundSerializer
|
||||
from .models import Sound, Track
|
||||
from .serializers import SoundSerializer, admin
|
||||
from .views import BaseAPIView
|
||||
|
||||
|
||||
__all__ = ('SoundFilter', 'SoundViewSet', 'TrackFilter', 'TrackROViewSet',
|
||||
'UserSettingsViewSet')
|
||||
|
||||
|
||||
class SoundFilter(filters.FilterSet):
|
||||
station = filters.NumberFilter(field_name='program__station__id')
|
||||
program = filters.NumberFilter(field_name='program_id')
|
||||
@ -24,3 +29,63 @@ class SoundViewSet(BaseAPIView, viewsets.ModelViewSet):
|
||||
filter_backends = (filters.DjangoFilterBackend,)
|
||||
filterset_class = SoundFilter
|
||||
|
||||
|
||||
# --- admin
|
||||
class TrackFilter(filters.FilterSet):
|
||||
artist = filters.CharFilter(field_name='artist', lookup_expr='icontains')
|
||||
album = filters.CharFilter(field_name='album', lookup_expr='icontains')
|
||||
title = filters.CharFilter(field_name='title', lookup_expr='icontains')
|
||||
|
||||
|
||||
class TrackROViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
""" Track viewset used for auto completion """
|
||||
serializer_class = admin.TrackSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
filter_backends = (filters.DjangoFilterBackend,)
|
||||
filterset_class = TrackFilter
|
||||
queryset = Track.objects.all()
|
||||
|
||||
@action(name='autocomplete', detail=False)
|
||||
def autocomplete(self, request):
|
||||
field = request.GET.get('field', None)
|
||||
if field:
|
||||
queryset = self.filter_queryset(self.get_queryset())
|
||||
values = queryset.values_list(field, flat=True).distinct()
|
||||
return Response(values)
|
||||
return self.list(request)
|
||||
|
||||
|
||||
class UserSettingsViewSet(viewsets.ViewSet):
|
||||
"""
|
||||
User's settings specific to aircox. Allow only to create and edit
|
||||
user's own settings.
|
||||
"""
|
||||
serializer_class = admin.UserSettingsSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get_serializer(self, instance=None, **kwargs):
|
||||
return self.serializer_class(
|
||||
instance=instance, context={'user': self.request.user},
|
||||
**kwargs)
|
||||
|
||||
@action(detail=False, methods=['GET'])
|
||||
def retrieve(self, request):
|
||||
user = self.request.user
|
||||
settings = getattr(user, 'aircox_settings', None)
|
||||
data = settings and self.get_serializer(settings) or None
|
||||
return Response(data)
|
||||
|
||||
@action(detail=False, methods=['POST', 'PUT'])
|
||||
def update(self, request):
|
||||
user = self.request.user
|
||||
settings = getattr(user, 'aircox_settings', None)
|
||||
data = dict(request.data)
|
||||
data['user_id'] = self.request.user
|
||||
serializer = self.get_serializer(instance=settings, data=request.data)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return Response({'status': 'ok'})
|
||||
else:
|
||||
return Response({'errors': serializer.errors},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
Reference in New Issue
Block a user