See #1100: clean compat and XXX in the code
This commit is contained in:
		
							parent
							
								
									b7f1c02c6f
								
							
						
					
					
						commit
						e271851f67
					
				|  | @ -74,11 +74,6 @@ v1_patterns += [ | |||
|         include(("funkwhale_api.history.urls", "history"), namespace="history"), | ||||
|     ), | ||||
|     url(r"^", include(("funkwhale_api.users.api_urls", "users"), namespace="users"),), | ||||
|     # XXX: 1.0: remove this | ||||
|     url( | ||||
|         r"^users/", | ||||
|         include(("funkwhale_api.users.api_urls", "users"), namespace="users-nested"), | ||||
|     ), | ||||
|     url( | ||||
|         r"^oauth/", | ||||
|         include(("funkwhale_api.users.oauth.urls", "oauth"), namespace="oauth"), | ||||
|  |  | |||
|  | @ -2,18 +2,13 @@ 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": AuthMiddlewareStack( | ||||
|             TokenAuthMiddleware( | ||||
|                 URLRouter( | ||||
|                     [url("^api/v1/activity$", consumers.InstanceActivityConsumer)] | ||||
|                 ) | ||||
|             ) | ||||
|             URLRouter([url("^api/v1/activity$", consumers.InstanceActivityConsumer)]) | ||||
|         ) | ||||
|     } | ||||
| ) | ||||
|  |  | |||
|  | @ -169,17 +169,7 @@ os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = env.bool( | |||
|     "DJANGO_ALLOW_ASYNC_UNSAFE", default="true" | ||||
| ) | ||||
| 
 | ||||
| # XXX: deprecated, see #186 | ||||
| FEDERATION_ENABLED = env.bool("FEDERATION_ENABLED", default=True) | ||||
| FEDERATION_HOSTNAME = env("FEDERATION_HOSTNAME", default=FUNKWHALE_HOSTNAME).lower() | ||||
| # XXX: deprecated, see #186 | ||||
| FEDERATION_COLLECTION_PAGE_SIZE = env.int("FEDERATION_COLLECTION_PAGE_SIZE", default=50) | ||||
| # XXX: deprecated, see #186 | ||||
| FEDERATION_MUSIC_NEEDS_APPROVAL = env.bool( | ||||
|     "FEDERATION_MUSIC_NEEDS_APPROVAL", default=True | ||||
| ) | ||||
| # XXX: deprecated, see #186 | ||||
| FEDERATION_ACTOR_FETCH_DELAY = env.int("FEDERATION_ACTOR_FETCH_DELAY", default=60 * 12) | ||||
| FEDERATION_SERVICE_ACTOR_USERNAME = env( | ||||
|     "FEDERATION_SERVICE_ACTOR_USERNAME", default="service" | ||||
| ) | ||||
|  | @ -1129,11 +1119,6 @@ Exemples: | |||
| CSRF_USE_SESSIONS = True | ||||
| SESSION_ENGINE = "django.contrib.sessions.backends.cache" | ||||
| 
 | ||||
| # Playlist settings | ||||
| # XXX: deprecated, see #186 | ||||
| PLAYLISTS_MAX_TRACKS = env.int("PLAYLISTS_MAX_TRACKS", default=250) | ||||
| 
 | ||||
| 
 | ||||
