From 745f6829dac3ef8056ea4a407f5d81c0a68f270f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Stefan=20K=C3=B6gl?= Date: Sat, 30 Aug 2014 11:41:15 +0200 Subject: [PATCH] [Suggestions] move existing code into own app --- mygpo/settings.py | 1 + mygpo/suggestions/__init__.py | 0 mygpo/suggestions/apps.py | 13 ++++++ mygpo/suggestions/models.py | 3 ++ mygpo/{users => suggestions}/signals.py | 12 +----- mygpo/suggestions/tasks.py | 32 ++++++++++++++ .../templates/suggestions.html | 0 mygpo/suggestions/tests.py | 16 +++++++ mygpo/suggestions/urls.py | 17 ++++++++ mygpo/suggestions/views.py | 49 ++++++++++++++++++++++ mygpo/urls.py | 1 + mygpo/users/signals.py | 12 +----- mygpo/users/tasks.py | 26 ------------ mygpo/web/urls.py | 3 -- mygpo/web/views/__init__.py | 41 ------------------ 15 files changed, 134 insertions(+), 92 deletions(-) create mode 100644 mygpo/suggestions/__init__.py create mode 100644 mygpo/suggestions/apps.py create mode 100644 mygpo/suggestions/models.py copy mygpo/{users => suggestions}/signals.py (52%) create mode 100644 mygpo/suggestions/tasks.py rename mygpo/{web => suggestions}/templates/suggestions.html (100%) create mode 100644 mygpo/suggestions/tests.py create mode 100644 mygpo/suggestions/urls.py create mode 100644 mygpo/suggestions/views.py diff --git a/mygpo/settings.py b/mygpo/settings.py index 74a8cca5..e9c10de3 100644 --- a/mygpo/settings.py +++ b/mygpo/settings.py @@ -142,6 +142,7 @@ INSTALLED_APPS = ( 'mygpo.favorites', 'mygpo.data', 'mygpo.userfeeds', + 'mygpo.suggestions', 'mygpo.directory', 'mygpo.maintenance', 'mygpo.share', diff --git a/mygpo/suggestions/__init__.py b/mygpo/suggestions/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mygpo/suggestions/apps.py b/mygpo/suggestions/apps.py new file mode 100644 index 00000000..822e6051 --- /dev/null +++ b/mygpo/suggestions/apps.py @@ -0,0 +1,13 @@ +from django.apps import AppConfig +from django.db.models.signals import post_save + +from mygpo.subscriptions.signals import subscription_changed +from mygpo.suggestions.signals import update_suggestions_on_subscription + + +class UsersConfig(AppConfig): + name = 'mygpo.suggestions' + verbose_name = "Suggestions" + + def ready(self): + subscription_changed.connect(update_suggestions_on_subscription) diff --git a/mygpo/suggestions/models.py b/mygpo/suggestions/models.py new file mode 100644 index 00000000..71a83623 --- /dev/null +++ b/mygpo/suggestions/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/mygpo/users/signals.py b/mygpo/suggestions/signals.py similarity index 52% copy from mygpo/users/signals.py copy to mygpo/suggestions/signals.py index 490fc8f6..c0d51fcb 100644 --- a/mygpo/users/signals.py +++ b/mygpo/suggestions/signals.py @@ -1,15 +1,5 @@ from mygpo.subscriptions.signals import subscription_changed -from mygpo.users.tasks import sync_user, update_suggestions - - -def sync_user_on_subscription(sender, **kwargs): - """ synchronizes the user after one of his subscriptions has changed """ - user = kwargs['user'] - sync_user.delay(user) - - -subscription_changed.connect(sync_user_on_subscription, - dispatch_uid='sync_user_on_subscription') +from mygpo.users.tasks import update_suggestions def update_suggestions_on_subscription(sender, **kwargs): diff --git a/mygpo/suggestions/tasks.py b/mygpo/suggestions/tasks.py new file mode 100644 index 00000000..e5a4caf3 --- /dev/null +++ b/mygpo/suggestions/tasks.py @@ -0,0 +1,32 @@ +from itertools import chain +from operator import itemgetter +from collections import Counter + +from mygpo.celery import celery +from mygpo.db.couchdb.user import (suggestions_for_user, + update_suggestions as update) +from mygpo.subscriptions import get_subscribed_podcasts + +from celery.utils.log import get_task_logger +logger = get_task_logger(__name__) + + +@celery.task(max_retries=5, default_retry_delay=60) +def update_suggestions(user, max_suggestions=15): + """ updates the suggestions of a user """ + + # get suggestions object + suggestion = suggestions_for_user(user) + + # calculate possible suggestions + subscribed_podcasts = get_subscribed_podcasts() + related = chain.from_iterable([p.related_podcasts for p in subscribed_podcasts]) + + # filter out blacklisted podcasts + related = filter(lambda pid: not pid in suggestion.blacklist, related) + + # get most relevant + counter = Counter(related) + get_podcast_id = itemgetter(0) + suggested = map(get_podcast_id, counter.most_common(max_suggestions)) + update(suggestion, suggested) diff --git a/mygpo/web/templates/suggestions.html b/mygpo/suggestions/templates/suggestions.html similarity index 100% rename from mygpo/web/templates/suggestions.html rename to mygpo/suggestions/templates/suggestions.html diff --git a/mygpo/suggestions/tests.py b/mygpo/suggestions/tests.py new file mode 100644 index 00000000..501deb77 --- /dev/null +++ b/mygpo/suggestions/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.assertEqual(1 + 1, 2) diff --git a/mygpo/suggestions/urls.py b/mygpo/suggestions/urls.py new file mode 100644 index 00000000..0112767c --- /dev/null +++ b/mygpo/suggestions/urls.py @@ -0,0 +1,17 @@ +from django.conf.urls import url + +from . import views + +urlpatterns = [ + url(r'^$', + views.suggestions, + name='suggestions'), + + url(r'^rate$', + views.rate_suggestions, + name='suggestions-rate'), + + url(r'^blacklist/(?P[\w-]+)$', + views.blacklist, + name='suggestions-blacklist-slug'), +] diff --git a/mygpo/suggestions/views.py b/mygpo/suggestions/views.py new file mode 100644 index 00000000..d9117418 --- /dev/null +++ b/mygpo/suggestions/views.py @@ -0,0 +1,49 @@ +from django.core.urlresolvers import reverse +from django.http import HttpResponseRedirect +from django.contrib import messages +from django.utils.translation import ugettext as _ +from django.contrib.auth.decorators import login_required +from django.shortcuts import render +from django.contrib.sites.models import RequestSite +from django.views.decorators.vary import vary_on_cookie +from django.views.decorators.cache import never_cache, cache_control + +from mygpo.suggestions.tasks import update_suggestions +from mygpo.db.couchdb.user import (suggestions_for_user, + blacklist_suggested_podcast) + + +@never_cache +@login_required +def blacklist(request, blacklisted_podcast): + user = request.user + suggestion = suggestions_for_user(user) + blacklist_suggested_podcast(suggestion, blacklisted_podcast.get_id()) + update_suggestions.delay(user) + return HttpResponseRedirect(reverse('suggestions')) + + +@never_cache +@login_required +def rate_suggestions(request): + rating_val = int(request.GET.get('rate', None)) + + suggestion = suggestions_for_user(request.user) + suggestion.rate(rating_val, request.user.profile.uuid.hex) + suggestion.save() + + messages.success(request, _('Thanks for rating!')) + + return HttpResponseRedirect(reverse('suggestions')) + +@vary_on_cookie +@cache_control(private=True) +@login_required +def suggestions(request): + suggestion_obj = suggestions_for_user(request.user) + suggestions = suggestion_obj.get_podcasts() + current_site = RequestSite(request) + return render(request, 'suggestions.html', { + 'entries': suggestions, + 'url': current_site + }) diff --git a/mygpo/urls.py b/mygpo/urls.py index f5238d6d..f79f8477 100644 --- a/mygpo/urls.py +++ b/mygpo/urls.py @@ -48,6 +48,7 @@ urlpatterns += patterns('', (r'^', include('mygpo.history.urls')), (r'^', include('mygpo.subscriptions.urls')), (r'^', include('mygpo.users.urls')), + (r'^suggestions/', include('mygpo.suggestions.urls')), (r'^publisher/', include('mygpo.publisher.urls')), (r'^administration/', include('mygpo.administration.urls')), (r'^pubsub/', include('mygpo.pubsub.urls')), diff --git a/mygpo/users/signals.py b/mygpo/users/signals.py index 490fc8f6..84d03493 100644 --- a/mygpo/users/signals.py +++ b/mygpo/users/signals.py @@ -1,5 +1,5 @@ from mygpo.subscriptions.signals import subscription_changed -from mygpo.users.tasks import sync_user, update_suggestions +from mygpo.users.tasks import sync_user def sync_user_on_subscription(sender, **kwargs): @@ -10,13 +10,3 @@ def sync_user_on_subscription(sender, **kwargs): subscription_changed.connect(sync_user_on_subscription, dispatch_uid='sync_user_on_subscription') - - -def update_suggestions_on_subscription(sender, **kwargs): - """ update a user's suggestions after one of his subscriptions change """ - user = kwargs['user'] - update_suggestions.delay(user) - - -subscription_changed.connect(update_suggestions_on_subscription, - dispatch_uid='update_suggestions_on_subscription') diff --git a/mygpo/users/tasks.py b/mygpo/users/tasks.py index b379a0f6..3b22031f 100644 --- a/mygpo/users/tasks.py +++ b/mygpo/users/tasks.py @@ -1,7 +1,4 @@ from datetime import datetime, timedelta -from itertools import chain -from operator import itemgetter -from collections import Counter from celery.decorators import periodic_task @@ -9,8 +6,6 @@ from django.contrib.auth import get_user_model from django.conf import settings from mygpo.celery import celery -from mygpo.db.couchdb.user import suggestions_for_user, update_suggestions -from mygpo.subscriptions import get_subscribed_podcasts from celery.utils.log import get_task_logger logger = get_task_logger(__name__) @@ -36,27 +31,6 @@ def sync_user(user): raise sync_user.retry() -@celery.task(max_retries=5, default_retry_delay=60) -def update_suggestions(user, max_suggestions=15): - """ updates the suggestions of a user """ - - # get suggestions object - suggestion = suggestions_for_user(user) - - # calculate possible suggestions - subscribed_podcasts = get_subscribed_podcasts() - related = chain.from_iterable([p.related_podcasts for p in subscribed_podcasts]) - - # filter out blacklisted podcasts - related = filter(lambda pid: not pid in suggestion.blacklist, related) - - # get most relevant - counter = Counter(related) - get_podcast_id = itemgetter(0) - suggested = map(get_podcast_id, counter.most_common(max_suggestions)) - update_suggestions(suggestion, suggested) - - @periodic_task(run_every=timedelta(hours=1)) def remove_unactivated_users(): """ Remove users that have not been activated """ diff --git a/mygpo/web/urls.py b/mygpo/web/urls.py index d0a48816..71f50612 100644 --- a/mygpo/web/urls.py +++ b/mygpo/web/urls.py @@ -8,9 +8,6 @@ from mygpo.web.logo import CoverArt urlpatterns = patterns('mygpo.web.views', url(r'^$', 'home', name='home'), url(r'^logo/(?P\d+)/(?P.{3})/(?P[^/]*)$', CoverArt.as_view(), name='logo'), - url(r'^suggestions/$', 'suggestions', name='suggestions'), - url(r'^suggestions/rate$', 'rate_suggestions', name='suggestions-rate'), - url(r'^suggestions/blacklist/(?P[\w-]+)$', 'blacklist', name='suggestions-blacklist-slug'), url(r'^tags/', 'mytags', name='tags'), url(r'^online-help', diff --git a/mygpo/web/views/__init__.py b/mygpo/web/views/__init__.py index ccad9e2d..bddeec47 100644 --- a/mygpo/web/views/__init__.py +++ b/mygpo/web/views/__init__.py @@ -33,7 +33,6 @@ from django.views.decorators.cache import never_cache, cache_control from mygpo.decorators import repeat_on_conflict from mygpo.podcasts.models import Podcast, Episode, Tag from mygpo.users.models import HistoryEntry, Client -from mygpo.users.tasks import update_suggestions from mygpo.subscriptions import get_subscribed_podcasts from mygpo.web.utils import process_lang_params from mygpo.utils import parse_range @@ -41,8 +40,6 @@ from mygpo.utils import parse_range from mygpo.users.settings import FLATTR_AUTO, FLATTR_TOKEN from mygpo.publisher.models import PublishedPodcast from mygpo.db.couchdb.episode_state import favorite_episode_ids_for_user -from mygpo.db.couchdb.user import (suggestions_for_user, - blacklist_suggested_podcast) from mygpo.db.couchdb.directory import tags_for_user from mygpo.db.couchdb.podcastlist import podcastlists_for_user @@ -146,44 +143,6 @@ def dashboard(request, episode_count=10): }) -@never_cache -@login_required -#@slug_id_decorator -def blacklist(request, blacklisted_podcast): - user = request.user - suggestion = suggestions_for_user(user) - blacklist_suggested_podcast(suggestion, blacklisted_podcast.get_id()) - update_suggestions.delay(user) - return HttpResponseRedirect(reverse('suggestions')) - - -@never_cache -@login_required -def rate_suggestions(request): - rating_val = int(request.GET.get('rate', None)) - - suggestion = suggestions_for_user(request.user) - suggestion.rate(rating_val, request.user.profile.uuid.hex) - suggestion.save() - - messages.success(request, _('Thanks for rating!')) - - return HttpResponseRedirect(reverse('suggestions')) - - -@vary_on_cookie -@cache_control(private=True) -@login_required -def suggestions(request): - suggestion_obj = suggestions_for_user(request.user) - suggestions = suggestion_obj.get_podcasts() - current_site = RequestSite(request) - return render(request, 'suggestions.html', { - 'entries': suggestions, - 'url': current_site - }) - - @vary_on_cookie @cache_control(private=True) @login_required -- 2.11.4.GIT