From 1d97a1ac6fc0bab36dbd550078db3e05720bf4bb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Stefan=20K=C3=B6gl?= Date: Wed, 1 Oct 2014 18:06:56 +0200 Subject: [PATCH] [Migration] remove CouchDB-based Categories --- .../_design/categories/validate_doc_update.js | 63 ---------- .../_design/categories/views/by_tags/map.js | 12 -- .../_design/categories/views/by_update/map.js | 11 -- doc/dev/couchdb-docs.rst | 15 --- doc/dev/couchdb-views.rst | 21 ---- mygpo/core/proxy.py | 52 -------- mygpo/directory/models.py | 131 +++++---------------- mygpo/directory/tags.py | 1 - mygpo/directory/views.py | 1 - mygpo/podcastlists/views.py | 1 - mygpo/publisher/views.py | 1 - mygpo/settings.py | 7 -- mygpo/web/utils.py | 15 --- mygpo/web/views/episode.py | 1 - mygpo/web/views/podcast.py | 1 - 15 files changed, 28 insertions(+), 305 deletions(-) delete mode 100644 couchdb/categories/_design/categories/validate_doc_update.js delete mode 100644 couchdb/categories/_design/categories/views/by_tags/map.js delete mode 100644 couchdb/categories/_design/categories/views/by_update/map.js delete mode 100644 mygpo/core/proxy.py rewrite mygpo/directory/models.py (71%) diff --git a/couchdb/categories/_design/categories/validate_doc_update.js b/couchdb/categories/_design/categories/validate_doc_update.js deleted file mode 100644 index 124ca90e..00000000 --- a/couchdb/categories/_design/categories/validate_doc_update.js +++ /dev/null @@ -1,63 +0,0 @@ -function(newDoc, oldDoc, userCtx) -{ - String.prototype.trim = function() - { - return this.replace(/^\s+|\s+$/g,""); - } - - function require(field, message) - { - message = message || "Document must have a " + field; - if (newDoc[field] == void 0 || newDoc[field] == null) - { - throw({forbidden: message}); - } - } - - function check(cond, message) - { - message = message || "Condition check failed"; - if(!cond) - { - throw({forbidden: message}); - } - } - - function checkTrimmed(field) - { - if (newDoc[field] != newDoc[field].trim()) - { - throw({forbidden: field + " must be trimmed"}); - } - } - - function checkUnique(arr, field) - { - for(n in arr) - { - function f(x) {return x==arr[n];}; - if(arr.filter(f).length > 1) - { - throw({forbidden: field + " must be unique"}); - } - } - } - - - if(newDoc.doc_type == "Category") - { - require("label"); - check(newDoc.label != "", "label must not be empty"); - checkTrimmed("label"); - - require("updated"); - - if (newDoc.spellings) - { - check(newDoc.spellings.indexOf(newDoc.label) < 0, - "The label should not be contained in the alternative spellings"); - checkUnique(newDoc.spellings, "spellings"); - } - } -} - diff --git a/couchdb/categories/_design/categories/views/by_tags/map.js b/couchdb/categories/_design/categories/views/by_tags/map.js deleted file mode 100644 index 24756bbb..00000000 --- a/couchdb/categories/_design/categories/views/by_tags/map.js +++ /dev/null @@ -1,12 +0,0 @@ -function(doc) -{ - if (doc.doc_type == "Category") - { - emit(doc.label, null); - for(i in doc.spellings) - { - emit(doc.spellings[i], null); - } - } - -} diff --git a/couchdb/categories/_design/categories/views/by_update/map.js b/couchdb/categories/_design/categories/views/by_update/map.js deleted file mode 100644 index 3f143c44..00000000 --- a/couchdb/categories/_design/categories/views/by_update/map.js +++ /dev/null @@ -1,11 +0,0 @@ -function (doc) -{ - if (doc.doc_type == "Category") - { - if(doc.updated && (doc.podcasts.length > 10)) - { - emit(doc.updated, [doc.label, doc.podcasts.length]); - } - } -} - diff --git a/doc/dev/couchdb-docs.rst b/doc/dev/couchdb-docs.rst index 32374381..58aa57b8 100644 --- a/doc/dev/couchdb-docs.rst +++ b/doc/dev/couchdb-docs.rst @@ -244,18 +244,3 @@ Example Document :: start: "2010-09-01", end: "2010-09-15" } - - -Category --------- - -Represents a category within the Podcast Directory. - -Example Document :: - - { - label: "Technology", - spellings: ["technology", "tech"], - weight: 1200, - updated: "2010-09-28T08:38:03Z", - } diff --git a/doc/dev/couchdb-views.rst b/doc/dev/couchdb-views.rst index 177e1f8d..423af017 100644 --- a/doc/dev/couchdb-views.rst +++ b/doc/dev/couchdb-views.rst @@ -168,24 +168,3 @@ Doc-Types: PodcastUserState * `usertags/by_podcast `_ * `usertags/by_user `_ * `usertags/podcasts `_ - - - - - -Categories ----------- - -This group of views is available on the categories database, called -``mygpo_categories`` by default. - - -Categories -^^^^^^^^^^ - -Doc-Types: Category - -**Views** - -* `categories/by_tags `_ -* `categories/by_update `_ diff --git a/mygpo/core/proxy.py b/mygpo/core/proxy.py deleted file mode 100644 index 6e77ca07..00000000 --- a/mygpo/core/proxy.py +++ /dev/null @@ -1,52 +0,0 @@ -from abc import ABCMeta - -from couchdbkit.ext.django.schema import DocumentMeta - - - -class DocumentABCMeta(ABCMeta, DocumentMeta): - """ Meta class must be subclass of all parents' meta classes """ - pass - - - -def proxy_object(obj, **kwargs): - """ Proxies an object to make it arbitrarily modifiable - - It is not possible to add arbitrary values to an couchdbkit Document, - because all values have to fit the schema and have to be JSON serializable - """ - - class ProxyObject(object): - """ Proxy for obj that can have properties of arbitrary type """ - - # ensure that proxied objects can be proxied again - __metaclass__ = DocumentABCMeta - - def __init__(self, obj, **kwargs): - self.obj = obj - - for key, val in kwargs.items(): - setattr(self, key, val) - - - def __getattr__(self, attr): - return getattr(self.obj, attr) - - - def __eq__(self, other): - # if "other" is of the same type as proxied obj, compare directly - if isinstance(other, ProxyObject): - return self.obj == other.obj - - else: - return self.obj == other - - def __hash__(self): - return hash(self.obj) - - - cls = obj.__class__ - cls.register(ProxyObject) - - return ProxyObject(obj, **kwargs) diff --git a/mygpo/directory/models.py b/mygpo/directory/models.py dissimilarity index 71% index 0443f5af..510144ba 100644 --- a/mygpo/directory/models.py +++ b/mygpo/directory/models.py @@ -1,103 +1,28 @@ -from __future__ import unicode_literals - -from django.db import models -from django.core.cache import cache - -from couchdbkit.ext.django.schema import * - -from mygpo.podcasts.models import Podcast -from mygpo.utils import iterate_together -from mygpo.core.models import UpdateInfoModel, OrderedModel -from mygpo.core.proxy import DocumentABCMeta - - -class Category(Document): - - __metaclass__ = DocumentABCMeta - - label = StringProperty(required=True) - updated = DateTimeProperty(required=True) - spellings = StringListProperty() - podcasts = ListProperty() - - - def merge_podcasts(self, podcasts): - """ - Merges some entries into the current category. - """ - - key = lambda e: e.podcast - - podcasts = sorted(podcasts, key=key) - self.podcasts = sorted(self.podcasts, key=key) - - new_entries = [] - - for e1, e2 in iterate_together([self.podcasts, podcasts], key): - if e1 is None: - new_entries.append(e2) - - elif e2 is None: - new_entries.append(e1) - - else: - new_entries.append( max(e1, e2) ) - - self.podcasts = new_entries - - - # called from within a template where we can't pass parameters - def get_podcasts_more(self, start=0, end=40): - return self.get_podcasts(start, end) - - - def get_podcasts(self, start=0, end=10): - cache_id = 'category-%s-%d-%d' % (self._id, start, end) - - podcasts = cache.get(cache_id) - if podcasts: - return podcasts - - ids = self.podcasts[start:end] - - # TODO: this should not be needed anymore after migration - if ids and not isinstance(ids[0], unicode): - return [] - - podcasts = Podcast.objects.filter(id__in=ids) - cache.set(cache_id, podcasts) - - return podcasts - - - def get_weight(self): - return getattr(self, '_weight', len(self.podcasts)) - - - def get_tags(self): - return self.spellings + [self.label] - - def __repr__(self): - return '%s (+%d variants)' % (self.label, len(self.spellings)) - - -class ExamplePodcastsManager(models.Manager): - """ Manager fo the ExamplePodcast model """ - - def get_podcasts(self): - """ The example podcasts """ - return Podcast.objects.filter(examplepodcast__isnull=False)\ - .order_by('examplepodcast__order') - - -class ExamplePodcast(UpdateInfoModel, OrderedModel): - """ Example podcasts returned by the API """ - - podcast = models.ForeignKey(Podcast) - - objects = ExamplePodcastsManager() - - class Meta(OrderedModel.Meta): - unique_together = [ - ('order', ) - ] +from __future__ import unicode_literals + +from django.db import models + +from mygpo.podcasts.models import Podcast +from mygpo.core.models import UpdateInfoModel, OrderedModel + + +class ExamplePodcastsManager(models.Manager): + """ Manager fo the ExamplePodcast model """ + + def get_podcasts(self): + """ The example podcasts """ + return Podcast.objects.filter(examplepodcast__isnull=False)\ + .order_by('examplepodcast__order') + + +class ExamplePodcast(UpdateInfoModel, OrderedModel): + """ Example podcasts returned by the API """ + + podcast = models.ForeignKey(Podcast) + + objects = ExamplePodcastsManager() + + class Meta(OrderedModel.Meta): + unique_together = [ + ('order', ) + ] diff --git a/mygpo/directory/tags.py b/mygpo/directory/tags.py index ca074f75..7bfe2d2d 100644 --- a/mygpo/directory/tags.py +++ b/mygpo/directory/tags.py @@ -7,7 +7,6 @@ from itertools import chain from django.utils.text import slugify from mygpo.decorators import query_if_required, repeat_on_conflict -from mygpo.core.proxy import proxy_object from mygpo.categories.models import Category, CategoryEntry diff --git a/mygpo/directory/views.py b/mygpo/directory/views.py index 2edbba90..8cf02f57 100644 --- a/mygpo/directory/views.py +++ b/mygpo/directory/views.py @@ -23,7 +23,6 @@ from django.contrib.auth import get_user_model from feedservice.parse.models import ParserException from feedservice.parse import FetchFeedException -from mygpo.core.proxy import proxy_object from mygpo.podcasts.models import Podcast, Episode from mygpo.directory.search import search_podcasts from mygpo.web.utils import process_lang_params, get_language_names, \ diff --git a/mygpo/podcastlists/views.py b/mygpo/podcastlists/views.py index 30f2b129..283147e1 100644 --- a/mygpo/podcastlists/views.py +++ b/mygpo/podcastlists/views.py @@ -16,7 +16,6 @@ from django.views.generic.base import View from mygpo.podcasts.models import Podcast, PodcastGroup from mygpo.podcastlists.models import PodcastList -from mygpo.core.proxy import proxy_object from mygpo.api.simple import format_podcast_list from mygpo.votes.models import Vote from mygpo.directory.views import search as directory_search diff --git a/mygpo/publisher/views.py b/mygpo/publisher/views.py index ffa90ecc..b20f7e5a 100644 --- a/mygpo/publisher/views.py +++ b/mygpo/publisher/views.py @@ -15,7 +15,6 @@ from django.contrib.contenttypes.models import ContentType from django.shortcuts import get_object_or_404 from mygpo.podcasts.models import PodcastGroup, Podcast, Episode -from mygpo.core.proxy import proxy_object from mygpo.publisher.auth import require_publisher, is_publisher from mygpo.publisher.forms import SearchPodcastForm from mygpo.publisher.utils import listener_data, episode_listener_data, \ diff --git a/mygpo/settings.py b/mygpo/settings.py index 9a38ee61..238c4344 100644 --- a/mygpo/settings.py +++ b/mygpo/settings.py @@ -38,15 +38,9 @@ DATABASES = { } COUCHDB_DATABASES = { - 'mygpo.directory': - {'URL': 'http://127.0.0.1:5984/mygpo_categories'}, - 'mygpo.users': {'URL': 'http://127.0.0.1:5984/mygpo_users'}, - 'mygpo.categories': - {'URL': 'http://127.0.0.1:5984/mygpo_categories'}, - 'mygpo.userdata': {'URL': 'http://127.0.0.1:5984/mygpo_userdata'}, } @@ -57,7 +51,6 @@ COUCHDB_DATABASES = { # COUCHDB_DATABASES is likely to be overwritten in settings_prod.py while # COUCHDB_DDOC_MAPPING is most probably not overwritten. COUCHDB_DDOC_MAPPING = { - 'categories': 'categories', 'userdata': 'userdata', 'users': 'users', } diff --git a/mygpo/web/utils.py b/mygpo/web/utils.py index caad7ed7..9d0f1fa7 100644 --- a/mygpo/web/utils.py +++ b/mygpo/web/utils.py @@ -13,7 +13,6 @@ from django.http import Http404 from babel import Locale, UnknownLocaleError from mygpo.podcasts.models import Podcast -from mygpo.core.proxy import proxy_object def get_accepted_lang(request): @@ -196,20 +195,6 @@ def get_episode_link_target(episode, podcast, view_name='episode', return strip_tags(reverse(view_name, args=args + add_args)) -def fetch_episode_data(episodes, podcasts={}): - - if not podcasts: - podcasts = [episode.podcast for episode in episodes] - podcasts = {podcast.id: podcast for podcast in podcasts} - - def set_podcast(episode): - episode = proxy_object(episode) - episode.podcast = podcasts.get(episode.podcast, None) - return episode - - return map(set_podcast, episodes) - - # doesn't include the '@' because it's not stored as part of a twitter handle TWITTER_CHARS = string.ascii_letters + string.digits + '_' diff --git a/mygpo/web/views/episode.py b/mygpo/web/views/episode.py index f03b7414..91a35d74 100644 --- a/mygpo/web/views/episode.py +++ b/mygpo/web/views/episode.py @@ -32,7 +32,6 @@ from django.utils.translation import ugettext as _ from mygpo.podcasts.models import Podcast, Episode from mygpo.api.constants import EPISODE_ACTION_TYPES -from mygpo.core.proxy import proxy_object from mygpo.core.tasks import flattr_thing from mygpo.users.models import Chapter, HistoryEntry, EpisodeAction from mygpo.utils import parse_time, get_timestamp diff --git a/mygpo/web/views/podcast.py b/mygpo/web/views/podcast.py index 4ee37070..1e9f88ca 100644 --- a/mygpo/web/views/podcast.py +++ b/mygpo/web/views/podcast.py @@ -24,7 +24,6 @@ from mygpo.subscriptions import ( get_subscribe_targets ) from mygpo.history.models import HistoryEntry -from mygpo.core.proxy import proxy_object from mygpo.core.tasks import flattr_thing from mygpo.utils import normalize_feed_url from mygpo.users.settings import PUBLIC_SUB_PODCAST, FLATTR_TOKEN -- 2.11.4.GIT