| ACCOUNT_USERNAME_BLACKLIST = [ | ||||
|     "funkwhale", | ||||
|     "library", | ||||
|  | @ -1170,8 +1155,6 @@ EXTERNAL_REQUESTS_TIMEOUT = env.int("EXTERNAL_REQUESTS_TIMEOUT", default=10) | |||
| """ | ||||
| Default timeout for external requests. | ||||
| """ | ||||
| # XXX: deprecated, see #186 | ||||
| API_AUTHENTICATION_REQUIRED = env.bool("API_AUTHENTICATION_REQUIRED", True) | ||||
| 
 | ||||
| MUSIC_DIRECTORY_PATH = env("MUSIC_DIRECTORY_PATH", default=None) | ||||
| """ | ||||
|  | @ -1285,8 +1268,6 @@ FUNKWHALE_SUPPORT_MESSAGE_DELAY = env.int("FUNKWHALE_SUPPORT_MESSAGE_DELAY", def | |||
| """ | ||||
| Delay in days after signup before we show the "support Funkwhale" message | ||||
| """ | ||||
| # XXX Stable release: remove | ||||
| USE_FULL_TEXT_SEARCH = env.bool("USE_FULL_TEXT_SEARCH", default=True) | ||||
| 
 | ||||
| MIN_DELAY_BETWEEN_DOWNLOADS_COUNT = env.int( | ||||
|     "MIN_DELAY_BETWEEN_DOWNLOADS_COUNT", default=60 * 60 * 6 | ||||
|  |  | |||
|  | @ -1,19 +1,15 @@ | |||
| from dynamic_preferences import types | ||||
| from dynamic_preferences.registries import global_preferences_registry | ||||
| 
 | ||||
| from funkwhale_api.common import preferences | ||||
| 
 | ||||
| common = types.Section("common") | ||||
| 
 | ||||
| 
 | ||||
| @global_preferences_registry.register | ||||
| class APIAutenticationRequired( | ||||
|     preferences.DefaultFromSettingMixin, types.BooleanPreference | ||||
| ): | ||||
| class APIAutenticationRequired(types.BooleanPreference): | ||||
|     section = common | ||||
|     name = "api_authentication_required" | ||||
|     verbose_name = "API Requires authentication" | ||||
|     setting = "API_AUTHENTICATION_REQUIRED" | ||||
|     default = True | ||||
|     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 " | ||||
|  |  | |||
|  | @ -1,6 +1,5 @@ | |||
| import django_filters | ||||
| from django import forms | ||||
| from django.conf import settings | ||||
| from django.core.serializers.json import DjangoJSONEncoder | ||||
| from django.db import models | ||||
| 
 | ||||
|  | @ -40,7 +39,7 @@ class SearchFilter(django_filters.CharFilter): | |||
|     def filter(self, qs, value): | ||||
|         if not value: | ||||
|             return qs | ||||
|         if settings.USE_FULL_TEXT_SEARCH and self.fts_search_fields: | ||||
|         if self.fts_search_fields: | ||||
|             query = search.get_fts_query( | ||||
|                 value, self.fts_search_fields, model=self.parent.Meta.model | ||||
|             ) | ||||
|  |  | |||
|  | @ -113,7 +113,7 @@ def get_spa_html(spa_url): | |||
| 
 | ||||
| def get_spa_file(spa_url, name): | ||||
|     if spa_url.startswith("/"): | ||||
|         # XXX: spa_url is an absolute path to index.html, on the local disk. | ||||
|         # spa_url is an absolute path to index.html, on the local disk. | ||||
|         # However, we may want to access manifest.json or other files as well, so we | ||||
|         # strip the filename | ||||
|         path = os.path.join(os.path.dirname(spa_url), name) | ||||
|  |  | |||
|  | @ -299,20 +299,6 @@ class AttachmentSerializer(serializers.Serializer): | |||
|         urls["medium_square_crop"] = o.download_url_medium_square_crop | ||||
|         return urls | ||||
| 
 | ||||
|     def to_representation(self, o): | ||||
|         repr = super().to_representation(o) | ||||
|         # XXX: BACKWARD COMPATIBILITY | ||||
|         # having the attachment urls in a nested JSON obj is better, | ||||
|         # but we can't do this without breaking clients | ||||
|         # So we extract the urls and include these in the parent payload | ||||
|         repr.update({k: v for k, v in repr["urls"].items() if k != "source"}) | ||||
|         # also, our legacy images had lots of variations (400x400, 200x200, 50x50) | ||||
|         # but we removed some of these, so we emulate these by hand (by redirecting) | ||||
|         # to actual, existing attachment variations | ||||
|         repr["square_crop"] = repr["medium_square_crop"] | ||||
|         repr["small_square_crop"] = repr["medium_square_crop"] | ||||
|         return repr | ||||
| 
 | ||||
|     def create(self, validated_data): | ||||
|         return models.Attachment.objects.create( | ||||
|             file=validated_data["file"], actor=validated_data["actor"] | ||||
|  |  | |||
|  | @ -13,8 +13,7 @@ class TrackFavoriteFilter(moderation_filters.HiddenContentFilterSet): | |||
| 
 | ||||
|     class Meta: | ||||
|         model = models.TrackFavorite | ||||
|         # XXX: 1.0 remove the user filter, we have scope=me now | ||||
|         fields = ["user"] | ||||
|         fields = [] | ||||
|         hidden_content_fields_mapping = moderation_filters.USER_FILTER_CONFIG[ | ||||
|             "TRACK_FAVORITE" | ||||
|         ] | ||||
|  |  | |||
|  | @ -1,8 +1,6 @@ | |||
| from dynamic_preferences import types | ||||
| from dynamic_preferences.registries import global_preferences_registry | ||||
| 
 | ||||
| from funkwhale_api.common import preferences | ||||
| 
 | ||||
| federation = types.Section("federation") | ||||
| 
 | ||||
| 
 | ||||
|  | @ -22,10 +20,10 @@ class MusicCacheDuration(types.IntPreference): | |||
| 
 | ||||
| 
 | ||||
| @global_preferences_registry.register | ||||
| class Enabled(preferences.DefaultFromSettingMixin, types.BooleanPreference): | ||||
| class Enabled(types.BooleanPreference): | ||||
|     section = federation | ||||
|     name = "enabled" | ||||
|     setting = "FEDERATION_ENABLED" | ||||
|     default = True | ||||
|     verbose_name = "Federation enabled" | ||||
|     help_text = ( | ||||
|         "Use this setting to enable or disable federation logic and API" " globally." | ||||
|  | @ -33,20 +31,20 @@ class Enabled(preferences.DefaultFromSettingMixin, types.BooleanPreference): | |||
| 
 | ||||
| 
 | ||||
| @global_preferences_registry.register | ||||
| class CollectionPageSize(preferences.DefaultFromSettingMixin, types.IntPreference): | ||||
| class CollectionPageSize(types.IntPreference): | ||||
|     section = federation | ||||
|     name = "collection_page_size" | ||||
|     setting = "FEDERATION_COLLECTION_PAGE_SIZE" | ||||
|     default = 50 | ||||
|     verbose_name = "Federation collection page size" | ||||
|     help_text = "How many items to display in ActivityPub collections." | ||||
|     field_kwargs = {"required": False} | ||||
| 
 | ||||
| 
 | ||||
| @global_preferences_registry.register | ||||
| class ActorFetchDelay(preferences.DefaultFromSettingMixin, types.IntPreference): | ||||
| class ActorFetchDelay(types.IntPreference): | ||||
|     section = federation | ||||
|     name = "actor_fetch_delay" | ||||
|     setting = "FEDERATION_ACTOR_FETCH_DELAY" | ||||
|     default = 60 * 12 | ||||
|     verbose_name = "Federation actor fetch delay" | ||||
|     help_text = ( | ||||
|         "How many minutes to wait before refetching actors on " | ||||
|  |  | |||
|  | @ -938,8 +938,6 @@ class PaginatedCollectionSerializer(jsonld.JsonLdSerializer): | |||
|         last = common_utils.set_query_parameter(conf["id"], page=paginator.num_pages) | ||||
|         d = { | ||||
|             "id": conf["id"], | ||||
|             # XXX Stable release: remove the obsolete actor field | ||||
|             "actor": conf["actor"].fid, | ||||
|             "attributedTo": conf["actor"].fid, | ||||
|             "totalItems": paginator.count, | ||||
|             "type": conf.get("type", "Collection"), | ||||
|  | @ -1004,9 +1002,8 @@ class LibrarySerializer(PaginatedCollectionSerializer): | |||
|             "name": library.name, | ||||
|             "summary": library.description, | ||||
|             "page_size": 100, | ||||
|             # XXX Stable release: remove the obsolete actor field | ||||
|             "actor": library.actor, | ||||
|             "attributedTo": library.actor, | ||||
|             "actor": library.actor, | ||||
|             "items": library.uploads.for_federation(), | ||||
|             "type": "Library", | ||||
|         } | ||||
|  | @ -1108,8 +1105,6 @@ class CollectionPageSerializer(jsonld.JsonLdSerializer): | |||
|             ], | ||||
|         } | ||||
|         if conf["actor"]: | ||||
|             # XXX Stable release: remove the obsolete actor field | ||||
|             d["actor"] = conf["actor"].fid | ||||
|             d["attributedTo"] = conf["actor"].fid | ||||
| 
 | ||||
|         if page.has_previous(): | ||||
|  | @ -1297,8 +1292,7 @@ class AlbumSerializer(MusicEntitySerializer): | |||
|         child=MultipleSerializer(allowed=[BasicActorSerializer, ArtistSerializer]), | ||||
|         min_length=1, | ||||
|     ) | ||||
|     # XXX: 1.0 rename to image | ||||
|     cover = ImageSerializer( | ||||
|     image = ImageSerializer( | ||||
|         allowed_mimetypes=["image/*"], | ||||
|         allow_null=True, | ||||
|         required=False, | ||||
|  | @ -1306,7 +1300,7 @@ class AlbumSerializer(MusicEntitySerializer): | |||
|     ) | ||||
|     updateable_fields = [ | ||||
|         ("name", "title"), | ||||
|         ("cover", "attachment_cover"), | ||||
|         ("image", "attachment_cover"), | ||||
|         ("musicbrainzId", "mbid"), | ||||
|         ("attributedTo", "attributed_to"), | ||||
|         ("released", "release_date"), | ||||
|  | @ -1320,7 +1314,7 @@ class AlbumSerializer(MusicEntitySerializer): | |||
|             { | ||||
|                 "released": jsonld.first_val(contexts.FW.released), | ||||
|                 "artists": jsonld.first_attr(contexts.FW.artists, "@list"), | ||||
|                 "cover": jsonld.first_obj(contexts.FW.cover), | ||||
|                 "image": jsonld.first_obj(contexts.AS.image), | ||||
|             }, | ||||
|         ) | ||||
| 
 | ||||
|  | @ -1354,11 +1348,6 @@ class AlbumSerializer(MusicEntitySerializer): | |||
|             ] | ||||
|         include_content(d, instance.description) | ||||
|         if instance.attachment_cover: | ||||
|             d["cover"] = { | ||||
|                 "type": "Link", | ||||
|                 "href": instance.attachment_cover.download_url_original, | ||||
|                 "mediaType": instance.attachment_cover.mimetype or "image/jpeg", | ||||
|             } | ||||
|             include_image(d, instance.attachment_cover) | ||||
| 
 | ||||
|         if self.context.get("include_ap_context", self.parent is None): | ||||
|  |  | |||
|  | @ -218,7 +218,6 @@ def should_redirect_ap_to_html(accept_header, default=True): | |||
|         "text/html", | ||||
|     ] | ||||
|     no_redirect_headers = [ | ||||
|         "*/*",  # XXX backward compat with older Funkwhale instances that don't send the Accept header | ||||
|         "application/json", | ||||
|         "application/activity+json", | ||||
|         "application/ld+json", | ||||
|  |  | |||
|  | @ -0,0 +1,22 @@ | |||
| # Generated by Django 3.0.8 on 2020-08-03 12:22 | ||||
| 
 | ||||
| from django.db import migrations, models | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('moderation', '0005_auto_20200317_0820'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.RemoveField( | ||||
|             model_name='userrequest', | ||||
|             name='url', | ||||
|         ), | ||||
|         migrations.AlterField( | ||||
|             model_name='userrequest', | ||||
|             name='status', | ||||
|             field=models.CharField(choices=[('pending', 'Pending'), ('refused', 'Refused'), ('approved', 'Approved')], default='pending', max_length=40), | ||||
|         ), | ||||
|     ] | ||||
|  | @ -20,7 +20,6 @@ from django.db.models.signals import post_save, pre_save | |||
| from django.dispatch import receiver | ||||
| from django.urls import reverse | ||||
| from django.utils import timezone | ||||
| from versatileimagefield.fields import VersatileImageField | ||||
| 
 | ||||
| from funkwhale_api import musicbrainz | ||||
| from funkwhale_api.common import fields | ||||
|  | @ -325,10 +324,6 @@ class Album(APIModelMixin): | |||
|     artist = models.ForeignKey(Artist, related_name="albums", on_delete=models.CASCADE) | ||||
|     release_date = models.DateField(null=True, blank=True, db_index=True) | ||||
|     release_group_id = models.UUIDField(null=True, blank=True) | ||||
|     # XXX: 1.0 clean this uneeded field in favor of attachment_cover | ||||
|     cover = VersatileImageField( | ||||
|         upload_to="albums/covers/%Y/%m/%d", null=True, blank=True | ||||
|     ) | ||||
|     attachment_cover = models.ForeignKey( | ||||
|         "common.Attachment", | ||||
|         null=True, | ||||
|  |  | |||
|  | @ -32,10 +32,7 @@ COVER_WRITE_FIELD = common_serializers.RelatedField( | |||
| from funkwhale_api.audio import serializers as audio_serializers  # NOQA | ||||
| 
 | ||||
| 
 | ||||
| class CoverField( | ||||
|     common_serializers.NullToEmptDict, common_serializers.AttachmentSerializer | ||||
| ): | ||||
|     # XXX: BACKWARD COMPATIBILITY | ||||
| class CoverField(common_serializers.AttachmentSerializer): | ||||
|     pass | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -364,7 +364,7 @@ def federation_audio_track_to_metadata(payload, references): | |||
|             "mbid": str(payload["album"]["musicbrainzId"]) | ||||
|             if payload["album"].get("musicbrainzId") | ||||
|             else None, | ||||
|             "cover_data": get_cover(payload["album"], "cover"), | ||||
|             "cover_data": get_cover(payload["album"], "image"), | ||||
|             "release_date": payload["album"].get("released"), | ||||
|             "tags": [t["name"] for t in payload["album"].get("tags", []) or []], | ||||
|             "artists": [ | ||||
|  | @ -896,8 +896,6 @@ UPDATE_CONFIG = { | |||
| 
 | ||||
| @transaction.atomic | ||||
| def update_track_metadata(audio_metadata, track): | ||||
|     # XXX: implement this to support updating metadata when an imported files | ||||
|     # is updated by an outside tool (e.g beets). | ||||
|     serializer = metadata.TrackMetadataSerializer(data=audio_metadata) | ||||
|     serializer.is_valid(raise_exception=True) | ||||
|     new_data = serializer.validated_data | ||||
|  |  | |||
|  | @ -797,20 +797,11 @@ class Search(views.APIView): | |||
|         return Response(results, status=200) | ||||
| 
 | ||||
|     def get_tracks(self, query): | ||||
|         search_fields = [ | ||||
|             "mbid", | ||||
|             "title__unaccent", | ||||
|             "album__title__unaccent", | ||||
|             "artist__name__unaccent", | ||||
|         ] | ||||
|         if settings.USE_FULL_TEXT_SEARCH: | ||||
|         query_obj = utils.get_fts_query( | ||||
|             query, | ||||
|             fts_fields=["body_text", "album__body_text", "artist__body_text"], | ||||
|             model=models.Track, | ||||
|         ) | ||||
|         else: | ||||
|             query_obj = utils.get_query(query, search_fields) | ||||
|         qs = ( | ||||
|             models.Track.objects.all() | ||||
|             .filter(query_obj) | ||||
|  | @ -828,13 +819,9 @@ class Search(views.APIView): | |||
|         return common_utils.order_for_search(qs, "title")[: self.max_results] | ||||
| 
 | ||||
|     def get_albums(self, query): | ||||
|         search_fields = ["mbid", "title__unaccent", "artist__name__unaccent"] | ||||
|         if settings.USE_FULL_TEXT_SEARCH: | ||||
|         query_obj = utils.get_fts_query( | ||||
|             query, fts_fields=["body_text", "artist__body_text"], model=models.Album | ||||
|         ) | ||||
|         else: | ||||
|             query_obj = utils.get_query(query, search_fields) | ||||
|         qs = ( | ||||
|             models.Album.objects.all() | ||||
|             .filter(query_obj) | ||||
|  | @ -844,11 +831,7 @@ class Search(views.APIView): | |||
|         return common_utils.order_for_search(qs, "title")[: self.max_results] | ||||
| 
 | ||||
|     def get_artists(self, query): | ||||
|         search_fields = ["mbid", "name__unaccent"] | ||||
|         if settings.USE_FULL_TEXT_SEARCH: | ||||
|         query_obj = utils.get_fts_query(query, model=models.Artist) | ||||
|         else: | ||||
|             query_obj = utils.get_query(query, search_fields) | ||||
|         qs = ( | ||||
|             models.Artist.objects.all() | ||||
|             .filter(query_obj) | ||||
|  |  | |||
|  | @ -1,16 +1,14 @@ | |||
| from dynamic_preferences import types | ||||
| from dynamic_preferences.registries import global_preferences_registry | ||||
| 
 | ||||
| from funkwhale_api.common import preferences | ||||
| 
 | ||||
| playlists = types.Section("playlists") | ||||
| 
 | ||||
| 
 | ||||
| @global_preferences_registry.register | ||||
| class MaxTracks(preferences.DefaultFromSettingMixin, types.IntegerPreference): | ||||
| class MaxTracks(types.IntegerPreference): | ||||
|     show_in_api = True | ||||
|     section = playlists | ||||
|     name = "max_tracks" | ||||
|     default = 250 | ||||
|     verbose_name = "Max tracks per playlist" | ||||
|     setting = "PLAYLISTS_MAX_TRACKS" | ||||
|     field_kwargs = {"required": False} | ||||
|  |  | |||
|  | @ -31,7 +31,6 @@ class PlaylistFilter(filters.FilterSet): | |||
|     class Meta: | ||||
|         model = models.Playlist | ||||
|         fields = { | ||||
|             "user": ["exact"], | ||||
|             "name": ["exact", "icontains"], | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -227,7 +227,6 @@ class PlaylistTrack(models.Model): | |||
| 
 | ||||
|     class Meta: | ||||
|         ordering = ("-playlist", "index") | ||||
|         unique_together = ("playlist", "index") | ||||
| 
 | ||||
|     def delete(self, *args, **kwargs): | ||||
|         playlist = self.playlist | ||||
|  |  | |||
|  | @ -0,0 +1,20 @@ | |||
| # Generated by Django 3.0.8 on 2020-08-03 12:22 | ||||
| 
 | ||||
| import django.contrib.postgres.fields.jsonb | ||||
| import django.core.serializers.json | ||||
| from django.db import migrations | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('radios', '0004_auto_20180107_1813'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AlterField( | ||||
|             model_name='radio', | ||||
|             name='config', | ||||
|             field=django.contrib.postgres.fields.jsonb.JSONField(encoder=django.core.serializers.json.DjangoJSONEncoder), | ||||
|         ), | ||||
|     ] | ||||
|  | @ -0,0 +1,25 @@ | |||
| # Generated by Django 3.0.8 on 2020-08-03 12:22 | ||||
| 
 | ||||
| from django.db import migrations, models | ||||
| import django.db.models.deletion | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('contenttypes', '0002_remove_content_type_name'), | ||||
|         ('tags', '0001_initial'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AlterField( | ||||
|             model_name='taggeditem', | ||||
|             name='content_type', | ||||
|             field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tagged_items', to='contenttypes.ContentType', verbose_name='Content type'), | ||||
|         ), | ||||
|         migrations.AlterField( | ||||
|             model_name='taggeditem', | ||||
|             name='tag', | ||||
|             field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tagged_items', to='tags.Tag'), | ||||
|         ), | ||||
|     ] | ||||
|  | @ -1,30 +0,0 @@ | |||
| import pytest | ||||
| from rest_framework_jwt.settings import api_settings | ||||
| 
 | ||||
| from funkwhale_api.common.auth import TokenAuthMiddleware | ||||
| 
 | ||||
| jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER | ||||
| jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("query_string", [b"token=wrong", b""]) | ||||
| def test_header_anonymous(query_string, factories): | ||||
|     def callback(scope): | ||||
|         assert scope["user"].is_anonymous | ||||
| 
 | ||||
|     scope = {"query_string": query_string} | ||||
|     consumer = TokenAuthMiddleware(callback) | ||||
|     consumer(scope) | ||||
| 
 | ||||
| 
 | ||||
| def test_header_correct_token(factories): | ||||
|     user = factories["users.User"]() | ||||
|     payload = jwt_payload_handler(user) | ||||
|     token = jwt_encode_handler(payload) | ||||
| 
 | ||||
|     def callback(scope): | ||||
|         assert scope["user"] == user | ||||
| 
 | ||||
|     scope = {"query_string": "token={}".format(token).encode("utf-8")} | ||||
|     consumer = TokenAuthMiddleware(callback) | ||||
|     consumer(scope) | ||||
|  | @ -17,7 +17,7 @@ from django import urls | |||
|         "/api/v1/auth/registration/account-confirm-email/key", | ||||
|         "/api/v1/history/listenings", | ||||
|         "/api/v1/radios/sessions", | ||||
|         "/api/v1/users/users/me", | ||||
|         "/api/v1/users/me", | ||||
|         "/api/v1/federation/follows/library", | ||||
|         "/api/v1/manage/accounts", | ||||
|         "/api/v1/oauth/apps", | ||||
|  |  | |||
|  | @ -201,15 +201,6 @@ def test_attachment_serializer_existing_file(factories, to_api_date): | |||
|                 attachment.file.crop["200x200"].url | ||||
|             ), | ||||
|         }, | ||||
|         # XXX: BACKWARD COMPATIBILITY | ||||
|         "original": federation_utils.full_url(attachment.file.url), | ||||
|         "medium_square_crop": federation_utils.full_url( | ||||
|             attachment.file.crop["200x200"].url | ||||
|         ), | ||||
|         "small_square_crop": federation_utils.full_url( | ||||
|             attachment.file.crop["200x200"].url | ||||
|         ), | ||||
|         "square_crop": federation_utils.full_url(attachment.file.crop["200x200"].url), | ||||
|     } | ||||
| 
 | ||||
|     serializer = serializers.AttachmentSerializer(attachment) | ||||
|  | @ -237,17 +228,6 @@ def test_attachment_serializer_remote_file(factories, to_api_date): | |||
|                 proxy_url + "?next=medium_square_crop" | ||||
|             ), | ||||
|         }, | ||||
|         # XXX: BACKWARD COMPATIBILITY | ||||
|         "original": federation_utils.full_url(proxy_url + "?next=original"), | ||||
|         "medium_square_crop": federation_utils.full_url( | ||||
|             proxy_url + "?next=medium_square_crop" | ||||
|         ), | ||||
|         "square_crop": federation_utils.full_url( | ||||
|             proxy_url + "?next=medium_square_crop" | ||||
|         ), | ||||
|         "small_square_crop": federation_utils.full_url( | ||||
|             proxy_url + "?next=medium_square_crop" | ||||
|         ), | ||||
|     } | ||||
| 
 | ||||
|     serializer = serializers.AttachmentSerializer(attachment) | ||||
|  |  | |||
|  | @ -20,10 +20,11 @@ def test_user_can_get_his_favorites( | |||
|     api_request, factories, logged_in_api_client, client | ||||
| ): | ||||
|     request = api_request.get("/") | ||||
|     logged_in_api_client.user.create_actor() | ||||
|     favorite = factories["favorites.TrackFavorite"](user=logged_in_api_client.user) | ||||
|     factories["favorites.TrackFavorite"]() | ||||
|     url = reverse("api:v1:favorites:tracks-list") | ||||
|     response = logged_in_api_client.get(url, {"user": logged_in_api_client.user.pk}) | ||||
|     response = logged_in_api_client.get(url, {"scope": "me"}) | ||||
|     expected = [ | ||||
|         serializers.UserTrackFavoriteSerializer( | ||||
|             favorite, context={"request": request} | ||||
|  |  | |||
|  | @ -388,7 +388,6 @@ def test_paginated_collection_serializer(factories): | |||
|         "@context": jsonld.get_default_context(), | ||||
|         "type": "Collection", | ||||
|         "id": conf["id"], | ||||
|         "actor": actor.fid, | ||||
|         "attributedTo": actor.fid, | ||||
|         "totalItems": len(uploads), | ||||
|         "current": conf["id"] + "?page=1", | ||||
|  | @ -486,7 +485,6 @@ def test_collection_page_serializer(factories): | |||
|         "@context": jsonld.get_default_context(), | ||||
|         "type": "CollectionPage", | ||||
|         "id": conf["id"] + "?page=2", | ||||
|         "actor": actor.fid, | ||||
|         "attributedTo": actor.fid, | ||||
|         "totalItems": len(uploads), | ||||
|         "partOf": conf["id"], | ||||
|  | @ -521,7 +519,6 @@ def test_music_library_serializer_to_ap(factories): | |||
|         "id": library.fid, | ||||
|         "name": library.name, | ||||
|         "summary": library.description, | ||||
|         "actor": library.actor.fid, | ||||
|         "attributedTo": library.actor.fid, | ||||
|         "totalItems": 0, | ||||
|         "current": library.fid + "?page=1", | ||||
|  | @ -764,11 +761,6 @@ def test_activity_pub_album_serializer_to_ap(factories): | |||
|         "type": "Album", | ||||
|         "id": album.fid, | ||||
|         "name": album.title, | ||||
|         "cover": { | ||||
|             "type": "Link", | ||||
|             "mediaType": "image/jpeg", | ||||
|             "href": utils.full_url(album.attachment_cover.file.url), | ||||
|         }, | ||||
|         "image": { | ||||
|             "type": "Image", | ||||
|             "mediaType": "image/jpeg", | ||||
|  | @ -815,7 +807,7 @@ def test_activity_pub_album_serializer_from_ap_create(factories, faker, now): | |||
|         "type": "Album", | ||||
|         "id": "https://album.example", | ||||
|         "name": faker.sentence(), | ||||
|         "cover": {"type": "Link", "mediaType": "image/jpeg", "href": faker.url()}, | ||||
|         "image": {"type": "Link", "mediaType": "image/jpeg", "href": faker.url()}, | ||||
|         "musicbrainzId": faker.uuid4(), | ||||
|         "published": now.isoformat(), | ||||
|         "released": released.isoformat(), | ||||
|  | @ -839,8 +831,8 @@ def test_activity_pub_album_serializer_from_ap_create(factories, faker, now): | |||
|     assert str(album.mbid) == payload["musicbrainzId"] | ||||
|     assert album.release_date == released | ||||
|     assert album.artist == artist | ||||
|     assert album.attachment_cover.url == payload["cover"]["href"] | ||||
|     assert album.attachment_cover.mimetype == payload["cover"]["mediaType"] | ||||
|     assert album.attachment_cover.url == payload["image"]["href"] | ||||
|     assert album.attachment_cover.mimetype == payload["image"]["mediaType"] | ||||
|     assert sorted(album.tagged_items.values_list("tag__name", flat=True)) == [ | ||||
|         "Punk", | ||||
|         "Rock", | ||||
|  | @ -879,7 +871,7 @@ def test_activity_pub_album_serializer_from_ap_update(factories, faker): | |||
|         "type": "Album", | ||||
|         "id": album.fid, | ||||
|         "name": faker.sentence(), | ||||
|         "cover": {"type": "Link", "mediaType": "image/jpeg", "href": faker.url()}, | ||||
|         "image": {"type": "Link", "mediaType": "image/jpeg", "href": faker.url()}, | ||||
|         "musicbrainzId": faker.uuid4(), | ||||
|         "published": album.creation_date.isoformat(), | ||||
|         "released": released.isoformat(), | ||||
|  | @ -904,8 +896,8 @@ def test_activity_pub_album_serializer_from_ap_update(factories, faker): | |||
|     assert album.title == payload["name"] | ||||
|     assert str(album.mbid) == payload["musicbrainzId"] | ||||
|     assert album.release_date == released | ||||
|     assert album.attachment_cover.url == payload["cover"]["href"] | ||||
|     assert album.attachment_cover.mimetype == payload["cover"]["mediaType"] | ||||
|     assert album.attachment_cover.url == payload["image"]["href"] | ||||
|     assert album.attachment_cover.mimetype == payload["image"]["mediaType"] | ||||
|     assert sorted(album.tagged_items.values_list("tag__name", flat=True)) == [ | ||||
|         "Punk", | ||||
|         "Rock", | ||||
|  | @ -996,7 +988,7 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker): | |||
|             "content": "Album summary", | ||||
|             "mediaType": "text/markdown", | ||||
|             "attributedTo": album_attributed_to.fid, | ||||
|             "cover": { | ||||
|             "image": { | ||||
|                 "type": "Link", | ||||
|                 "href": "https://cover.image/test.png", | ||||
|                 "mediaType": "image/png", | ||||
|  | @ -1066,8 +1058,8 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker): | |||
|     assert track.attachment_cover.mimetype == data["image"]["mediaType"] | ||||
| 
 | ||||
|     assert album.from_activity == activity | ||||
|     assert album.attachment_cover.url == data["album"]["cover"]["href"] | ||||
|     assert album.attachment_cover.mimetype == data["album"]["cover"]["mediaType"] | ||||
|     assert album.attachment_cover.url == data["album"]["image"]["href"] | ||||
|     assert album.attachment_cover.mimetype == data["album"]["image"]["mediaType"] | ||||
|     assert album.title == data["album"]["name"] | ||||
|     assert album.fid == data["album"]["id"] | ||||
|     assert str(album.mbid) == data["album"]["musicbrainzId"] | ||||
|  | @ -1196,7 +1188,7 @@ def test_activity_pub_upload_serializer_from_ap(factories, mocker, r_mock): | |||
|                 "musicbrainzId": str(uuid.uuid4()), | ||||
|                 "published": published.isoformat(), | ||||
|                 "released": released.isoformat(), | ||||
|                 "cover": { | ||||
|                 "image": { | ||||
|                     "type": "Link", | ||||
|                     "href": "https://cover.image/test.png", | ||||
|                     "mediaType": "image/png", | ||||
|  | @ -1222,7 +1214,7 @@ def test_activity_pub_upload_serializer_from_ap(factories, mocker, r_mock): | |||
|             ], | ||||
|         }, | ||||
|     } | ||||
|     r_mock.get(data["track"]["album"]["cover"]["href"], body=io.BytesIO(b"coucou")) | ||||
|     r_mock.get(data["track"]["album"]["image"]["href"], body=io.BytesIO(b"coucou")) | ||||
| 
 | ||||
|     serializer = serializers.UploadSerializer(data=data, context={"activity": activity}) | ||||
|     assert serializer.is_valid(raise_exception=True) | ||||
|  | @ -1266,7 +1258,7 @@ def test_activity_pub_upload_serializer_from_ap_update(factories, mocker, now, r | |||
|         "library": library.fid, | ||||
|         "track": serializers.TrackSerializer(upload.track).data, | ||||
|     } | ||||
|     r_mock.get(data["track"]["album"]["cover"]["href"], body=io.BytesIO(b"coucou")) | ||||
|     r_mock.get(data["track"]["album"]["image"]["url"], body=io.BytesIO(b"coucou")) | ||||
| 
 | ||||
|     serializer = serializers.UploadSerializer(upload, data=data) | ||||
|     assert serializer.is_valid(raise_exception=True) | ||||
|  | @ -1628,7 +1620,6 @@ def test_channel_actor_outbox_serializer(factories): | |||
|         "@context": jsonld.get_default_context(), | ||||
|         "type": "OrderedCollection", | ||||
|         "id": channel.actor.outbox_url, | ||||
|         "actor": channel.actor.fid, | ||||
|         "attributedTo": channel.actor.fid, | ||||
|         "totalItems": len(uploads), | ||||
|         "first": channel.actor.outbox_url + "?page=1", | ||||
|  |  | |||
|  | @ -384,11 +384,6 @@ def test_music_upload_detail_private_approved_follow( | |||
|         ("text/html,application/xhtml+xml", True, True), | ||||
|         ("text/html,application/json", True, True), | ||||
|         ("", True, False), | ||||
|         ( | ||||
|             "*/*", | ||||
|             True, | ||||
|             False, | ||||
|         ),  # XXX: compat with older versions of Funkwhale that miss the Accept header | ||||
|         (None, True, False), | ||||
|         ("application/json", True, False), | ||||
|         ("application/activity+json", True, False), | ||||
|  |  | |||
|  | @ -196,15 +196,6 @@ def test_album_serializer(factories, to_api_date): | |||
|     assert serializer.data == expected | ||||
| 
 | ||||
| 
 | ||||
| def test_album_serializer_empty_cover(factories, to_api_date): | ||||
|     # XXX: BACKWARD COMPATIBILITY | ||||
|     album = factories["music.Album"](attachment_cover=None) | ||||
| 
 | ||||
|     serializer = serializers.AlbumSerializer(album) | ||||
| 
 | ||||
|     assert serializer.data["cover"] == {} | ||||
| 
 | ||||
| 
 | ||||
| def test_track_serializer(factories, to_api_date): | ||||
|     actor = factories["federation.Actor"]() | ||||
|     upload = factories["music.Upload"]( | ||||
|  |  | |||
|  | @ -660,7 +660,7 @@ def test_federation_audio_track_to_metadata(now, mocker): | |||
|                     }, | ||||
|                 } | ||||
|             ], | ||||
|             "cover": { | ||||
|             "image": { | ||||
|                 "type": "Link", | ||||
|                 "href": "http://cover.test", | ||||
|                 "mediaType": "image/png", | ||||
|  | @ -713,8 +713,8 @@ def test_federation_audio_track_to_metadata(now, mocker): | |||
|             "tags": ["AlbumTag"], | ||||
|             "description": {"content_type": "text/plain", "text": "album desc"}, | ||||
|             "cover_data": { | ||||
|                 "mimetype": serializer.validated_data["album"]["cover"]["mediaType"], | ||||
|                 "url": serializer.validated_data["album"]["cover"]["href"], | ||||
|                 "mimetype": serializer.validated_data["album"]["image"]["mediaType"], | ||||
|                 "url": serializer.validated_data["album"]["image"]["href"], | ||||
|             }, | ||||
|             "artists": [ | ||||
|                 { | ||||
|  |  | |||
|  | @ -1307,9 +1307,7 @@ def test_get_upload_audio_metadata(logged_in_api_client, factories): | |||
|     assert response.data == serializer.validated_data | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("use_fts", [True, False]) | ||||
| def test_search_get(use_fts, settings, logged_in_api_client, factories): | ||||
|     settings.USE_FULL_TEXT_SEARCH = use_fts | ||||
| def test_search_get(logged_in_api_client, factories): | ||||
|     artist = factories["music.Artist"](name="Foo Fighters") | ||||
|     album = factories["music.Album"](title="Foo Bar") | ||||
|     track = factories["music.Track"](title="Foo Baz") | ||||
|  | @ -1332,8 +1330,7 @@ def test_search_get(use_fts, settings, logged_in_api_client, factories): | |||
|     assert response.data == expected | ||||
| 
 | ||||
| 
 | ||||
| def test_search_get_fts_advanced(settings, logged_in_api_client, factories): | ||||
|     settings.USE_FULL_TEXT_SEARCH = True | ||||
| def test_search_get_fts_advanced(logged_in_api_client, factories): | ||||
|     artist1 = factories["music.Artist"](name="Foo Bighters") | ||||
|     artist2 = factories["music.Artist"](name="Bar Fighter") | ||||
|     factories["music.Artist"]() | ||||
|  | @ -1353,8 +1350,7 @@ def test_search_get_fts_advanced(settings, logged_in_api_client, factories): | |||
|     assert response.data == expected | ||||
| 
 | ||||
| 
 | ||||
| def test_search_get_fts_stop_words(settings, logged_in_api_client, factories): | ||||
|     settings.USE_FULL_TEXT_SEARCH = True | ||||
| def test_search_get_fts_stop_words(logged_in_api_client, factories): | ||||
|     artist = factories["music.Artist"](name="she") | ||||
|     factories["music.Artist"](name="something else") | ||||
| 
 | ||||
|  |  | |||
|  | @ -720,7 +720,7 @@ User: | |||
|       type: "string" | ||||
|       example: "Alice Kingsley" | ||||
|     avatar: | ||||
|       $ref: "#/Avatar" | ||||
|       $ref: "#/Attachment" | ||||
| 
 | ||||
| Me: | ||||
|   type: "object" | ||||
|  | @ -767,29 +767,7 @@ Me: | |||
|                 via request headers isn't possible. | ||||
| 
 | ||||
|                 The token expires after 3 days by default. | ||||
| Avatar: | ||||
|   type: "object" | ||||
|   properties: | ||||
|     original: | ||||
|       type: "string" | ||||
|       format: "uri" | ||||
|       description: "Original image URL" | ||||
|       example: "http://yourinstance/media/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996.jpg" | ||||
|     square_crop: | ||||
|       type: "string" | ||||
|       format: "uri" | ||||
|       description: "400x400 thumbnail URL" | ||||
|       example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-400x400-70.jpg" | ||||
|     small_square_crop: | ||||
|       type: "string" | ||||
|       format: "uri" | ||||
|       description: "50x50 thumbnail URL" | ||||
|       example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-50x50-70.jpg" | ||||
|     medium_square_crop: | ||||
|       type: "string" | ||||
|       format: "uri" | ||||
|       description: "200x200 thumbnail URL" | ||||
|       example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-200x200-70.jpg" | ||||
| 
 | ||||
|                 QuotaStatus: | ||||
|   type: "object" | ||||
|   properties: | ||||
|  |  | |||
|  | @ -296,7 +296,7 @@ paths: | |||
|       responses: | ||||
|         200: | ||||
|           $ref: "#/responses/200" | ||||
|   /api/v1/users/users/me/: | ||||
|   /api/v1/users/me/: | ||||
|     get: | ||||
|       summary: Retrive profile information | ||||
|       description: | | ||||
|  |  | |||
|  | @ -337,7 +337,7 @@ export default { | |||
|     }, | ||||
|     getCover(albumCover) { | ||||
|       if (albumCover) { | ||||
|         return albumCover.medium_square_crop | ||||
|         return albumCover.urls.medium_square_crop | ||||
|       } | ||||
|     }, | ||||
|     getSources (uploads) { | ||||
|  |  | |||
|  | @ -6,8 +6,8 @@ | |||
|           <div class="ui six wide column current-track"> | ||||
|             <div class="ui basic segment" id="player"> | ||||
|               <template v-if="currentTrack"> | ||||
|                 <img ref="cover" alt="" v-if="currentTrack.cover && currentTrack.cover.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.medium_square_crop)"> | ||||
|                 <img ref="cover" alt="" v-else-if="currentTrack.album && currentTrack.album.cover && currentTrack.album.cover.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.medium_square_crop)"> | ||||
|                 <img ref="cover" alt="" v-if="currentTrack.cover && currentTrack.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.urls.medium_square_crop)"> | ||||
|                 <img ref="cover" alt="" v-else-if="currentTrack.album && currentTrack.album.cover && currentTrack.album.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.urls.medium_square_crop)"> | ||||
|                 <img class="ui image" alt="" v-else src="../assets/audio/default-cover.png"> | ||||
|                 <h1 class="ui header"> | ||||
|                   <div class="content ellipsis"> | ||||
|  | @ -159,8 +159,8 @@ | |||
|                     <i class="grip lines icon"></i> | ||||
|                   </td> | ||||
|                   <td class="image-cell" @click="$store.dispatch('queue/currentIndex', index)"> | ||||
|                     <img class="ui mini image" alt="" v-if="track.cover && track.cover.original" :src="$store.getters['instance/absoluteUrl'](track.cover.medium_square_crop)"> | ||||
|                     <img class="ui mini image" alt="" v-else-if="track.album && track.album.cover && track.album.cover.original" :src="$store.getters['instance/absoluteUrl'](track.album.cover.medium_square_crop)"> | ||||
|                     <img class="ui mini image" alt="" v-if="track.cover && track.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](track.cover.urls.medium_square_crop)"> | ||||
|                     <img class="ui mini image" alt="" v-else-if="track.album && track.album.cover && track.album.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](track.album.cover.urls.medium_square_crop)"> | ||||
|                     <img class="ui mini image" alt="" v-else src="../assets/audio/default-cover.png"> | ||||
|                   </td> | ||||
|                   <td colspan="3" @click="$store.dispatch('queue/currentIndex', index)"> | ||||
|  |  | |||
|  | @ -78,7 +78,7 @@ | |||
|         </router-link> | ||||
|         <div class="item"> | ||||
|           <div class="ui user-dropdown dropdown" > | ||||
|             <img class="ui avatar image" alt="" v-if="$store.state.auth.profile.avatar && $store.state.auth.profile.avatar.square_crop" :src="$store.getters['instance/absoluteUrl']($store.state.auth.profile.avatar.square_crop)" /> | ||||
|             <img class="ui avatar image" alt="" v-if="$store.state.auth.profile.avatar && $store.state.auth.profile.avatar.urls.square_crop" :src="$store.getters['instance/absoluteUrl']($store.state.auth.profile.avatar.urls.square_crop)" /> | ||||
|             <actor-avatar v-else :actor="{preferred_username: $store.state.auth.username, full_username: $store.state.auth.username}" /> | ||||
|             <div class="menu"> | ||||
|               <router-link class="item" :to="{name: 'profile.overview', params: {username: $store.state.auth.username}}"><translate translate-context="*/*/*/Noun">Profile</translate></router-link> | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| <template> | ||||
|   <router-link class="artist-label ui image label" :to="route"> | ||||
|     <img :class="[{circular: artist.content_category != 'podcast'}]" alt="" v-if="artist.cover && artist.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](artist.cover.small_square_crop)" /> | ||||
|     <img alt="" :class="[{circular: artist.content_category != 'podcast'}]" v-if="artist.cover && artist.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](artist.cover.urls.medium_square_crop)" /> | ||||
|     <i :class="[artist.content_category != 'podcast' ? 'circular' : 'bordered', 'inverted violet users icon']" v-else /> | ||||
|     {{ artist.name }} | ||||
|   </router-link> | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ export default { | |||
|   computed: { | ||||
|     imageUrl () { | ||||
|       if (this.object.artist.cover) { | ||||
|         return this.$store.getters['instance/absoluteUrl'](this.object.artist.cover.medium_square_crop) | ||||
|         return this.$store.getters['instance/absoluteUrl'](this.object.artist.cover.urls.medium_square_crop) | ||||
|       } | ||||
|     }, | ||||
|     urlId () { | ||||
|  |  | |||
|  | @ -7,8 +7,8 @@ | |||
|       @click="$router.push({name: 'library.tracks.detail', params: {id: entry.id}})" | ||||
|       alt="" | ||||
|       class="channel-image image" | ||||
|       v-if="cover && cover.original" | ||||
|       v-lazy="$store.getters['instance/absoluteUrl'](cover.square_crop)"> | ||||
|       v-if="cover && cover.urls.original" | ||||
|       v-lazy="$store.getters['instance/absoluteUrl'](cover.urls.square_crop)"> | ||||
|     <span | ||||
|       @click="$router.push({name: 'library.tracks.detail', params: {id: entry.id}})" | ||||
|       class="channel-image image" | ||||
|  | @ -17,8 +17,8 @@ | |||
|       @click="$router.push({name: 'library.tracks.detail', params: {id: entry.id}})" | ||||
|       alt="" | ||||
|       class="channel-image image" | ||||
|       v-else-if="entry.album && entry.album.cover && entry.album.cover.original" | ||||
|       v-lazy="$store.getters['instance/absoluteUrl'](entry.album.cover.square_crop)"> | ||||
|       v-else-if="entry.album && entry.album.cover && entry.album.cover.urls.original" | ||||
|       v-lazy="$store.getters['instance/absoluteUrl'](entry.album.cover.urls.square_crop)"> | ||||
|     <img | ||||
|       @click="$router.push({name: 'library.tracks.detail', params: {id: entry.id}})" | ||||
|       alt="" | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| <template> | ||||
|   <div class="channel-serie-card"> | ||||
|     <div class="two-images"> | ||||
|       <img @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" alt="" v-if="cover.original" v-lazy="$store.getters['instance/absoluteUrl'](cover.square_crop)"> | ||||
|       <img @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" alt="" v-else src="../../assets/audio/default-cover.png"> | ||||
|       <img @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" alt="" v-if="cover.original" v-lazy="$store.getters['instance/absoluteUrl'](cover.square_crop)"> | ||||
|       <img @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" alt="" v-else src="../../assets/audio/default-cover.png"> | ||||
|       <img alt="" @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" v-if="cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](cover.urls.square_crop)"> | ||||
|       <img alt="" @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" v-else src="../../assets/audio/default-cover.png"> | ||||
|       <img alt="" @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" v-if="cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](cover.urls.square_crop)"> | ||||
|       <img alt="" @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" v-else src="../../assets/audio/default-cover.png"> | ||||
|     </div> | ||||
|     <div class="content ellipsis"> | ||||
|       <strong> | ||||
|  |  | |||
|  | @ -10,9 +10,9 @@ | |||
| 
 | ||||
|         <div class="controls track-controls queue-not-focused desktop-and-up"> | ||||
|           <div class="ui tiny image" @click.stop.prevent="$router.push({name: 'library.tracks.detail', params: {id: currentTrack.id }})"> | ||||
|             <img ref="cover" alt="" v-if="currentTrack.cover && currentTrack.cover.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.medium_square_crop)"> | ||||
|             <img ref="cover" alt="" v-else-if="currentTrack.album && currentTrack.album.cover && currentTrack.album.cover.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.medium_square_crop)"> | ||||
|             <img v-else src="../../assets/audio/default-cover.png" alt=""> | ||||
|             <img alt="" ref="cover" v-if="currentTrack.cover && currentTrack.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.urls.medium_square_crop)"> | ||||
|             <img alt="" ref="cover" v-else-if="currentTrack.album && currentTrack.album.cover.urls && currentTrack.album.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.urls.medium_square_crop)"> | ||||
|             <img alt="" v-else src="../../assets/audio/default-cover.png"> | ||||
|           </div> | ||||
|           <div @click.stop.prevent="" class="middle aligned content ellipsis"> | ||||
|             <strong> | ||||
|  | @ -30,9 +30,9 @@ | |||
|         </div> | ||||
|         <div class="controls track-controls queue-not-focused tablet-and-below"> | ||||
|           <div class="ui tiny image"> | ||||
|             <img ref="cover" alt="" v-if="currentTrack.cover && currentTrack.cover.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.medium_square_crop)"> | ||||
|             <img ref="cover" alt="" v-else-if="currentTrack.album && currentTrack.album.cover && currentTrack.album.cover.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.medium_square_crop)"> | ||||
|             <img v-else src="../../assets/audio/default-cover.png" alt=""> | ||||
|             <img alt="" ref="cover" v-if="currentTrack.cover && currentTrack.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.urls.medium_square_crop)"> | ||||
|             <img alt="" ref="cover" v-else-if="currentTrack.album && currentTrack.album.cover && currentTrack.album.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.urls.medium_square_crop)"> | ||||
|             <img alt="" v-else src="../../assets/audio/default-cover.png"> | ||||
|           </div> | ||||
|           <div class="middle aligned content ellipsis"> | ||||
|             <strong> | ||||
|  | @ -738,12 +738,12 @@ export default { | |||
|           if (this.currentTrack.album) { | ||||
|             metadata.album = this.currentTrack.album.title | ||||
|             metadata.artwork = [ | ||||
|               { src: this.currentTrack.album.cover.original, sizes: '96x96',   type: 'image/png' }, | ||||
|               { src: this.currentTrack.album.cover.original, sizes: '128x128', type: 'image/png' }, | ||||
|               { src: this.currentTrack.album.cover.original, sizes: '192x192', type: 'image/png' }, | ||||
|               { src: this.currentTrack.album.cover.original, sizes: '256x256', type: 'image/png' }, | ||||
|               { src: this.currentTrack.album.cover.original, sizes: '384x384', type: 'image/png' }, | ||||
|               { src: this.currentTrack.album.cover.original, sizes: '512x512', type: 'image/png' }, | ||||
|               { src: this.currentTrack.album.cover.urls.original, sizes: '96x96',   type: 'image/png' }, | ||||
|               { src: this.currentTrack.album.cover.urls.original, sizes: '128x128', type: 'image/png' }, | ||||
|               { src: this.currentTrack.album.cover.urls.original, sizes: '192x192', type: 'image/png' }, | ||||
|               { src: this.currentTrack.album.cover.urls.original, sizes: '256x256', type: 'image/png' }, | ||||
|               { src: this.currentTrack.album.cover.urls.original, sizes: '384x384', type: 'image/png' }, | ||||
|               { src: this.currentTrack.album.cover.urls.original, sizes: '512x512', type: 'image/png' }, | ||||
|             ] | ||||
|           } | ||||
|           navigator.mediaSession.metadata = new MediaMetadata(metadata); | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
|   <div class="card app-card component-album-card"> | ||||
|     <div | ||||
|       @click="$router.push({name: 'library.albums.detail', params: {id: album.id}})" | ||||
|       :class="['ui', 'head-image', 'image', {'default-cover': !album.cover.original}]" v-lazy:background-image="imageUrl"> | ||||
|       :class="['ui', 'head-image', 'image', {'default-cover': !album.cover || !album.cover.urls.original}]" v-lazy:background-image="imageUrl"> | ||||
|       <play-button :icon-only="true" :is-playable="album.is_playable" :button-classes="['ui', 'circular', 'large', 'vibrant', 'icon', 'button']" :album="album"></play-button> | ||||
|     </div> | ||||
|     <div class="content"> | ||||
|  | @ -38,8 +38,8 @@ export default { | |||
|   }, | ||||
|   computed: { | ||||
|     imageUrl () { | ||||
|       if (this.album.cover.original) { | ||||
|         return this.$store.getters['instance/absoluteUrl'](this.album.cover.medium_square_crop) | ||||
|       if (this.album.cover && this.album.cover.urls.original) { | ||||
|         return this.$store.getters['instance/absoluteUrl'](this.album.cover.urls.medium_square_crop) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
|   <div class="app-card card"> | ||||
|     <div | ||||
|       @click="$router.push({name: 'library.artists.detail', params: {id: artist.id}})" | ||||
|       :class="['ui', 'head-image', 'circular', 'image', {'default-cover': !cover.original}]" v-lazy:background-image="imageUrl"> | ||||
|       :class="['ui', 'head-image', 'circular', 'image', {'default-cover': !cover || !cover.urls.original}]" v-lazy:background-image="imageUrl"> | ||||
|       <play-button :icon-only="true" :is-playable="artist.is_playable" :button-classes="['ui', 'circular', 'large', 'vibrant', 'icon', 'button']" :artist="artist"></play-button> | ||||
|     </div> | ||||
|     <div class="content"> | ||||
|  | @ -40,19 +40,19 @@ export default { | |||
|   computed: { | ||||
|     imageUrl () { | ||||
|       let cover = this.cover | ||||
|       if (cover.original) { | ||||
|         return this.$store.getters['instance/absoluteUrl'](cover.medium_square_crop) | ||||
|       if (cover && cover.urls.original) { | ||||
|         return this.$store.getters['instance/absoluteUrl'](cover.urls.medium_square_crop) | ||||
|       } | ||||
|     }, | ||||
|     cover () { | ||||
|       if (this.artist.cover && this.artist.cover.original) { | ||||
|       if (this.artist.cover && this.artist.cover.urls.original) { | ||||
|         return this.artist.cover | ||||
|       } | ||||
|       return this.artist.albums.map((a) => { | ||||
|         return a.cover | ||||
|       }).filter((c) => { | ||||
|         return c && c.original | ||||
|       })[0] || {} | ||||
|         return c && c.urls.original | ||||
|       })[0] | ||||
|     }, | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -4,8 +4,8 @@ | |||
|       <play-button :class="['basic', {vibrant: currentTrack && isPlaying && track.id === currentTrack.id}, 'icon']" :discrete="true" :is-playable="playable" :track="track"></play-button> | ||||
|     </td> | ||||
|     <td> | ||||
|       <img class="ui mini image" alt="" v-if="track.album && track.album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](track.album.cover.small_square_crop)"> | ||||
|       <img class="ui mini image" alt="" v-else src="../../../assets/audio/default-cover.png"> | ||||
|       <img alt="" class="ui mini image" v-if="track.album && track.album.cover && track.album.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](track.album.cover.urls.medium_square_crop)"> | ||||
|       <img alt="" class="ui mini image" v-else src="../../../assets/audio/default-cover.png"> | ||||
|     </td> | ||||
|     <td colspan="6"> | ||||
|       <router-link class="track" :to="{name: 'library.tracks.detail', params: {id: track.id }}"> | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ | |||
|     <div v-if="count > 0" class="ui divided unstackable items"> | ||||
|       <div :class="['item', itemClasses]" v-for="object in objects" :key="object.id"> | ||||
|         <div class="ui tiny image"> | ||||
|           <img alt="" v-if="object.track.album && object.track.album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](object.track.album.cover.medium_square_crop)"> | ||||
|           <img alt="" v-if="object.track.album && object.track.album.cover" v-lazy="$store.getters['instance/absoluteUrl'](object.track.album.cover.urls.medium_square_crop)"> | ||||
|           <img alt="" v-else src="../../../assets/audio/default-cover.png"> | ||||
|           <play-button class="play-overlay" :icon-only="true" :button-classes="['ui', 'circular', 'tiny', 'vibrant', 'icon', 'button']" :track="object.track"></play-button> | ||||
|         </div> | ||||
|  |  | |||
|  | @ -416,12 +416,12 @@ export default { | |||
|       this.settings.errors = [] | ||||
|       let self = this | ||||
|       let payload = this.settingsValues | ||||
|       let url = `users/users/${this.$store.state.auth.username}/` | ||||
|       let url = `users/${this.$store.state.auth.username}/` | ||||
|       return axios.patch(url, payload).then( | ||||
|         response => { | ||||
|           logger.default.info("Updated settings successfully") | ||||
|           self.settings.success = true | ||||
|           return axios.get("users/users/me/").then(response => { | ||||
|           return axios.get("users/me/").then(response => { | ||||
|             self.$store.dispatch("auth/updateProfile", response.data) | ||||
|           }) | ||||
|         }, | ||||
|  | @ -487,7 +487,7 @@ export default { | |||
|       this.avatarErrors = [] | ||||
|       let self = this | ||||
|       axios | ||||
|         .patch(`users/users/${this.$store.state.auth.username}/`, {avatar: uuid}) | ||||
|         .patch(`users/${this.$store.state.auth.username}/`, {avatar: uuid}) | ||||
|         .then( | ||||
|           response => { | ||||
|             this.isLoadingAvatar = false | ||||
|  | @ -538,7 +538,7 @@ export default { | |||
|         confirm: true, | ||||
|         password: this.password, | ||||
|       } | ||||
|       axios.delete(`users/users/me/`, {data: payload}) | ||||
|       axios.delete(`users/me/`, {data: payload}) | ||||
|         .then( | ||||
|           response => { | ||||
|             self.isDeletingAccount = false | ||||
|  |  | |||
|  | @ -87,7 +87,7 @@ export default { | |||
|       this.errors = [] | ||||
|       this.isLoading = true | ||||
|       let self = this | ||||
|       let url = `users/users/${this.$store.state.auth.username}/subsonic-token/` | ||||
|       let url = `users/${this.$store.state.auth.username}/subsonic-token/` | ||||
|       return axios.get(url).then(response => { | ||||
|         self.token = response.data['subsonic_api_token'] | ||||
|         self.isLoading = false | ||||
|  | @ -102,7 +102,7 @@ export default { | |||
|       this.errors = [] | ||||
|       this.isLoading = true | ||||
|       let self = this | ||||
|       let url = `users/users/${this.$store.state.auth.username}/subsonic-token/` | ||||
|       let url = `users/${this.$store.state.auth.username}/subsonic-token/` | ||||
|       return axios.post(url, {}).then(response => { | ||||
|         self.showToken = true | ||||
|         self.token = response.data['subsonic_api_token'] | ||||
|  | @ -119,7 +119,7 @@ export default { | |||
|       this.errors = [] | ||||
|       this.isLoading = true | ||||
|       let self = this | ||||
|       let url = `users/users/${this.$store.state.auth.username}/subsonic-token/` | ||||
|       let url = `users/${this.$store.state.auth.username}/subsonic-token/` | ||||
|       return axios.delete(url).then(response => { | ||||
|         self.isLoading = false | ||||
|         self.token = null | ||||
|  |  | |||
|  | @ -347,7 +347,7 @@ export default { | |||
|     }, | ||||
|     fetchQuota () { | ||||
|       let self = this | ||||
|       axios.get('users/users/me/').then((response) => { | ||||
|       axios.get('users/me/').then((response) => { | ||||
|         self.quotaStatus = response.data.quota_status | ||||
|       }) | ||||
|     }, | ||||
|  | @ -391,8 +391,8 @@ export default { | |||
|             value: c.uuid, | ||||
|             selected: self.channel && self.channel.uuid === c.uuid, | ||||
|           } | ||||
|           if (c.artist.cover && c.artist.cover.small_square_crop) { | ||||
|             let coverUrl = self.$store.getters['instance/absoluteUrl'](c.artist.cover.small_square_crop) | ||||
|           if (c.artist.cover && c.artist.cover.urls.medium_square_crop) { | ||||
|             let coverUrl = self.$store.getters['instance/absoluteUrl'](c.artist.cover.urls.medium_square_crop) | ||||
|             d.image = coverUrl | ||||
|             if (c.artist.content_category === 'podcast') { | ||||
|               d.imageClass = 'ui image' | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| <template> | ||||
|   <img alt="" v-if="actor.icon && actor.icon.original" :src="actor.icon.small_square_crop" class="ui avatar circular image" /> | ||||
|   <img alt="" v-if="actor.icon && actor.icon.urls.original" :src="actor.icon.urls.medium_square_crop" class="ui avatar circular image" /> | ||||
|   <span v-else :style="defaultAvatarStyle" class="ui avatar circular label">{{ actor.preferred_username[0]}}</span> | ||||
| </template> | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,8 +4,8 @@ | |||
|       <img | ||||
|         class="ui tiny circular avatar" | ||||
|         alt="" | ||||
|         v-if="user.avatar && user.avatar.small_square_crop" | ||||
|         v-lazy="$store.getters['instance/absoluteUrl'](user.avatar.small_square_crop)" /> | ||||
|         v-if="user.avatar && user.avatar.urls.medium_square_crop" | ||||
|         v-lazy="$store.getters['instance/absoluteUrl'](user.avatar.urls.medium_square_crop)" /> | ||||
|       <span v-else :style="defaultAvatarStyle" class="ui circular label">{{ user.username[0]}}</span> | ||||
|         | ||||
|     </template> | ||||
|  |  | |||
|  | @ -11,10 +11,10 @@ | |||
|               <div class="ui two column grid" v-if="isSerie"> | ||||
|                 <div class="column"> | ||||
|                   <div class="large two-images"> | ||||
|                     <img class="channel-image" alt="" v-if="object.cover && object.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.square_crop)"> | ||||
|                     <img class="channel-image" alt="" v-else src="../../assets/audio/default-cover.png"> | ||||
|                     <img class="channel-image" alt="" v-if="object.cover && object.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.square_crop)"> | ||||
|                     <img class="channel-image" alt="" v-else src="../../assets/audio/default-cover.png"> | ||||
|                     <img alt="" class="channel-image" v-if="object.cover && object.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.urls.square_crop)"> | ||||
|                     <img alt="" class="channel-image" v-else src="../../assets/audio/default-cover.png"> | ||||
|                     <img alt="" class="channel-image" v-if="object.cover && object.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.urls.square_crop)"> | ||||
|                     <img alt="" class="channel-image" v-else src="../../assets/audio/default-cover.png"> | ||||
|                   </div> | ||||
|                 </div> | ||||
|                 <div class="ui column right aligned"> | ||||
|  | @ -53,8 +53,8 @@ | |||
|               </header> | ||||
|             </div> | ||||
|             <div v-else class="ui center aligned text padded basic segment"> | ||||
|               <img class="channel-image" alt="" v-if="object.cover && object.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.square_crop)"> | ||||
|               <img class="channel-image" alt="" v-else src="../../assets/audio/default-cover.png"> | ||||
|               <img alt="" class="channel-image" v-if="object.cover && object.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.urls.square_crop)"> | ||||
|               <img alt="" class="channel-image" v-else src="../../assets/audio/default-cover.png"> | ||||
|               <div class="ui hidden divider"></div> | ||||
|               <header> | ||||
|                 <h2 class="ui header" :title="object.title"> | ||||
|  |  | |||
|  | @ -235,12 +235,12 @@ export default { | |||
|       ) | ||||
|     }, | ||||
|     cover() { | ||||
|       if (this.object.cover && this.object.cover.original) { | ||||
|       if (this.object.cover && this.object.cover.urls.original) { | ||||
|         return this.object.cover | ||||
|       } | ||||
|       return this.object.albums | ||||
|         .filter(album => { | ||||
|           return album.cover && album.cover.original | ||||
|           return album.cover && album.cover.urls.original | ||||
|         }) | ||||
|         .map(album => { | ||||
|           return album.cover | ||||
|  | @ -253,12 +253,12 @@ export default { | |||
|       }) | ||||
|     }, | ||||
|     headerStyle() { | ||||
|       if (!this.cover || !this.cover.original) { | ||||
|       if (!this.cover || !this.cover.urls.original) { | ||||
|         return "" | ||||
|       } | ||||
|       return ( | ||||
|         "background-image: url(" + | ||||
|         this.$store.getters["instance/absoluteUrl"](this.cover.original) + | ||||
|         this.$store.getters["instance/absoluteUrl"](this.cover.urls.original) + | ||||
|         ")" | ||||
|       ) | ||||
|     }, | ||||
|  |  | |||
|  | @ -274,7 +274,7 @@ export default { | |||
|     fetchQuota () { | ||||
|       let self = this | ||||
|       self.isLoadingQuota = true | ||||
|       axios.get('users/users/me/').then((response) => { | ||||
|       axios.get('users/me/').then((response) => { | ||||
|         self.quotaStatus = response.data.quota_status | ||||
|         self.isLoadingQuota = false | ||||
|       }) | ||||
|  |  | |||
|  | @ -264,12 +264,12 @@ export default { | |||
|       return route.href | ||||
|     }, | ||||
|     headerStyle() { | ||||
|       if (!this.cover || !this.cover.original) { | ||||
|       if (!this.cover || !this.cover.urls.original) { | ||||
|         return "" | ||||
|       } | ||||
|       return ( | ||||
|         "background-image: url(" + | ||||
|         this.$store.getters["instance/absoluteUrl"](this.cover.original) + | ||||
|         this.$store.getters["instance/absoluteUrl"](this.cover.urls.original) + | ||||
|         ")" | ||||
|       ) | ||||
|     }, | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
|     <section class="ui vertical stripe segment"> | ||||
|       <div class="ui stackable grid row container"> | ||||
|         <div class="six wide column"> | ||||
|           <img class="image" alt="" v-if="cover && cover.original" v-lazy="$store.getters['instance/absoluteUrl'](cover.square_crop)"> | ||||
|           <img alt="" class="image" v-if="cover && cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](cover.urls.square_crop)"> | ||||
|           <template v-if="upload"> | ||||
|             <h3 class="ui header"> | ||||
|               <translate key="1" v-if="track.artist.content_category === 'music'" translate-context="Content/*/*">Track Details</translate> | ||||
|  | @ -223,7 +223,7 @@ export default { | |||
|       return this.licenseData | ||||
|     }, | ||||
|     cover () { | ||||
|       if (this.track.cover && this.track.cover.original) { | ||||
|       if (this.track.cover && this.track.cover.urls.original) { | ||||
|         return this.track.cover | ||||
|       } | ||||
|       if (this.track.album && this.track.album.cover) { | ||||
|  |  | |||
|  | @ -64,7 +64,7 @@ | |||
|               <tr v-for="(plt, index) in plts" :key="`${index}-${plt.track.id}`"> | ||||
|                 <td class="left aligned">{{ plt.index + 1}}</td> | ||||
|                 <td class="center aligned"> | ||||
|                   <img alt="" class="ui mini image" v-if="plt.track.album && plt.track.album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](plt.track.album.cover.small_square_crop)"> | ||||
|                   <img alt="" class="ui mini image" v-if="plt.track.album && plt.track.album.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](plt.track.album.cover.urls.medium_square_crop)"> | ||||
|                   <img alt="" class="ui mini image" v-else src="../../assets/audio/default-cover.png"> | ||||
|                 </td> | ||||
|                 <td colspan="4"> | ||||
|  |  | |||
|  | @ -182,7 +182,7 @@ export default { | |||
|     fetchProfile ({commit, dispatch, state}) { | ||||
| 
 | ||||
|       return new Promise((resolve, reject) => { | ||||
|         axios.get('users/users/me/').then((response) => { | ||||
|         axios.get('users/me/').then((response) => { | ||||
|           logger.default.info('Successfully fetched user profile') | ||||
|           dispatch('ui/initSettings', response.data.settings, { root: true }) | ||||
|           dispatch('updateProfile', response.data).then(() => { | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ export default { | |||
|       let playlists = [] | ||||
|       let url = 'playlists/' | ||||
|       while (url != null) { | ||||
|         let response = await axios.get(url, {params: {user: userId}}) | ||||
|         let response = await axios.get(url, {params: {scope: "me"}}) | ||||
|         playlists = [...playlists, ...response.data.results] | ||||
|         url = response.data.next | ||||
| 
 | ||||
|  |  | |||
|  | @ -167,7 +167,7 @@ export default { | |||
|       } | ||||
|       payload[field] = newDisplayDate | ||||
|       let self = this | ||||
|       axios.patch(`users/users/${this.$store.state.auth.username}/`, payload).then((response) => { | ||||
|       axios.patch(`users/${this.$store.state.auth.username}/`, payload).then((response) => { | ||||
|         self.$store.commit('auth/profilePartialUpdate', response.data) | ||||
|       }) | ||||
|     }, | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ | |||
|           <div class="ui column"> | ||||
|             <div class="segment-content"> | ||||
|               <h2 class="ui header"> | ||||
|                 <img alt="" v-if="object.artist.cover && object.artist.cover.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](object.artist.cover.square_crop)"> | ||||
|                 <img alt="" v-if="object.artist.cover && object.artist.cover.urls.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](object.artist.cover.urls.square_crop)"> | ||||
|                 <img alt="" v-else src="../../assets/audio/default-cover.png"> | ||||
|                 <div class="content"> | ||||
|                   {{ object.artist.name | truncate(100) }} | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ | |||
|           <div class="ui column"> | ||||
|             <div class="segment-content"> | ||||
|               <h2 class="ui header"> | ||||
|                 <img alt="" v-if="object.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.square_crop)"> | ||||
|                 <img alt="" v-if="object.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.urls.square_crop)"> | ||||
|                 <img alt="" v-else src="../../../assets/audio/default-cover.png"> | ||||
|                 <div class="content"> | ||||
|                   {{ object.title | truncate(100) }} | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ | |||
|           <div class="ui column"> | ||||
|             <div class="segment-content"> | ||||
|               <h2 class="ui header"> | ||||
|                 <img alt="" v-if="object.cover && object.cover.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.square_crop)"> | ||||
|                 <img alt="" v-if="object.cover && object.cover.urls.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.urls.square_crop)"> | ||||
|                 <img alt="" v-else src="../../../assets/audio/default-cover.png"> | ||||
|                 <div class="content"> | ||||
|                   {{ object.name | truncate(100) }} | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ | |||
|           <div class="ui column"> | ||||
|             <div class="segment-content"> | ||||
|               <h2 class="ui header"> | ||||
|                 <img alt="" v-if="object.cover && object.cover.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.square_crop)"> | ||||
|                 <img alt="" v-if="object.cover && object.cover.urls.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.urls.square_crop)"> | ||||
|                 <img alt="" v-else src="../../../assets/audio/default-cover.png"> | ||||
|                 <div class="content"> | ||||
|                   {{ object.title | truncate(100) }} | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ | |||
|           </div> | ||||
|           <h1 class="ui center aligned icon header"> | ||||
|             <i v-if="!object.icon" class="circular inverted user success icon"></i> | ||||
|             <img alt="" class="ui big circular image" v-else v-lazy="$store.getters['instance/absoluteUrl'](object.icon.square_crop)" /> | ||||
|             <img alt="" class="ui big circular image" v-else v-lazy="$store.getters['instance/absoluteUrl'](object.icon.urls.square_crop)" /> | ||||
|             <div class="ellispsis content"> | ||||
|               <div class="ui very small hidden divider"></div> | ||||
|               <span>{{ displayName }}</span> | ||||
|  | @ -49,7 +49,7 @@ | |||
|               @updated="$emit('updated', $event)" | ||||
|               :content="object.summary" | ||||
|               :field-name="'summary'" | ||||
|               :update-url="`users/users/${$store.state.auth.username}/`" | ||||
|               :update-url="`users/${$store.state.auth.username}/`" | ||||
|               :can-update="$store.state.auth.authenticated && object.full_username === $store.state.auth.fullUsername"></rendered-description> | ||||
|           </div> | ||||
|         </div> | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ | |||
|         @updated="$emit('updated', $event)" | ||||
|         :content="object.summary" | ||||
|         :field-name="'summary'" | ||||
|         :update-url="`users/users/${$store.state.auth.username}/`" | ||||
|         :update-url="`users/${$store.state.auth.username}/`" | ||||
|         :can-update="$store.state.auth.authenticated && object.full_username === $store.state.auth.fullUsername"></rendered-description> | ||||
|       <div class="ui hidden divider"></div> | ||||
|     </div> | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ | |||
|           <div class="seven wide column"> | ||||
|             <div class="ui two column grid"> | ||||
|               <div class="column"> | ||||
|                 <img alt="" class="huge channel-image" v-if="object.artist.cover" :src="$store.getters['instance/absoluteUrl'](object.artist.cover.medium_square_crop)"> | ||||
|                 <img alt="" class="huge channel-image" v-if="object.artist.cover" :src="$store.getters['instance/absoluteUrl'](object.artist.cover.urls.medium_square_crop)"> | ||||
|                 <i v-else class="huge circular inverted users violet icon"></i> | ||||
|               </div> | ||||
|               <div class="ui column right aligned"> | ||||
|  |  | |||
|  | @ -114,7 +114,7 @@ export default { | |||
|     fetch () { | ||||
|       let self = this | ||||
|       self.isLoading = true | ||||
|       axios.get('users/users/me/').then((response) => { | ||||
|       axios.get('users/me/').then((response) => { | ||||
|         self.quotaStatus = response.data.quota_status | ||||
|         self.isLoading = false | ||||
|       }) | ||||
|  |  | |||
|  | @ -146,7 +146,7 @@ describe('store/auth', () => { | |||
|           admin: true | ||||
|         } | ||||
|       } | ||||
|       moxios.stubRequest('users/users/me/', { | ||||
|       moxios.stubRequest('users/me/', { | ||||
|         status: 200, | ||||
|         response: profile | ||||
|       }) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Agate
						Agate