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
No related branches found
No related tags found
No related merge requests found
Showing
with 1286 additions and 476 deletions
...@@ -3,13 +3,39 @@ variables: ...@@ -3,13 +3,39 @@ variables:
IMAGE: $IMAGE_NAME:$CI_COMMIT_REF_NAME IMAGE: $IMAGE_NAME:$CI_COMMIT_REF_NAME
IMAGE_LATEST: $IMAGE_NAME:latest IMAGE_LATEST: $IMAGE_NAME:latest
PIP_CACHE_DIR: "$CI_PROJECT_DIR/pip-cache" PIP_CACHE_DIR: "$CI_PROJECT_DIR/pip-cache"
PYTHONDONTWRITEBYTECODE: "true"
stages: stages:
- lint
- test - test
- build - build
- deploy - 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: test_api:
services: services:
- postgres:9.4 - postgres:9.4
...@@ -108,7 +134,7 @@ pages: ...@@ -108,7 +134,7 @@ pages:
tags: tags:
- docker - docker
docker_develop: docker_release:
stage: deploy stage: deploy
before_script: before_script:
- docker login -u $DOCKER_LOGIN -p $DOCKER_PASSWORD - docker login -u $DOCKER_LOGIN -p $DOCKER_PASSWORD
...@@ -119,8 +145,9 @@ docker_develop: ...@@ -119,8 +145,9 @@ docker_develop:
- docker push $IMAGE - docker push $IMAGE
only: only:
- develop@funkwhale/funkwhale - develop@funkwhale/funkwhale
- tags@funkwhale/funkwhale
tags: tags:
- dind - docker-build
build_api: build_api:
# Simply publish a zip containing api/ directory # Simply publish a zip containing api/ directory
...@@ -135,19 +162,3 @@ build_api: ...@@ -135,19 +162,3 @@ build_api:
- tags@funkwhale/funkwhale - tags@funkwhale/funkwhale
- master@funkwhale/funkwhale - master@funkwhale/funkwhale
- develop@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. ...@@ -10,6 +10,133 @@ This changelog is viewable on the web at https://docs.funkwhale.audio/changelog.
.. towncrier .. 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) 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 ...@@ -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 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 Creating your env file
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
...@@ -84,6 +74,24 @@ Create it like this:: ...@@ -84,6 +74,24 @@ Create it like this::
touch .env 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 Database management
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
...@@ -124,7 +132,7 @@ Launch all services ...@@ -124,7 +132,7 @@ Launch all services
Then you can run everything with:: 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. 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``. 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 ...@@ -194,13 +202,6 @@ Run a reverse proxy for your instances
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Create docker network
^^^^^^^^^^^^^^^^^^^^
Create the federation network::
docker network create federation
Launch everything Launch everything
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ Funkwhale ...@@ -7,7 +7,7 @@ Funkwhale
A self-hosted tribute to Grooveshark.com. A self-hosted tribute to Grooveshark.com.
LICENSE: BSD LICENSE: AGPL3
Getting help Getting help
------------ ------------
......
from django.conf.urls import include, url
from dynamic_preferences.api.viewsets import GlobalPreferencesViewSet
from rest_framework import routers from rest_framework import routers
from rest_framework.urlpatterns import format_suffix_patterns 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.activity import views as activity_views
from funkwhale_api.instance import views as instance_views
from funkwhale_api.music import views from funkwhale_api.music import views
from funkwhale_api.playlists import views as playlists_views from funkwhale_api.playlists import views as playlists_views
from funkwhale_api.subsonic.views import SubsonicViewSet 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 = routers.SimpleRouter()
router.register(r'settings', GlobalPreferencesViewSet, base_name='settings') router.register(r"settings", GlobalPreferencesViewSet, base_name="settings")
router.register(r'activity', activity_views.ActivityViewSet, 'activity') router.register(r"activity", activity_views.ActivityViewSet, "activity")
router.register(r'tags', views.TagViewSet, 'tags') router.register(r"tags", views.TagViewSet, "tags")
router.register(r'tracks', views.TrackViewSet, 'tracks') router.register(r"tracks", views.TrackViewSet, "tracks")
router.register(r'trackfiles', views.TrackFileViewSet, 'trackfiles') router.register(r"trackfiles", views.TrackFileViewSet, "trackfiles")
router.register(r'artists', views.ArtistViewSet, 'artists') router.register(r"artists", views.ArtistViewSet, "artists")
router.register(r'albums', views.AlbumViewSet, 'albums') router.register(r"albums", views.AlbumViewSet, "albums")
router.register(r'import-batches', views.ImportBatchViewSet, 'import-batches') router.register(r"import-batches", views.ImportBatchViewSet, "import-batches")
router.register(r'import-jobs', views.ImportJobViewSet, 'import-jobs') router.register(r"import-jobs", views.ImportJobViewSet, "import-jobs")
router.register(r'submit', views.SubmitViewSet, 'submit') router.register(r"submit", views.SubmitViewSet, "submit")
router.register(r'playlists', playlists_views.PlaylistViewSet, 'playlists') router.register(r"playlists", playlists_views.PlaylistViewSet, "playlists")
router.register( router.register(
r'playlist-tracks', r"playlist-tracks", playlists_views.PlaylistTrackViewSet, "playlist-tracks"
playlists_views.PlaylistTrackViewSet, )
'playlist-tracks')
v1_patterns = router.urls v1_patterns = router.urls
subsonic_router = routers.SimpleRouter(trailing_slash=False) 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 += [ v1_patterns += [
url(r'^instance/', url(
include( r"^instance/",
('funkwhale_api.instance.urls', 'instance'), include(("funkwhale_api.instance.urls", "instance"), namespace="instance"),
namespace='instance')), ),
url(r'^manage/', url(
include( r"^manage/",
('funkwhale_api.manage.urls', 'manage'), include(("funkwhale_api.manage.urls", "manage"), namespace="manage"),
namespace='manage')), ),
url(r'^federation/', url(
include( r"^federation/",
('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( include(
('funkwhale_api.requests.api_urls', 'requests'), ("funkwhale_api.federation.api_urls", "federation"), namespace="federation"
namespace='requests')), ),
url(r'^token/$', jwt_views.obtain_jwt_token, name='token'), ),
url(r'^token/refresh/$', jwt_views.refresh_jwt_token, name='token_refresh'), 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 = [ urlpatterns = [
url(r'^v1/', include((v1_patterns, 'v1'), namespace='v1')) url(r"^v1/", include((v1_patterns, "v1"), namespace="v1"))
] + format_suffix_patterns(subsonic_router.urls, allowed=['view']) ] + format_suffix_patterns(subsonic_router.urls, allowed=["view"])
import django
import os import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production") import django
django.setup() 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 channels.routing import ProtocolTypeRouter, URLRouter
from django.conf.urls import url
from funkwhale_api.common.auth import TokenAuthMiddleware from funkwhale_api.common.auth import TokenAuthMiddleware
from funkwhale_api.instance import consumers from funkwhale_api.instance import consumers
application = ProtocolTypeRouter(
application = ProtocolTypeRouter({ {
# Empty for now (http->django views is added by default) # Empty for now (http->django views is added by default)
"websocket": TokenAuthMiddleware( "websocket": TokenAuthMiddleware(
URLRouter([ URLRouter(
url("^api/v1/instance/activity$", [url("^api/v1/instance/activity$", consumers.InstanceActivityConsumer)]
consumers.InstanceActivityConsumer), )
]) )
), }
}) )
This diff is collapsed.
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
''' """
Local settings Local settings
- Run in Debug mode - Run in Debug mode
- Use console backend for emails - Use console backend for emails
- Add Django Debug Toolbar - Add Django Debug Toolbar
- Add django-extensions as app - Add django-extensions as app
''' """
from .common import * # noqa from .common import * # noqa
# DEBUG # DEBUG
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
DEBUG = env.bool('DJANGO_DEBUG', default=True) DEBUG = env.bool("DJANGO_DEBUG", default=True)
TEMPLATES[0]['OPTIONS']['debug'] = DEBUG TEMPLATES[0]["OPTIONS"]["debug"] = DEBUG
# SECRET CONFIGURATION # SECRET CONFIGURATION
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key # See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
# Note: This key only used for development and testing. # 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 # Mail settings
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
EMAIL_HOST = 'localhost' EMAIL_HOST = "localhost"
EMAIL_PORT = 1025 EMAIL_PORT = 1025
# django-debug-toolbar # django-debug-toolbar
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
MIDDLEWARE += ('debug_toolbar.middleware.DebugToolbarMiddleware',) MIDDLEWARE += ("debug_toolbar.middleware.DebugToolbarMiddleware",)
# INTERNAL_IPS = ('127.0.0.1', '10.0.2.2',) # INTERNAL_IPS = ('127.0.0.1', '10.0.2.2',)
DEBUG_TOOLBAR_CONFIG = { DEBUG_TOOLBAR_CONFIG = {
'DISABLE_PANELS': [ "DISABLE_PANELS": ["debug_toolbar.panels.redirects.RedirectsPanel"],
'debug_toolbar.panels.redirects.RedirectsPanel', "SHOW_TEMPLATE_CONTEXT": True,
], "SHOW_TOOLBAR_CALLBACK": lambda request: True,
'SHOW_TEMPLATE_CONTEXT': True,
'SHOW_TOOLBAR_CALLBACK': lambda request: True,
} }
# django-extensions # django-extensions
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# INSTALLED_APPS += ('django_extensions', ) # INSTALLED_APPS += ('django_extensions', )
INSTALLED_APPS += ('debug_toolbar', ) INSTALLED_APPS += ("debug_toolbar",)
# TESTING # 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 # In development, all tasks will be executed locally by blocking until the task returns
CELERY_TASK_ALWAYS_EAGER = False CELERY_TASK_ALWAYS_EAGER = False
########## END CELERY # END CELERY
# Your local stuff: Below this line define 3rd party library settings # Your local stuff: Below this line define 3rd party library settings
LOGGING = { LOGGING = {
'version': 1, "version": 1,
'handlers': { "handlers": {"console": {"level": "DEBUG", "class": "logging.StreamHandler"}},
'console':{ "loggers": {
'level':'DEBUG', "django.request": {
'class':'logging.StreamHandler', "handlers": ["console"],
}, "propagate": True,
}, "level": "DEBUG",
'loggers': {
'django.request': {
'handlers':['console'],
'propagate': True,
'level':'DEBUG',
},
'': {
'level': 'DEBUG',
'handlers': ['console'],
}, },
"": {"level": "DEBUG", "handlers": ["console"]},
}, },
} }
CSRF_TRUSTED_ORIGINS = [o for o in ALLOWED_HOSTS] CSRF_TRUSTED_ORIGINS = [o for o in ALLOWED_HOSTS]
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
''' """
Production Configurations Production Configurations
- Use djangosecure - Use djangosecure
...@@ -8,12 +8,9 @@ Production Configurations ...@@ -8,12 +8,9 @@ Production Configurations
- Use Redis on Heroku - Use Redis on Heroku
''' """
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
from django.utils import six
from .common import * # noqa from .common import * # noqa
# SECRET CONFIGURATION # SECRET CONFIGURATION
...@@ -58,19 +55,24 @@ CSRF_TRUSTED_ORIGINS = ALLOWED_HOSTS ...@@ -58,19 +55,24 @@ CSRF_TRUSTED_ORIGINS = ALLOWED_HOSTS
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Uploaded Media Files # Uploaded Media Files
# ------------------------ # ------------------------
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage' DEFAULT_FILE_STORAGE = "django.core.files.storage.FileSystemStorage"
# Static Assets # Static Assets
# ------------------------ # ------------------------
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' STATICFILES_STORAGE = "django.contrib.staticfiles.storage.StaticFilesStorage"
# TEMPLATE CONFIGURATION # TEMPLATE CONFIGURATION
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# See: # See:
# https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.cached.Loader # https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.cached.Loader
TEMPLATES[0]['OPTIONS']['loaders'] = [ TEMPLATES[0]["OPTIONS"]["loaders"] = [
('django.template.loaders.cached.Loader', [ (
'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ]), "django.template.loaders.cached.Loader",
[
"django.template.loaders.filesystem.Loader",
"django.template.loaders.app_directories.Loader",
],
)
] ]
# CACHING # CACHING
...@@ -78,7 +80,6 @@ TEMPLATES[0]['OPTIONS']['loaders'] = [ ...@@ -78,7 +80,6 @@ TEMPLATES[0]['OPTIONS']['loaders'] = [
# Heroku URL does not pass the DB number, so we parse it in # Heroku URL does not pass the DB number, so we parse it in
# LOGGING CONFIGURATION # LOGGING CONFIGURATION
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#logging # See: https://docs.djangoproject.com/en/dev/ref/settings/#logging
...@@ -88,43 +89,39 @@ TEMPLATES[0]['OPTIONS']['loaders'] = [ ...@@ -88,43 +89,39 @@ TEMPLATES[0]['OPTIONS']['loaders'] = [
# See http://docs.djangoproject.com/en/dev/topics/logging for # See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration. # more details on how to customize your logging configuration.
LOGGING = { LOGGING = {
'version': 1, "version": 1,
'disable_existing_loggers': False, "disable_existing_loggers": False,
'filters': { "filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}},
'require_debug_false': { "formatters": {
'()': 'django.utils.log.RequireDebugFalse' "verbose": {
"format": "%(levelname)s %(asctime)s %(module)s "
"%(process)d %(thread)d %(message)s"
} }
}, },
'formatters': { "handlers": {
'verbose': { "mail_admins": {
'format': '%(levelname)s %(asctime)s %(module)s ' "level": "ERROR",
'%(process)d %(thread)d %(message)s' "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'
}, },
'console': { "loggers": {
'level': 'DEBUG', "django.request": {
'class': 'logging.StreamHandler', "handlers": ["mail_admins"],
'formatter': 'verbose', "level": "ERROR",
"propagate": True,
}, },
"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 ...@@ -5,38 +5,35 @@ from django.conf import settings
from django.conf.urls import include, url from django.conf.urls import include, url
from django.conf.urls.static import static from django.conf.urls.static import static
from django.contrib import admin from django.contrib import admin
from django.views.generic import TemplateView
from django.views import defaults as default_views from django.views import defaults as default_views
urlpatterns = [ urlpatterns = [
# Django Admin, use {% url 'admin:index' %} # Django Admin, use {% url 'admin:index' %}
url(settings.ADMIN_URL, admin.site.urls), url(settings.ADMIN_URL, admin.site.urls),
url(r"^api/", include(("config.api_urls", "api"), namespace="api")),
url(r'^api/', include(("config.api_urls", 'api'), namespace="api")), url(
url(r'^', include( r"^",
('funkwhale_api.federation.urls', 'federation'), include(
namespace="federation")), ("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/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 # Your stuff: custom urls includes go here
] ]
if settings.DEBUG: if settings.DEBUG:
# This allows the error pages to be debugged during development, just visit # This allows the error pages to be debugged during development, just visit
# these url in browser to see how these error pages look like. # these url in browser to see how these error pages look like.
urlpatterns += [ urlpatterns += [
url(r'^400/$', default_views.bad_request), url(r"^400/$", default_views.bad_request),
url(r'^403/$', default_views.permission_denied), url(r"^403/$", default_views.permission_denied),
url(r'^404/$', default_views.page_not_found), url(r"^404/$", default_views.page_not_found),
url(r'^500/$', default_views.server_error), url(r"^500/$", default_views.server_error),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + 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 import debug_toolbar
urlpatterns += [
url(r'^__debug__/', include(debug_toolbar.urls)), urlpatterns += [url(r"^__debug__/", include(debug_toolbar.urls))]
]
...@@ -15,11 +15,9 @@ framework. ...@@ -15,11 +15,9 @@ framework.
""" """
import os import os
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise from whitenoise.django import DjangoWhiteNoise
# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks # 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 # 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 # mod_wsgi daemon mode with each site in its own daemon process, or use
......
from funkwhale_api.users.models import User from funkwhale_api.users.models import User
u = User.objects.create(email='demo@demo.com', username='demo', is_staff=True) u = User.objects.create(email="demo@demo.com", username="demo", is_staff=True)
u.set_password('demo') u.set_password("demo")
u.subsonic_api_token = 'demo' u.subsonic_api_token = "demo"
u.save() u.save()
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
__version__ = '0.14.1' __version__ = "0.14.2"
__version_info__ = tuple([int(num) if num.isdigit() else num for num in __version__.replace('-', '.', 1).split('.')]) __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 ...@@ -2,8 +2,9 @@ from django.apps import AppConfig, apps
from . import record from . import record
class ActivityConfig(AppConfig): class ActivityConfig(AppConfig):
name = 'funkwhale_api.activity' name = "funkwhale_api.activity"
def ready(self): def ready(self):
super(ActivityConfig, self).ready() super(ActivityConfig, self).ready()
......
...@@ -2,37 +2,36 @@ import persisting_theory ...@@ -2,37 +2,36 @@ import persisting_theory
class ActivityRegistry(persisting_theory.Registry): class ActivityRegistry(persisting_theory.Registry):
look_into = 'activities' look_into = "activities"
def _register_for_model(self, model, attr, value): def _register_for_model(self, model, attr, value):
key = model._meta.label key = model._meta.label
d = self.setdefault(key, {'consumers': []}) d = self.setdefault(key, {"consumers": []})
d[attr] = value d[attr] = value
def register_serializer(self, serializer_class): def register_serializer(self, serializer_class):
model = serializer_class.Meta.model model = serializer_class.Meta.model
self._register_for_model(model, 'serializer', serializer_class) self._register_for_model(model, "serializer", serializer_class)
return serializer_class return serializer_class
def register_consumer(self, label): def register_consumer(self, label):
def decorator(func): def decorator(func):
consumers = self[label]['consumers'] consumers = self[label]["consumers"]
if func not in consumers: if func not in consumers:
consumers.append(func) consumers.append(func)
return func return func
return decorator return decorator
registry = ActivityRegistry() registry = ActivityRegistry()
def send(obj): def send(obj):
conf = registry[obj.__class__._meta.label] conf = registry[obj.__class__._meta.label]
consumers = conf['consumers'] consumers = conf["consumers"]
if not consumers: if not consumers:
return return
serializer = conf['serializer'](obj) serializer = conf["serializer"](obj)
for consumer in consumers: for consumer in consumers:
consumer(data=serializer.data, obj=obj) consumer(data=serializer.data, obj=obj)
...@@ -4,8 +4,8 @@ from funkwhale_api.activity import record ...@@ -4,8 +4,8 @@ from funkwhale_api.activity import record
class ModelSerializer(serializers.ModelSerializer): class ModelSerializer(serializers.ModelSerializer):
id = serializers.CharField(source='get_activity_url') id = serializers.CharField(source="get_activity_url")
local_id = serializers.IntegerField(source='id') local_id = serializers.IntegerField(source="id")
# url = serializers.SerializerMethodField() # url = serializers.SerializerMethodField()
def get_url(self, obj): def get_url(self, obj):
...@@ -17,8 +17,7 @@ class AutoSerializer(serializers.Serializer): ...@@ -17,8 +17,7 @@ class AutoSerializer(serializers.Serializer):
A serializer that will automatically use registered activity serializers A serializer that will automatically use registered activity serializers
to serialize an henerogeneous list of objects (favorites, listenings, etc.) to serialize an henerogeneous list of objects (favorites, listenings, etc.)
""" """
def to_representation(self, instance): def to_representation(self, instance):
serializer = record.registry[instance._meta.label]['serializer']( serializer = record.registry[instance._meta.label]["serializer"](instance)
instance
)
return serializer.data return serializer.data
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment