mirror of
https://github.com/fergalmoran/dss.api.git
synced 2025-12-22 09:18:13 +00:00
Feed working
This commit is contained in:
@@ -98,6 +98,17 @@ class LikeSerializer(serializers.ModelSerializer):
|
||||
display_name = serializers.ReadOnlyField(source='get_nice_name')
|
||||
|
||||
|
||||
class FavouriteSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = UserProfile
|
||||
fields = (
|
||||
'display_name',
|
||||
'slug',
|
||||
)
|
||||
|
||||
display_name = serializers.ReadOnlyField(source='get_nice_name')
|
||||
|
||||
|
||||
class GenreSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Genre
|
||||
@@ -162,6 +173,7 @@ class MixSerializer(serializers.ModelSerializer):
|
||||
'plays',
|
||||
'downloads',
|
||||
'is_liked',
|
||||
'is_favourited',
|
||||
|
||||
]
|
||||
|
||||
@@ -174,10 +186,11 @@ class MixSerializer(serializers.ModelSerializer):
|
||||
|
||||
genres = GenreSerializer(many=True, required=False, read_only=True)
|
||||
likes = LikeSerializer(many=True, required=False, read_only=True) # slug_field='slug', many=True, read_only=True)
|
||||
favourites = serializers.SlugRelatedField(slug_field='slug', many=True, read_only=True)
|
||||
favourites = FavouriteSerializer(many=True, required=False, read_only=True) # slug_field='slug', many=True, read_only=True)
|
||||
plays = InlineActivityPlaySerializer(many=True, read_only=True, source='activity_plays')
|
||||
downloads = InlineActivityDownloadSerializer(read_only=True, source='activity_downloads')
|
||||
is_liked = serializers.SerializerMethodField(read_only=True)
|
||||
is_favourited = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
# all nested representations need to be serialized separately here
|
||||
@@ -202,6 +215,25 @@ class MixSerializer(serializers.ModelSerializer):
|
||||
except UserProfile.DoesNotExist:
|
||||
pass
|
||||
|
||||
favourites = self.initial_data['favourites']
|
||||
unfavourited = instance.favourites.exclude(user__userprofile__slug__in=[f['slug'] for f in favourites])
|
||||
for uf in unfavourited:
|
||||
# check that the user removing the like is an instance of the current user
|
||||
# for now, only the current user can like stuff
|
||||
if uf == self.context['request'].user.userprofile:
|
||||
instance.update_favourite(uf, False)
|
||||
|
||||
for favourite in favourites:
|
||||
# check that the user adding the like is an instance of the current user
|
||||
# for now, only the current user can like stuff
|
||||
try:
|
||||
user = UserProfile.objects.get(slug=favourite['slug'])
|
||||
if user is not None and user == self.context['request'].user.userprofile:
|
||||
instance.update_favourite(user, True)
|
||||
|
||||
except UserProfile.DoesNotExist:
|
||||
pass
|
||||
|
||||
genres = self.initial_data['genres']
|
||||
instance.genres.clear()
|
||||
for genre in genres:
|
||||
@@ -224,6 +256,8 @@ class MixSerializer(serializers.ModelSerializer):
|
||||
return super(MixSerializer, self).update(instance, validated_data)
|
||||
except MixUpdateException as ex:
|
||||
raise ex
|
||||
except Exception as ex:
|
||||
raise ex
|
||||
|
||||
def is_valid(self, raise_exception=False):
|
||||
return super(MixSerializer, self).is_valid(raise_exception)
|
||||
|
||||
@@ -123,13 +123,12 @@ INSTALLED_APPS = (
|
||||
'allauth.socialaccount.providers.twitter',
|
||||
|
||||
'pipeline',
|
||||
'dbbackup',
|
||||
'gunicorn',
|
||||
|
||||
'corsheaders',
|
||||
'sorl.thumbnail',
|
||||
'djcelery',
|
||||
'spa',
|
||||
'gunicorn',
|
||||
'spa.signals',
|
||||
'core',
|
||||
'storages',
|
||||
@@ -254,7 +253,9 @@ SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
|
||||
'social.backends.yahoo.YahooOpenId'
|
||||
)
|
||||
|
||||
"""
|
||||
DBBACKUP_STORAGE = 'dbbackup.storage.dropbox_storage'
|
||||
DBBACKUP_TOKENS_FILEPATH = '._dss_tokens'
|
||||
DBBACKUP_DROPBOX_APP_KEY = localsettings.DSS_DB_BACKUP_KEY
|
||||
DBBACKUP_DROPBOX_APP_SECRET = localsettings.DSS_DB_BACKUP_SECRET
|
||||
"""
|
||||
@@ -14,6 +14,7 @@ urlpatterns = patterns(
|
||||
(r'^_embed/', include('spa.embedding.urls')),
|
||||
(r'^__redir/blog/', include('spa.blog.urls')),
|
||||
(r'^__redir/social/', include('spa.social.urls')),
|
||||
(r'^podcast/', include('spa.podcast.urls')),
|
||||
url(r'', include('user_sessions.urls', 'user_sessions')),
|
||||
url(r'^', include('api.urls')),
|
||||
)
|
||||
|
||||
@@ -22,7 +22,6 @@ google-api-python-client
|
||||
django-celery
|
||||
django-scheduler
|
||||
django-recurrence
|
||||
# django-dbbackup
|
||||
|
||||
azure
|
||||
|
||||
|
||||
16
spa/management/commands/add_user_uid.py
Executable file
16
spa/management/commands/add_user_uid.py
Executable file
@@ -0,0 +1,16 @@
|
||||
import uuid
|
||||
|
||||
from django.core.management.base import NoArgsCommand
|
||||
|
||||
from spa.models import UserProfile
|
||||
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
def handle_noargs(self, **options):
|
||||
try:
|
||||
users = UserProfile.objects.exclude(uid__isnull=False)
|
||||
for user in users:
|
||||
user.uid = uuid.uuid4()
|
||||
user.save()
|
||||
except Exception as ex:
|
||||
print("Debug exception: %s" % ex)
|
||||
19
spa/migrations/0026_userprofile_uid.py
Normal file
19
spa/migrations/0026_userprofile_uid.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spa', '0025_socialaccountlink_provider_data'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='userprofile',
|
||||
name='uid',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
]
|
||||
@@ -238,7 +238,7 @@ class Mix(BaseModel):
|
||||
if user.user.is_authenticated():
|
||||
if value:
|
||||
if self.favourites.filter(user=user.user).count() == 0:
|
||||
fav = ActivityFavourite(user=user) # , mix=self)
|
||||
fav = ActivityFavourite(user=user, mix=self)
|
||||
fav.save()
|
||||
self.favourites.add(user)
|
||||
self.save()
|
||||
|
||||
@@ -7,6 +7,7 @@ from django.contrib.auth.models import User
|
||||
from django.core.exceptions import SuspiciousOperation
|
||||
from django.db import models
|
||||
from django.db.models import Count
|
||||
import uuid
|
||||
from django_gravatar.helpers import has_gravatar, get_gravatar_url
|
||||
from sorl import thumbnail
|
||||
|
||||
@@ -41,6 +42,8 @@ class UserProfile(BaseModel):
|
||||
ACTIVITY_SHARE_NETWORK_TWITTER = 2
|
||||
|
||||
user = models.OneToOneField(User, unique=True, related_name='userprofile')
|
||||
uid = models.UUIDField(primary_key=False, editable=False, null=True)
|
||||
|
||||
avatar_type = models.CharField(max_length=15, default='social')
|
||||
avatar_image = models.ImageField(max_length=1024, blank=True, upload_to=avatar_name)
|
||||
display_name = models.CharField(blank=True, max_length=35)
|
||||
|
||||
6
spa/podcast/urls.py
Normal file
6
spa/podcast/urls.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.conf.urls import patterns, url
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
url(r'^(?P<uid>[\w\d_.-]+)/favourites/?$', 'spa.podcast.views.favourites', name='podast_favourites_slug'),
|
||||
)
|
||||
35
spa/podcast/views.py
Normal file
35
spa/podcast/views.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from django.http import Http404
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template import RequestContext
|
||||
|
||||
from spa.models import UserProfile
|
||||
|
||||
|
||||
def favourites(request, uid):
|
||||
try:
|
||||
user = UserProfile.objects.order_by('-id').get(uid=uid)
|
||||
except UserProfile.DoesNotExist:
|
||||
raise Http404("User does not exist")
|
||||
|
||||
fav_list = user.favourites.all()
|
||||
return _render_podcast(request, user, fav_list)
|
||||
|
||||
|
||||
def _render_podcast(request, user, list):
|
||||
context = {
|
||||
'title': 'DSS Favourites',
|
||||
'description': 'All your favourites on Deep South Sounds',
|
||||
'link': 'https://deepsouthsounds.com/',
|
||||
'user': user.first_name,
|
||||
'summary': 'Deep South Sounds is a collective of like minded house heads from Ireland"s Deep South',
|
||||
'last_build_date': list[0].upload_date,
|
||||
'objects': list,
|
||||
}
|
||||
response = render_to_response(
|
||||
'podcast/feed.xml',
|
||||
context=context,
|
||||
context_instance=RequestContext(request),
|
||||
content_type='application/rss+xml'
|
||||
)
|
||||
return response
|
||||
0
spa/templatetags/__init__.py
Normal file
0
spa/templatetags/__init__.py
Normal file
33
spa/templatetags/dss_extras.py
Normal file
33
spa/templatetags/dss_extras.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from django import template
|
||||
import datetime
|
||||
import time
|
||||
from email import utils
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter
|
||||
def get_mix_url(obj):
|
||||
return obj.get_full_url()
|
||||
|
||||
|
||||
@register.filter
|
||||
def get_mix_audio_url(obj):
|
||||
return obj.get_download_url()
|
||||
|
||||
|
||||
@register.filter
|
||||
def seconds_to_hms(seconds):
|
||||
try:
|
||||
m, s = divmod(seconds, 60)
|
||||
h, m = divmod(m, 60)
|
||||
return "%d:%02d:%02d" % (h, m, s)
|
||||
except Exception as ex:
|
||||
return "00:00:09"
|
||||
|
||||
|
||||
@register.filter
|
||||
def date_to_rfc2822(date):
|
||||
nowtuple = date.timetuple()
|
||||
nowtimestamp = time.mktime(nowtuple)
|
||||
return utils.formatdate(nowtimestamp)
|
||||
BIN
static/img/podcast_logo.png
Normal file
BIN
static/img/podcast_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 431 KiB |
52
templates/podcast/feed.xml
Normal file
52
templates/podcast/feed.xml
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
|
||||
<channel>
|
||||
{% load dss_extras %}
|
||||
|
||||
<title>{{ title }}</title>
|
||||
<description>{{ description }}</description>
|
||||
<link>{{ link }}</link>
|
||||
<language>en-ie</language>
|
||||
<copyright>Copyright 2016</copyright>
|
||||
<lastBuildDate>{{ last_build_date|date_to_rfc2822 }}</lastBuildDate>
|
||||
<pubDate>{{ last_build_date|date_to_rfc2822 }}</pubDate>
|
||||
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
|
||||
<webMaster>webmaster@deepsouthsounds.com</webMaster>
|
||||
|
||||
<itunes:author>{{ user }} @ deepsouthsounds</itunes:author>
|
||||
<itunes:subtitle>{{ title }}</itunes:subtitle>
|
||||
<itunes:summary>{{ summary }}</itunes:summary>
|
||||
|
||||
<itunes:owner>
|
||||
<itunes:name>Fergal Moran</itunes:name>
|
||||
<itunes:email>fergal@deepsouthsounds.com</itunes:email>
|
||||
</itunes:owner>
|
||||
|
||||
<itunes:explicit>No</itunes:explicit>
|
||||
|
||||
<itunes:image href="https://dsscdn2.blob.core.windows.net/static/podcast_logo.png"/>
|
||||
|
||||
<itunes:category text="Technology">
|
||||
<itunes:category text="Podcasting"/>
|
||||
</itunes:category>
|
||||
{% for item in objects %}
|
||||
<item>
|
||||
<title>{{ item.title }}</title>
|
||||
<link>{{ item|get_mix_url }}</link>
|
||||
<guid>{{ item|get_mix_url }}</guid>
|
||||
<description>{{ item.description }}</description>
|
||||
<enclosure url="{{ item|get_mix_audio_url }}" length="{{ item.duration }}" type="audio/mpeg"/>
|
||||
<category>Podcasts</category>
|
||||
<pubDate>{{ item.upload_date|date_to_rfc2822 }}</pubDate>
|
||||
<itunes:author>{{ item.user.display_name }}</itunes:author>
|
||||
<itunes:explicit>No</itunes:explicit>
|
||||
<itunes:subtitle>{{ item.description }}</itunes:subtitle>
|
||||
<itunes:summary>{{ item.description }}</itunes:summary>
|
||||
<itunes:duration>{{ item.duration|seconds_to_hms }}</itunes:duration>
|
||||
<itunes:keywords>deep south sounds, deep house, Cork, Fergal Moran, Ed Dunlea, {{ item.title }}, {{ item.user.display_name }}
|
||||
</itunes:keywords>
|
||||
</item>
|
||||
{% endfor %}
|
||||
</channel>
|
||||
|
||||
</rss>
|
||||
57
templates/podcast/full.feed.html
Normal file
57
templates/podcast/full.feed.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
|
||||
<channel>
|
||||
<title>{{ object.title }}</title>
|
||||
<link>{{ object.link }}</link>
|
||||
<description>{{ object.description|striptags }}</description>
|
||||
{% if object.language %}<language>{{ object.language }}</language>{% endif %}
|
||||
<copyright>℗ & © {% now "Y" %} {{ object.organization }}. {{ object.copyright }}.</copyright>
|
||||
<managingEditor>{% for author in object.author.all %}{% if forloop.first %}{% else %}{% if forloop.last %} and {% else %}, {% endif %}{% endif %}{{ author.email }}{% endfor %}</managingEditor>
|
||||
{% if object.author.email or object.webmaster.email %}<webMaster>{% if object.webmaster.email %}{{ object.webmaster.email }}{% else %}{% endif %}</webMaster>{% endif %}
|
||||
<lastBuildDate>{{ object.list.0.date|date:"r" }}</lastBuildDate>
|
||||
{% if object.category_show %}<category{% if object.domain %} domain="{{ object.domain }}"{% endif %}>{{ object.category_show }}</category>{% endif %}
|
||||
<generator>Django Web Framework</generator>
|
||||
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
|
||||
{% if object.ttl %}<ttl>{{ object.ttl }}</ttl>{% endif %}
|
||||
{% if object.image %}<image>
|
||||
<url>{{ object.image.url }}</url>
|
||||
<title>{{ object.title }}</title>
|
||||
<link>{{ object.link }}</link>
|
||||
</image>{% endif %}
|
||||
<itunes:author>{{ object.organization }}</itunes:author>
|
||||
<itunes:owner>
|
||||
<itunes:name>{% for author in object.author.all %}{% if forloop.first %}{% else %}{% if forloop.last %} and {% else %}, {% endif %}{% endif %}{% if author.first_name or author.last_name %}{% if author.first_name and author.last_name %}{{ author.first_name }} {{ author.last_name }}{% endif %}{% if author.first_name and not author.last_name %}{{ author.first_name }}{% endif %}{% if author.last_name and not author.first_name %}{{ author.last_name }}{% endif %}{% else %}{{ author.username }}{% endif %}{% endfor %}</itunes:name>
|
||||
<itunes:email>{% for author in object.author.all %}{{ author.email }}{% if forloop.last %}{% else %}, {% endif %}{% endfor %}</itunes:email>
|
||||
</itunes:owner>
|
||||
{% if object.subtitle %}<itunes:subtitle>{{ object.subtitle }}</itunes:subtitle>{% endif %}
|
||||
<itunes:summary>{% if object.summary %}{{ object.summary|striptags }}{% else %}{{ object.description|striptags }}{% endif %}</itunes:summary>
|
||||
{% if object.image %}<itunes:image href="{{ object.image.url }}" />{% endif %}
|
||||
{% if object.category.all %}{% for category in object.category.all %}{% if category.name %}<itunes:category text="{{ category.parent.name }}">
|
||||
<itunes:category text="{{ category.name }}" />
|
||||
</itunes:category>
|
||||
{% else %}<itunes:category text="{{ category.parent.name }}" />
|
||||
{% endif %}{% endfor %}{% endif %}
|
||||
{% if object.explicit %}<itunes:explicit>{{ object.explicit|lower }}</itunes:explicit>{% endif %}
|
||||
{% if object.block %}<itunes:block>yes</itunes:block>{% endif %}
|
||||
{% if object.redirect %}<itunes:new-feed-url>{{ object.redirect }}</itunes:new-feed-url>{% endif %}
|
||||
|
||||
{% for episode in object.episode_set.published %}<item>
|
||||
<title>{{ episode.title }}</title>
|
||||
<link>{{ episode.enclosure_set.all.0.file.url }}</link>
|
||||
<description>{{ episode.description|striptags }}</description>
|
||||
<author>{% for author in object.author.all %}{{ author.email }}{% if forloop.last %}{% else %}, {% endif %}{% endfor %}</author>
|
||||
{% if episode.category %}<category{% if episode.domain %} url="{{ episode.domain }}"{% endif %}>{{ episode.category }}</category>{% endif %}
|
||||
<enclosure url="{{ episode.enclosure_set.all.0.file.url }}" length="{{ episode.enclosure_set.all.0.file.size }}" type="{{ episode.enclosure_set.all.0.mime }}" />
|
||||
<guid isPermalink="true">{{ episode.enclosure_set.all.0.file.url }}</guid>
|
||||
<pubDate>{{ episode.date|date:"r" }} GMT</pubDate>
|
||||
<itunes:author>{% for author in episode.author.all %}{% if forloop.first %}{% else %}{% if forloop.last %} and {% else %}, {% endif %}{% endif %}{% if author.first_name or author.last_name %}{% if author.first_name and author.last_name %}{{ author.first_name }} {{ author.last_name }}{% endif %}{% if author.first_name and not author.last_name %}{{ author.first_name }}{% endif %}{% if author.last_name and not author.first_name %}{{ author.last_name }}{% endif %}{% else %}{{ author.username }}{% endif %}{% endfor %}</itunes:author>
|
||||
{% if episode.subtitle %}<itunes:subtitle>{{ episode.subtitle }}</itunes:subtitle>{% endif %}
|
||||
<itunes:summary>{% if episode.summary %}{{ episode.summary|striptags }}{% else %}{{ episode.description|striptags }}{% endif %}</itunes:summary>
|
||||
{% if episode.minutes and episode.seconds %}<itunes:duration>{{ episode.minutes }}:{{ episode.seconds }}</itunes:duration>{% endif %}
|
||||
{% if episode.keywords %}<itunes:keywords>{{ episode.keywords }}</itunes:keywords>{% endif %}
|
||||
{% if episode.explicit %}<itunes:explicit>{{ episode.explicit|lower }}</itunes:explicit>{% endif %}
|
||||
{% if episode.block %}<itunes:block>yes</itunes:block>{% endif %}
|
||||
</item>
|
||||
{% endfor %}
|
||||
</channel>
|
||||
</rss>
|
||||
Reference in New Issue
Block a user