Skip to content
Snippets Groups Projects
Commit e953468e authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Merge branch 'black' into 'develop'

Blacked the code

See merge request funkwhale/funkwhale!241
parents 76c94f41 62ca3bd7
No related branches found
No related tags found
No related merge requests found
Showing
with 438 additions and 484 deletions
......@@ -12,70 +12,70 @@ from dynamic_preferences.api.viewsets import GlobalPreferencesViewSet
from dynamic_preferences.users.viewsets import UserPreferencesViewSet
router = routers.SimpleRouter()
router.register(r'settings', GlobalPreferencesViewSet, base_name='settings')
router.register(r'activity', activity_views.ActivityViewSet, 'activity')
router.register(r'tags', views.TagViewSet, 'tags')
router.register(r'tracks', views.TrackViewSet, 'tracks')
router.register(r'trackfiles', views.TrackFileViewSet, 'trackfiles')
router.register(r'artists', views.ArtistViewSet, 'artists')
router.register(r'albums', views.AlbumViewSet, 'albums')
router.register(r'import-batches', views.ImportBatchViewSet, 'import-batches')
router.register(r'import-jobs', views.ImportJobViewSet, 'import-jobs')
router.register(r'submit', views.SubmitViewSet, 'submit')
router.register(r'playlists', playlists_views.PlaylistViewSet, 'playlists')
router.register(r"settings", GlobalPreferencesViewSet, base_name="settings")
router.register(r"activity", activity_views.ActivityViewSet, "activity")
router.register(r"tags", views.TagViewSet, "tags")
router.register(r"tracks", views.TrackViewSet, "tracks")
router.register(r"trackfiles", views.TrackFileViewSet, "trackfiles")
router.register(r"artists", views.ArtistViewSet, "artists")
router.register(r"albums", views.AlbumViewSet, "albums")
router.register(r"import-batches", views.ImportBatchViewSet, "import-batches")
router.register(r"import-jobs", views.ImportJobViewSet, "import-jobs")
router.register(r"submit", views.SubmitViewSet, "submit")
router.register(r"playlists", playlists_views.PlaylistViewSet, "playlists")
router.register(
r'playlist-tracks',
playlists_views.PlaylistTrackViewSet,
'playlist-tracks')
r"playlist-tracks", playlists_views.PlaylistTrackViewSet, "playlist-tracks"
)
v1_patterns = router.urls
subsonic_router = routers.SimpleRouter(trailing_slash=False)
subsonic_router.register(r'subsonic/rest', SubsonicViewSet, base_name='subsonic')
subsonic_router.register(r"subsonic/rest", SubsonicViewSet, base_name="subsonic")
v1_patterns += [
url(r'^instance/',
url(
r"^instance/",
include(("funkwhale_api.instance.urls", "instance"), namespace="instance"),
),
url(
r"^manage/",
include(("funkwhale_api.manage.urls", "manage"), namespace="manage"),
),
url(
r"^federation/",
include(
('funkwhale_api.instance.urls', 'instance'),
namespace='instance')),
url(r'^manage/',
include(
('funkwhale_api.manage.urls', 'manage'),
namespace='manage')),
url(r'^federation/',
include(
('funkwhale_api.federation.api_urls', 'federation'),
namespace='federation')),
url(r'^providers/',
include(
('funkwhale_api.providers.urls', 'providers'),
namespace='providers')),
url(r'^favorites/',
include(
('funkwhale_api.favorites.urls', 'favorites'),
namespace='favorites')),
url(r'^search$',
views.Search.as_view(), name='search'),
url(r'^radios/',
include(
('funkwhale_api.radios.urls', 'radios'),
namespace='radios')),
url(r'^history/',
include(
('funkwhale_api.history.urls', 'history'),
namespace='history')),
url(r'^users/',
include(
('funkwhale_api.users.api_urls', 'users'),
namespace='users')),
url(r'^requests/',
include(
('funkwhale_api.requests.api_urls', 'requests'),
namespace='requests')),
url(r'^token/$', jwt_views.obtain_jwt_token, name='token'),
url(r'^token/refresh/$', jwt_views.refresh_jwt_token, name='token_refresh'),
("funkwhale_api.federation.api_urls", "federation"), namespace="federation"
),
),
url(
r"^providers/",
include(("funkwhale_api.providers.urls", "providers"), namespace="providers"),
),
url(
r"^favorites/",
include(("funkwhale_api.favorites.urls", "favorites"), namespace="favorites"),
),
url(r"^search$", views.Search.as_view(), name="search"),
url(
r"^radios/",
include(("funkwhale_api.radios.urls", "radios"), namespace="radios"),
),
url(
r"^history/",
include(("funkwhale_api.history.urls", "history"), namespace="history"),
),
url(
r"^users/",
include(("funkwhale_api.users.api_urls", "users"), namespace="users"),
),
url(
r"^requests/",
include(("funkwhale_api.requests.api_urls", "requests"), namespace="requests"),
),
url(r"^token/$", jwt_views.obtain_jwt_token, name="token"),
url(r"^token/refresh/$", jwt_views.refresh_jwt_token, name="token_refresh"),
]
urlpatterns = [
url(r'^v1/', include((v1_patterns, 'v1'), namespace='v1'))
] + format_suffix_patterns(subsonic_router.urls, allowed=['view'])
url(r"^v1/", include((v1_patterns, "v1"), namespace="v1"))
] + format_suffix_patterns(subsonic_router.urls, allowed=["view"])
......@@ -7,12 +7,13 @@ from funkwhale_api.common.auth import TokenAuthMiddleware
from funkwhale_api.instance import consumers
application = ProtocolTypeRouter({
# Empty for now (http->django views is added by default)
"websocket": TokenAuthMiddleware(
URLRouter([
url("^api/v1/instance/activity$",
consumers.InstanceActivityConsumer),
])
),
})
application = ProtocolTypeRouter(
{
# Empty for now (http->django views is added by default)
"websocket": TokenAuthMiddleware(
URLRouter(
[url("^api/v1/instance/activity$", consumers.InstanceActivityConsumer)]
)
)
}
)
This diff is collapsed.
# -*- coding: utf-8 -*-
'''
"""
Local settings
- Run in Debug mode
- Use console backend for emails
- Add Django Debug Toolbar
- Add django-extensions as app
'''
"""
from .common import * # noqa
# DEBUG
# ------------------------------------------------------------------------------
DEBUG = env.bool('DJANGO_DEBUG', default=True)
TEMPLATES[0]['OPTIONS']['debug'] = DEBUG
DEBUG = env.bool("DJANGO_DEBUG", default=True)
TEMPLATES[0]["OPTIONS"]["debug"] = DEBUG
# SECRET CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
# Note: This key only used for development and testing.
SECRET_KEY = env("DJANGO_SECRET_KEY", default='mc$&b=5j#6^bv7tld1gyjp2&+^-qrdy=0sw@r5sua*1zp4fmxc')
SECRET_KEY = env(
"DJANGO_SECRET_KEY", default="mc$&b=5j#6^bv7tld1gyjp2&+^-qrdy=0sw@r5sua*1zp4fmxc"
)
# Mail settings
# ------------------------------------------------------------------------------
EMAIL_HOST = 'localhost'
EMAIL_HOST = "localhost"
EMAIL_PORT = 1025
# django-debug-toolbar
# ------------------------------------------------------------------------------
MIDDLEWARE += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
MIDDLEWARE += ("debug_toolbar.middleware.DebugToolbarMiddleware",)
# INTERNAL_IPS = ('127.0.0.1', '10.0.2.2',)
DEBUG_TOOLBAR_CONFIG = {
'DISABLE_PANELS': [
'debug_toolbar.panels.redirects.RedirectsPanel',
],
'SHOW_TEMPLATE_CONTEXT': True,
'SHOW_TOOLBAR_CALLBACK': lambda request: True,
"DISABLE_PANELS": ["debug_toolbar.panels.redirects.RedirectsPanel"],
"SHOW_TEMPLATE_CONTEXT": True,
"SHOW_TOOLBAR_CALLBACK": lambda request: True,
}
# django-extensions
# ------------------------------------------------------------------------------
# INSTALLED_APPS += ('django_extensions', )
INSTALLED_APPS += ('debug_toolbar', )
INSTALLED_APPS += ("debug_toolbar",)
# TESTING
# ------------------------------------------------------------------------------
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
TEST_RUNNER = "django.test.runner.DiscoverRunner"
########## CELERY
# In development, all tasks will be executed locally by blocking until the task returns
......@@ -57,23 +57,15 @@ CELERY_TASK_ALWAYS_EAGER = False
# Your local stuff: Below this line define 3rd party library settings
LOGGING = {
'version': 1,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.request': {
'handlers':['console'],
'propagate': True,
'level':'DEBUG',
},
'': {
'level': 'DEBUG',
'handlers': ['console'],
"version": 1,
"handlers": {"console": {"level": "DEBUG", "class": "logging.StreamHandler"}},
"loggers": {
"django.request": {
"handlers": ["console"],
"propagate": True,
"level": "DEBUG",
},
"": {"level": "DEBUG", "handlers": ["console"]},
},
}
CSRF_TRUSTED_ORIGINS = [o for o in ALLOWED_HOSTS]
# -*- coding: utf-8 -*-
'''
"""
Production Configurations
- Use djangosecure
......@@ -8,7 +8,7 @@ Production Configurations
- Use Redis on Heroku
'''
"""
from __future__ import absolute_import, unicode_literals
from django.utils import six
......@@ -58,19 +58,24 @@ CSRF_TRUSTED_ORIGINS = ALLOWED_HOSTS
# ------------------------------------------------------------------------------
# Uploaded Media Files
# ------------------------
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
DEFAULT_FILE_STORAGE = "django.core.files.storage.FileSystemStorage"
# Static Assets
# ------------------------
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
STATICFILES_STORAGE = "django.contrib.staticfiles.storage.StaticFilesStorage"
# TEMPLATE CONFIGURATION
# ------------------------------------------------------------------------------
# See:
# https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.cached.Loader
TEMPLATES[0]['OPTIONS']['loaders'] = [
('django.template.loaders.cached.Loader', [
'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ]),
TEMPLATES[0]["OPTIONS"]["loaders"] = [
(
"django.template.loaders.cached.Loader",
[
"django.template.loaders.filesystem.Loader",
"django.template.loaders.app_directories.Loader",
],
)
]
# CACHING
......@@ -78,7 +83,6 @@ TEMPLATES[0]['OPTIONS']['loaders'] = [
# Heroku URL does not pass the DB number, so we parse it in
# LOGGING CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#logging
......@@ -88,43 +92,39 @@ TEMPLATES[0]['OPTIONS']['loaders'] = [
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
"version": 1,
"disable_existing_loggers": False,
"filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}},
"formatters": {
"verbose": {
"format": "%(levelname)s %(asctime)s %(module)s "
"%(process)d %(thread)d %(message)s"
}
},
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s '
'%(process)d %(thread)d %(message)s'
"handlers": {
"mail_admins": {
"level": "ERROR",
"filters": ["require_debug_false"],
"class": "django.utils.log.AdminEmailHandler",
},
"console": {
"level": "DEBUG",
"class": "logging.StreamHandler",
"formatter": "verbose",
},
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
"loggers": {
"django.request": {
"handlers": ["mail_admins"],
"level": "ERROR",
"propagate": True,
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
"django.security.DisallowedHost": {
"level": "ERROR",
"handlers": ["console", "mail_admins"],
"propagate": True,
},
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True
},
'django.security.DisallowedHost': {
'level': 'ERROR',
'handlers': ['console', 'mail_admins'],
'propagate': True
}
}
}
......
......@@ -11,32 +11,30 @@ from django.views import defaults as default_views
urlpatterns = [
# Django Admin, use {% url 'admin:index' %}
url(settings.ADMIN_URL, admin.site.urls),
url(r'^api/', include(("config.api_urls", 'api'), namespace="api")),
url(r'^', include(
('funkwhale_api.federation.urls', 'federation'),
namespace="federation")),
url(r'^api/v1/auth/', include('rest_auth.urls')),
url(r'^api/v1/auth/registration/', include('funkwhale_api.users.rest_auth_urls')),
url(r'^accounts/', include('allauth.urls')),
url(r"^api/", include(("config.api_urls", "api"), namespace="api")),
url(
r"^",
include(
("funkwhale_api.federation.urls", "federation"), namespace="federation"
),
),
url(r"^api/v1/auth/", include("rest_auth.urls")),
url(r"^api/v1/auth/registration/", include("funkwhale_api.users.rest_auth_urls")),
url(r"^accounts/", include("allauth.urls")),
# Your stuff: custom urls includes go here
]
if settings.DEBUG:
# This allows the error pages to be debugged during development, just visit
# these url in browser to see how these error pages look like.
urlpatterns += [
url(r'^400/$', default_views.bad_request),
url(r'^403/$', default_views.permission_denied),
url(r'^404/$', default_views.page_not_found),
url(r'^500/$', default_views.server_error),
url(r"^400/$", default_views.bad_request),
url(r"^403/$", default_views.permission_denied),
url(r"^404/$", default_views.page_not_found),
url(r"^500/$", default_views.server_error),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
if 'debug_toolbar' in settings.INSTALLED_APPS:
if "debug_toolbar" in settings.INSTALLED_APPS:
import debug_toolbar
urlpatterns += [
url(r'^__debug__/', include(debug_toolbar.urls)),
]
urlpatterns += [url(r"^__debug__/", include(debug_toolbar.urls))]
from funkwhale_api.users.models import User
u = User.objects.create(email='demo@demo.com', username='demo', is_staff=True)
u.set_password('demo')
u.subsonic_api_token = 'demo'
u = User.objects.create(email="demo@demo.com", username="demo", is_staff=True)
u.set_password("demo")
u.subsonic_api_token = "demo"
u.save()
# -*- coding: utf-8 -*-
__version__ = '0.14.1'
__version_info__ = tuple([int(num) if num.isdigit() else num for num in __version__.replace('-', '.', 1).split('.')])
__version__ = "0.14.1"
__version_info__ = tuple(
[
int(num) if num.isdigit() else num
for num in __version__.replace("-", ".", 1).split(".")
]
)
......@@ -2,8 +2,9 @@ from django.apps import AppConfig, apps
from . import record
class ActivityConfig(AppConfig):
name = 'funkwhale_api.activity'
name = "funkwhale_api.activity"
def ready(self):
super(ActivityConfig, self).ready()
......
......@@ -2,37 +2,36 @@ import persisting_theory
class ActivityRegistry(persisting_theory.Registry):
look_into = 'activities'
look_into = "activities"
def _register_for_model(self, model, attr, value):
key = model._meta.label
d = self.setdefault(key, {'consumers': []})
d = self.setdefault(key, {"consumers": []})
d[attr] = value
def register_serializer(self, serializer_class):
model = serializer_class.Meta.model
self._register_for_model(model, 'serializer', serializer_class)
self._register_for_model(model, "serializer", serializer_class)
return serializer_class
def register_consumer(self, label):
def decorator(func):
consumers = self[label]['consumers']
consumers = self[label]["consumers"]
if func not in consumers:
consumers.append(func)
return func
return decorator
registry = ActivityRegistry()
def send(obj):
conf = registry[obj.__class__._meta.label]
consumers = conf['consumers']
consumers = conf["consumers"]
if not consumers:
return
serializer = conf['serializer'](obj)
serializer = conf["serializer"](obj)
for consumer in consumers:
consumer(data=serializer.data, obj=obj)
......@@ -4,8 +4,8 @@ from funkwhale_api.activity import record
class ModelSerializer(serializers.ModelSerializer):
id = serializers.CharField(source='get_activity_url')
local_id = serializers.IntegerField(source='id')
id = serializers.CharField(source="get_activity_url")
local_id = serializers.IntegerField(source="id")
# url = serializers.SerializerMethodField()
def get_url(self, obj):
......@@ -17,8 +17,7 @@ class AutoSerializer(serializers.Serializer):
A serializer that will automatically use registered activity serializers
to serialize an henerogeneous list of objects (favorites, listenings, etc.)
"""
def to_representation(self, instance):
serializer = record.registry[instance._meta.label]['serializer'](
instance
)
serializer = record.registry[instance._meta.label]["serializer"](instance)
return serializer.data
......@@ -6,31 +6,25 @@ from funkwhale_api.history.models import Listening
def combined_recent(limit, **kwargs):
datetime_field = kwargs.pop('datetime_field', 'creation_date')
source_querysets = {
qs.model._meta.label: qs for qs in kwargs.pop('querysets')
}
datetime_field = kwargs.pop("datetime_field", "creation_date")
source_querysets = {qs.model._meta.label: qs for qs in kwargs.pop("querysets")}
querysets = {
k: qs.annotate(
__type=models.Value(
qs.model._meta.label, output_field=models.CharField()
)
).values('pk', datetime_field, '__type')
__type=models.Value(qs.model._meta.label, output_field=models.CharField())
).values("pk", datetime_field, "__type")
for k, qs in source_querysets.items()
}
_qs_list = list(querysets.values())
union_qs = _qs_list[0].union(*_qs_list[1:])
records = []
for row in union_qs.order_by('-{}'.format(datetime_field))[:limit]:
records.append({
'type': row['__type'],
'when': row[datetime_field],
'pk': row['pk']
})
for row in union_qs.order_by("-{}".format(datetime_field))[:limit]:
records.append(
{"type": row["__type"], "when": row[datetime_field], "pk": row["pk"]}
)
# Now we bulk-load each object type in turn
to_load = {}
for record in records:
to_load.setdefault(record['type'], []).append(record['pk'])
to_load.setdefault(record["type"], []).append(record["pk"])
fetched = {}
for key, pks in to_load.items():
......@@ -39,26 +33,19 @@ def combined_recent(limit, **kwargs):
# Annotate 'records' with loaded objects
for record in records:
record['object'] = fetched[(record['type'], record['pk'])]
record["object"] = fetched[(record["type"], record["pk"])]
return records
def get_activity(user, limit=20):
query = fields.privacy_level_query(
user, lookup_field='user__privacy_level')
query = fields.privacy_level_query(user, lookup_field="user__privacy_level")
querysets = [
Listening.objects.filter(query).select_related(
'track',
'user',
'track__artist',
'track__album__artist',
"track", "user", "track__artist", "track__album__artist"
),
TrackFavorite.objects.filter(query).select_related(
'track',
'user',
'track__artist',
'track__album__artist',
"track", "user", "track__artist", "track__album__artist"
),
]
records = combined_recent(limit=limit, querysets=querysets)
return [r['object'] for r in records]
return [r["object"] for r in records]
......@@ -17,4 +17,4 @@ class ActivityViewSet(viewsets.GenericViewSet):
def list(self, request, *args, **kwargs):
activity = utils.get_activity(user=request.user)
serializer = self.serializer_class(activity, many=True)
return Response({'results': serializer.data}, status=200)
return Response({"results": serializer.data}, status=200)
......@@ -16,20 +16,19 @@ class TokenHeaderAuth(BaseJSONWebTokenAuthentication):
def get_jwt_value(self, request):
try:
qs = request.get('query_string', b'').decode('utf-8')
qs = request.get("query_string", b"").decode("utf-8")
parsed = parse_qs(qs)
token = parsed['token'][0]
token = parsed["token"][0]
except KeyError:
raise exceptions.AuthenticationFailed('No token')
raise exceptions.AuthenticationFailed("No token")
if not token:
raise exceptions.AuthenticationFailed('Empty token')
raise exceptions.AuthenticationFailed("Empty token")
return token
class TokenAuthMiddleware:
def __init__(self, inner):
# Store the ASGI application we were passed
self.inner = inner
......@@ -41,5 +40,5 @@ class TokenAuthMiddleware:
except (User.DoesNotExist, exceptions.AuthenticationFailed):
user = AnonymousUser()
scope['user'] = user
scope["user"] = user
return self.inner(scope)
......@@ -6,34 +6,34 @@ from rest_framework_jwt import authentication
from rest_framework_jwt.settings import api_settings
class JSONWebTokenAuthenticationQS(
authentication.BaseJSONWebTokenAuthentication):
class JSONWebTokenAuthenticationQS(authentication.BaseJSONWebTokenAuthentication):
www_authenticate_realm = 'api'
www_authenticate_realm = "api"
def get_jwt_value(self, request):
token = request.query_params.get('jwt')
if 'jwt' in request.query_params and not token:
msg = _('Invalid Authorization header. No credentials provided.')
token = request.query_params.get("jwt")
if "jwt" in request.query_params and not token:
msg = _("Invalid Authorization header. No credentials provided.")
raise exceptions.AuthenticationFailed(msg)
return token
def authenticate_header(self, request):
return '{0} realm="{1}"'.format(
api_settings.JWT_AUTH_HEADER_PREFIX, self.www_authenticate_realm)
api_settings.JWT_AUTH_HEADER_PREFIX, self.www_authenticate_realm
)
class BearerTokenHeaderAuth(
authentication.BaseJSONWebTokenAuthentication):
class BearerTokenHeaderAuth(authentication.BaseJSONWebTokenAuthentication):
"""
For backward compatibility purpose, we used Authorization: JWT <token>
but Authorization: Bearer <token> is probably better.
"""
www_authenticate_realm = 'api'
www_authenticate_realm = "api"
def get_jwt_value(self, request):
auth = authentication.get_authorization_header(request).split()
auth_header_prefix = 'bearer'
auth_header_prefix = "bearer"
if not auth:
if api_settings.JWT_AUTH_COOKIE:
......@@ -44,14 +44,16 @@ class BearerTokenHeaderAuth(
return None
if len(auth) == 1:
msg = _('Invalid Authorization header. No credentials provided.')
msg = _("Invalid Authorization header. No credentials provided.")
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid Authorization header. Credentials string '
'should not contain spaces.')
msg = _(
"Invalid Authorization header. Credentials string "
"should not contain spaces."
)
raise exceptions.AuthenticationFailed(msg)
return auth[1]
def authenticate_header(self, request):
return '{0} realm="{1}"'.format('Bearer', self.www_authenticate_realm)
return '{0} realm="{1}"'.format("Bearer", self.www_authenticate_realm)
......@@ -5,7 +5,7 @@ from funkwhale_api.common import channels
class JsonAuthConsumer(JsonWebsocketConsumer):
def connect(self):
try:
assert self.scope['user'].pk is not None
assert self.scope["user"].pk is not None
except (AssertionError, AttributeError, KeyError):
return self.close()
......
......@@ -3,18 +3,19 @@ from dynamic_preferences.registries import global_preferences_registry
from funkwhale_api.common import preferences
common = types.Section('common')
common = types.Section("common")
@global_preferences_registry.register
class APIAutenticationRequired(
preferences.DefaultFromSettingMixin, types.BooleanPreference):
preferences.DefaultFromSettingMixin, types.BooleanPreference
):
section = common
name = 'api_authentication_required'
verbose_name = 'API Requires authentication'
setting = 'API_AUTHENTICATION_REQUIRED'
name = "api_authentication_required"
verbose_name = "API Requires authentication"
setting = "API_AUTHENTICATION_REQUIRED"
help_text = (
'If disabled, anonymous users will be able to query the API'
'and access music data (as well as other data exposed in the API '
'without specific permissions).'
"If disabled, anonymous users will be able to query the API"
"and access music data (as well as other data exposed in the API "
"without specific permissions)."
)
......@@ -6,34 +6,31 @@ from funkwhale_api.music import utils
PRIVACY_LEVEL_CHOICES = [
('me', 'Only me'),
('followers', 'Me and my followers'),
('instance', 'Everyone on my instance, and my followers'),
('everyone', 'Everyone, including people on other instances'),
("me", "Only me"),
("followers", "Me and my followers"),
("instance", "Everyone on my instance, and my followers"),
("everyone", "Everyone, including people on other instances"),
]
def get_privacy_field():
return models.CharField(
max_length=30, choices=PRIVACY_LEVEL_CHOICES, default='instance')
max_length=30, choices=PRIVACY_LEVEL_CHOICES, default="instance"
)
def privacy_level_query(user, lookup_field='privacy_level'):
def privacy_level_query(user, lookup_field="privacy_level"):
if user.is_anonymous:
return models.Q(**{
lookup_field: 'everyone',
})
return models.Q(**{lookup_field: "everyone"})
return models.Q(**{
'{}__in'.format(lookup_field): [
'followers', 'instance', 'everyone'
]
})
return models.Q(
**{"{}__in".format(lookup_field): ["followers", "instance", "everyone"]}
)
class SearchFilter(django_filters.CharFilter):
def __init__(self, *args, **kwargs):
self.search_fields = kwargs.pop('search_fields')
self.search_fields = kwargs.pop("search_fields")
super().__init__(*args, **kwargs)
def filter(self, qs, value):
......
......@@ -4,17 +4,20 @@ from funkwhale_api.common import scripts
class Command(BaseCommand):
help = 'Run a specific script from funkwhale_api/common/scripts/'
help = "Run a specific script from funkwhale_api/common/scripts/"
def add_arguments(self, parser):
parser.add_argument('script_name', nargs='?', type=str)
parser.add_argument("script_name", nargs="?", type=str)
parser.add_argument(
'--noinput', '--no-input', action='store_false', dest='interactive',
"--noinput",
"--no-input",
action="store_false",
dest="interactive",
help="Do NOT prompt the user for input of any kind.",
)
def handle(self, *args, **options):
name = options['script_name']
name = options["script_name"]
if not name:
self.show_help()
......@@ -23,44 +26,44 @@ class Command(BaseCommand):
script = available_scripts[name]
except KeyError:
raise CommandError(
'{} is not a valid script. Run python manage.py script for a '
'list of available scripts'.format(name))
"{} is not a valid script. Run python manage.py script for a "
"list of available scripts".format(name)
)
self.stdout.write('')
if options['interactive']:
self.stdout.write("")
if options["interactive"]:
message = (
'Are you sure you want to execute the script {}?\n\n'
"Are you sure you want to execute the script {}?\n\n"
"Type 'yes' to continue, or 'no' to cancel: "
).format(name)
if input(''.join(message)) != 'yes':
if input("".join(message)) != "yes":
raise CommandError("Script cancelled.")
script['entrypoint'](self, **options)
script["entrypoint"](self, **options)
def show_help(self):
indentation = 4
self.stdout.write('')
self.stdout.write('Available scripts:')
self.stdout.write('Launch with: python manage.py <script_name>')
self.stdout.write("")
self.stdout.write("Available scripts:")
self.stdout.write("Launch with: python manage.py <script_name>")
available_scripts = self.get_scripts()
for name, script in sorted(available_scripts.items()):
self.stdout.write('')
self.stdout.write("")
self.stdout.write(self.style.SUCCESS(name))
self.stdout.write('')
for line in script['help'].splitlines():
self.stdout.write(' {}'.format(line))
self.stdout.write('')
self.stdout.write("")
for line in script["help"].splitlines():
self.stdout.write(" {}".format(line))
self.stdout.write("")
def get_scripts(self):
available_scripts = [
k for k in sorted(scripts.__dict__.keys())
if not k.startswith('__')
k for k in sorted(scripts.__dict__.keys()) if not k.startswith("__")
]
data = {}
for name in available_scripts:
module = getattr(scripts, name)
data[name] = {
'name': name,
'help': module.__doc__.strip(),
'entrypoint': module.main
"name": name,
"help": module.__doc__.strip(),
"entrypoint": module.main,
}
return data
......@@ -7,6 +7,4 @@ class Migration(migrations.Migration):
dependencies = []
operations = [
UnaccentExtension()
]
operations = [UnaccentExtension()]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment