[Models] update migration files for user models
[mygpo.git] / mygpo / core / slugs.py
blob29107ce28568b410da517bbe8893b33dbb696d93
1 from collections import defaultdict
3 from itertools import count
5 from couchdbkit.ext.django.schema import *
7 from django.utils.text import slugify
9 from mygpo.podcasts.models import Slug, Episode
10 from mygpo.decorators import repeat_on_conflict
11 from mygpo.utils import partition
14 # TODO: move to feed-downloader?
15 def assign_missing_episode_slugs(podcast):
16 common_title = podcast.get_common_episode_title()
18 episodes = Episode.objects.filter(podcast=podcast, slugs__isnull=True)
20 for episode in episodes:
21 slug = EpisodeSlug(episode, common_title).get_slug()
22 if slug:
23 episode.set_slug(slug)
26 class SlugGenerator(object):
27 """ Generates a unique slug for an object """
30 def __init__(self, obj, override_existing=False):
31 if obj.slug and not override_existing:
32 raise ValueError('%(obj)s already has slug %(slug)s' % \
33 dict(obj=obj, slug=obj.slug))
35 self.base_slug = self._get_base_slug(obj)
38 @staticmethod
39 def _get_base_slug(obj):
40 if not obj.title:
41 return None
42 base_slug = slugify(obj.title)
43 return base_slug
46 @staticmethod
47 def _get_existing_slugs():
48 return []
51 def get_slug(self):
52 """ Gets existing slugs and appends numbers until slug is unique """
53 if not self.base_slug:
54 return None
56 existing_slugs = self._get_existing_slugs()
58 if not self.base_slug in existing_slugs:
59 return str(self.base_slug)
61 for n in count(1):
62 tmp_slug = '%s-%d' % (self.base_slug, n)
63 if not tmp_slug in existing_slugs:
64 # slugify returns SafeUnicode, we need a plain string
65 return str(tmp_slug)
69 class PodcastGroupSlug(SlugGenerator):
70 """ Generates slugs for Podcast Groups """
72 def _get_existing_slugs(self):
73 query = Slug.objects.filter(scope__isnull=True,
74 slug__startswith=self.base_slug)
75 return [s['slug'] for s in query]
79 class PodcastSlug(PodcastGroupSlug):
80 """ Generates slugs for Podcasts """
82 @staticmethod
83 def _get_base_slug(podcast):
84 base_slug = SlugGenerator._get_base_slug(podcast)
86 if not base_slug:
87 return None
89 # append group_member_name to slug
90 if podcast.group_member_name:
91 member_slug = slugify(podcast.group_member_name)
92 if member_slug and not member_slug in base_slug:
93 base_slug = '%s-%s' % (base_slug, member_slug)
95 return base_slug
99 class EpisodeSlug(SlugGenerator):
100 """ Generates slugs for Episodes """
102 def __init__(self, episode, common_title, override_existing=False):
103 self.common_title = common_title
104 super(EpisodeSlug, self).__init__(episode, override_existing)
105 self.podcast_id = episode.podcast
108 def _get_base_slug(self, obj):
110 number = obj.get_episode_number(self.common_title)
111 if number:
112 return str(number)
114 short_title = obj.get_short_title(self.common_title)
115 if short_title:
116 return slugify(short_title)
118 if obj.title:
119 return slugify(obj.title)
121 return None
124 def _get_existing_slugs(self):
125 """ Episode slugs have to be unique within the Podcast """
126 query = Slug.objects.filter(scope=self.podcast_id,
127 slug__startswith=self.base_slug)
128 return [s['slug'] for s in query]
131 class SlugMixin(DocumentSchema):
132 slug = StringProperty()
133 merged_slugs = StringListProperty()
135 def set_slug(self, slug):
136 """ Set the main slug of the object """
138 if self.slug:
139 self.merged_slugs.append(self.slug)
141 self.merged_slugs = list(set(self.merged_slugs) - set([slug]))
143 self.slug = slug
146 def remove_slug(self, slug):
147 """ Removes the slug from the object """
149 # remove main slug
150 if self.slug == slug:
151 self.slug = None
153 # remove from merged slugs
154 self.merged_slugs = list(set(self.merged_slugs) - set([slug]))