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

Merge branch 'release/0.14.2'

parents 30eaa78e cb1957a9
Branches
Tags 0.14.2
No related merge requests found
Showing
with 1286 additions and 476 deletions
......@@ -3,13 +3,39 @@ variables:
IMAGE: $IMAGE_NAME:$CI_COMMIT_REF_NAME
IMAGE_LATEST: $IMAGE_NAME:latest
PIP_CACHE_DIR: "$CI_PROJECT_DIR/pip-cache"
PYTHONDONTWRITEBYTECODE: "true"
stages:
- lint
- test
- build
- deploy
black:
image: python:3.6
stage: lint
variables:
GIT_STRATEGY: fetch
before_script:
- pip install black
script:
- black --check --diff api/
flake8:
image: python:3.6
stage: lint
variables:
GIT_STRATEGY: fetch
before_script:
- pip install flake8
script:
- flake8 -v api
cache:
key: "$CI_PROJECT_ID__flake8_pip_cache"
paths:
- "$PIP_CACHE_DIR"
test_api:
services:
- postgres:9.4
......@@ -108,7 +134,7 @@ pages:
tags:
- docker
docker_develop:
docker_release:
stage: deploy
before_script:
- docker login -u $DOCKER_LOGIN -p $DOCKER_PASSWORD
......@@ -119,8 +145,9 @@ docker_develop:
- docker push $IMAGE
only:
- develop@funkwhale/funkwhale
- tags@funkwhale/funkwhale
tags:
- dind
- docker-build
build_api:
# Simply publish a zip containing api/ directory
......@@ -135,19 +162,3 @@ build_api:
- tags@funkwhale/funkwhale
- master@funkwhale/funkwhale
- develop@funkwhale/funkwhale
docker_release:
stage: deploy
before_script:
- docker login -u $DOCKER_LOGIN -p $DOCKER_PASSWORD
- cp -r front/dist api/frontend
- cd api
script:
- docker build -t $IMAGE -t $IMAGE_LATEST .
- docker push $IMAGE
- docker push $IMAGE_LATEST
only:
- tags@funkwhale/funkwhale
tags:
- dind
<!--
Hi there! You are reporting a bug on this project, and we want to thank you!
To ensure your bug report is as useful as possible, please try to stick
to the following structure. You can leave the parts text between `<!- ->`
markers untouched, they won't be displayed in your final message.
Please do not edit the following line, it's used for automatic classification
-->
/label ~"Type: Bug" ~"Status: Need triage"
## Steps to reproduce
<!--
Describe the steps to reproduce the issue, like:
1. Visit the page at /artists/
2. Type that
3. Submit
-->
## What happens?
<!--
Describe what happens once the previous steps are completed.
-->
## What is expected?
<!--
Describe the expected behaviour.
-->
## Context
<!--
If relevant, share additional context here like:
- Browser type and version (for front-end bugs)
- Instance configuration (Docker/non-docker, nginx/apache as proxy, etc.)
- Error messages, screenshots and logs
-->
<!--
Hi there! You are about to share feature request or an idea, and we want to thank you!
To ensure we can deal with your idea or request, please try to stick
to the following structure. You can leave the parts text between `<!- ->`
markers untouched, they won't be displayed in your final message.
Please do not edit the following line, it's used for automatic classification
-->
/label ~"Type: New feature" ~"Status: Need triage"
## What is the problem you are facing?
<!--
Describe the problem you'd like to solve, and why we need to add or
improve something in the current system to solve that problem.
Be as specific as possible.
-->
## What are the possible drawbacks or issues with the requested changes?
<!--
Altering the system behaviour is not always a free action, and it can impact
user experience, performance, introduce bugs or complexity, etc..
If you think about anything we should keep in mind while
examining your request, please describe it in this section.
-->
## Context
<!--
If relevant, share additional context here like:
- Links to existing implementations or examples of the requested feature
- Screenshots
-->
......@@ -10,6 +10,133 @@ This changelog is viewable on the web at https://docs.funkwhale.audio/changelog.
.. towncrier
0.14.2 (2018-06-16)
-------------------
.. warning::
This release contains a fix for a permission issue. You should upgrade
as soon as possible. Read the changelog below for more details.
Upgrade instructions are available at
https://docs.funkwhale.audio/upgrading.html
Enhancements:
- Added feedback on shuffle button (#262)
- Added multiple warnings in the documentation that you should never run
makemigrations yourself (#291)
- Album cover served in http (#264)
- Apache2 reverse proxy now supports websockets (tested with Apache 2.4.25)
(!252)
- Display file size in human format during file upload (#289)
- Switch from BSD-3 licence to AGPL-3 licence (#280)
Bugfixes:
- Ensure radios can only be edited and deleted by their owners (#311)
- Fixed admin menu not showing after login (#245)
- Fixed broken pagination in Subsonic API (#295)
- Fixed duplicated websocket connexion on timeline (#287)
Documentation:
- Improved documentation about in-place imports setup (#298)
Other:
- Added Black and flake8 checks in CI to ensure consistent code styling and
formatting (#297)
- Added bug and feature issue templates (#299)
Permission issues on radios
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Because of an error in the way we checked user permissions on radios,
public radios could be deleted by any logged-in user, even if they were not
the owner of the radio.
We recommend instances owners to upgrade as fast as possible to avoid any abuse
and data loss.
Funkwhale is now licenced under AGPL-3
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Following the recent switch made by PixelFed
(https://github.com/dansup/pixelfed/issues/143), we decided along with
the community to relicence Funkwhale under the AGPL-3 licence. We did this
switch for various reasons:
- This is better aligned with other fediverse software
- It prohibits anyone to distribute closed-source and proprietary forks of Funkwhale
As end users and instance owners, this does not change anything. You can
continue to use Funkwhale exactly as you did before :)
Apache support for websocket
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Up until now, our Apache2 configuration was not working with websockets. This is now
solved by adding this at the beginning of your Apache2 configuration file::
Define funkwhale-api-ws ws://localhost:5000
And this, before the "/api" block::
# Activating WebSockets
ProxyPass "/api/v1/instance/activity" ${funkwhale-api-ws}/api/v1/instance/activity
Websockets may not be supported in older versions of Apache2. Be sure to upgrade to the latest version available.
Serving album covers in https (Apache2 proxy)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Two issues are addressed here. The first one was about Django replying with
mixed content (http) when queried for covers. Setting up the `X-Forwarded-Proto`
allows Django to know that the client is using https, and that the reply must
be https as well.
Second issue was a problem of permission causing Apache a denied access to
album cover folder. It is solved by adding another block for this path in
the Apache configuration file for funkwhale.
Here is how to modify your `funkwhale.conf` apache2 configuration::
<VirtualHost *:443>
...
#Add this new line
RequestHeader set X-Forwarded-Proto "https"
...
# Add this new block below the other <Directory/> blocks
# replace /srv/funkwhale/data/media with the path to your media directory
# if you're not using the standard layout.
<Directory /srv/funkwhale/data/media/albums>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
...
</VirtualHost>
About the makemigrations warning
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You may sometimes get the following warning while applying migrations::
"Your models have changes that are not yet reflected in a migration, and so won't be applied."
This is a warning, not an error, and it can be safely ignored.
Never run the ``makemigrations`` command yourself.
0.14.1 (2018-06-06)
-------------------
......
......@@ -61,16 +61,6 @@ If you do not want to add the ``-f dev.yml`` snippet everytime, you can run this
export COMPOSE_FILE=dev.yml
Building the containers
^^^^^^^^^^^^^^^^^^^^^^^
On your initial clone, or if there have been some changes in the
app dependencies, you will have to rebuild your containers. This is done
via the following command::
docker-compose -f dev.yml build
Creating your env file
^^^^^^^^^^^^^^^^^^^^^^
......@@ -84,6 +74,24 @@ Create it like this::
touch .env
Create docker network
^^^^^^^^^^^^^^^^^^^^
Create the federation network::
docker network create federation
Building the containers
^^^^^^^^^^^^^^^^^^^^^^^
On your initial clone, or if there have been some changes in the
app dependencies, you will have to rebuild your containers. This is done
via the following command::
docker-compose -f dev.yml build
Database management
^^^^^^^^^^^^^^^^^^^
......@@ -124,7 +132,7 @@ Launch all services
Then you can run everything with::
docker-compose -f dev.yml up
docker-compose -f dev.yml up front api nginx celeryworker
This will launch all services, and output the logs in your current terminal window.
If you prefer to launch them in the background instead, use the ``-d`` flag, and access the logs when you need it via ``docker-compose -f dev.yml logs --tail=50 --follow``.
......@@ -194,13 +202,6 @@ Run a reverse proxy for your instances
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Create docker network
^^^^^^^^^^^^^^^^^^^^
Create the federation network::
docker network create federation
Launch everything
^^^^^^^^^^^^^^^^^
......
This diff is collapsed.
......@@ -7,7 +7,7 @@ Funkwhale
A self-hosted tribute to Grooveshark.com.
LICENSE: BSD
LICENSE: AGPL3
Getting help
------------
......
from django.conf.urls import include, url
from dynamic_preferences.api.viewsets import GlobalPreferencesViewSet
from rest_framework import routers
from rest_framework.urlpatterns import format_suffix_patterns
from django.conf.urls import include, url
from rest_framework_jwt import views as jwt_views
from funkwhale_api.activity import views as activity_views
from funkwhale_api.instance import views as instance_views
from funkwhale_api.music import views
from funkwhale_api.playlists import views as playlists_views
from funkwhale_api.subsonic.views import SubsonicViewSet
from rest_framework_jwt import views as jwt_views
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/',
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/',
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.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"])
import django
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
import django
django.setup()
from .routing import application
from .routing import application # noqa
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
from django.conf.urls import url
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.conf.urls import url
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
# CELERY
# In development, all tasks will be executed locally by blocking until the task returns
CELERY_TASK_ALWAYS_EAGER = False
########## END CELERY
# END CELERY
# 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,12 +8,9 @@ Production Configurations
- Use Redis on Heroku
'''
"""
from __future__ import absolute_import, unicode_literals
from django.utils import six
from .common import * # noqa
# SECRET CONFIGURATION
......@@ -58,19 +55,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 +80,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 +89,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
}
}
}
......
......@@ -5,38 +5,35 @@ from django.conf import settings
from django.conf.urls import include, url
from django.conf.urls.static import static
from django.contrib import admin
from django.views.generic import TemplateView
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))]
......@@ -15,11 +15,9 @@ framework.
"""
import os
from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise
# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
# if running multiple sites in the same mod_wsgi process. To fix this, use
# mod_wsgi daemon mode with each site in its own daemon process, or use
......
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.2"
__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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment