1 from datetime
import datetime
2 from couchdbkit
import Server
, Document
4 from mygpo
.core
.models
import Podcast
, PodcastGroup
, Episode
, SubscriberData
5 from mygpo
.users
.models
import Rating
, EpisodeAction
, User
, Device
, SubscriptionAction
6 from mygpo
.log
import log
7 from mygpo
import utils
8 from mygpo
.decorators
import repeat_on_conflict
11 This module contains methods for converting objects from the old
12 ORM-based backend to the CouchDB-based backend
16 def save_podcast_signal(sender
, instance
=False, **kwargs
):
18 Signal-handler for creating/updating a CouchDB-based podcast when
19 an ORM-based podcast has been saved
25 newp
= Podcast
.for_oldid(instance
.id)
27 update_podcast(oldp
=instance
, newp
=newp
)
29 create_podcast(instance
)
32 log('error while updating CouchDB-Podcast: %s' % repr(e
))
35 def delete_podcast_signal(sender
, instance
=False, **kwargs
):
37 Signal-handler for deleting a CouchDB-based podcast when an ORM-based
44 newp
= Podcast
.for_oldid(instance
.id)
49 log('error while deleting CouchDB-Podcast: %s' % repr(e
))
52 def save_episode_signal(sender
, instance
=False, **kwargs
):
54 Signal-handler for creating/updating a CouchDB-based episode when
55 an ORM-based episode has been saved
61 newe
= Episode
.for_oldid(instance
.id)
62 newp
= Podcast
.for_id(newe
.podcast
)
65 update_episode(instance
, newe
, newp
)
67 create_episode(instance
)
70 log('error while updating CouchDB Episode: %s' % repr(e
))
74 @repeat_on_conflict(['oldp'])
75 def update_podcast(oldp
, newp
):
77 Updates newp based on oldp and returns True if an update was necessary
81 # Update related podcasts
82 from mygpo
.data
.models
import RelatedPodcast
84 rel_podcast
= set([r
.rel_podcast
for r
in RelatedPodcast
.objects
.filter(ref_podcast
=oldp
)])
85 rel
= list(podcasts_to_ids(rel_podcast
))
86 if newp
.related_podcasts
!= rel
:
87 newp
.related_podcasts
= rel
90 # Update Group-assignment
92 group
= get_group(oldp
.group
.id)
93 if not newp
in list(group
.podcasts
):
94 newp
= group
.add_podcast(newp
)
97 # Update subscriber-data
98 from mygpo
.data
.models
import HistoricPodcastData
99 sub
= HistoricPodcastData
.objects
.filter(podcast
=oldp
).order_by('date')
100 if sub
.count() and len(newp
.subscribers
) != sub
.count():
101 transf
= lambda s
: SubscriberData(
102 timestamp
= datetime(s
.date
.year
, s
.date
.month
, s
.date
.day
),
103 subscriber_count
= s
.subscriber_count
)
104 check
= lambda s
: s
.date
.weekday() == 6
106 newp
.subscribers
= newp
.subscribers
+ map(transf
, filter(check
, sub
))
107 newp
.subscribers
= utils
.set_cmp(newp
.subscribers
, lambda x
: x
.timestamp
)
108 newp
.subscribers
= list(sorted(set(newp
.subscribers
), key
=lambda s
: s
.timestamp
))
111 PROPERTIES
= ('language', 'content_types', 'title',
112 'description', 'link', 'last_update', 'logo_url',
116 if getattr(newp
, p
, None) != getattr(oldp
, p
, None):
117 setattr(newp
, p
, getattr(oldp
, p
, None))
120 if not oldp
.url
in newp
.urls
:
121 newp
.urls
.append(oldp
.url
)
130 def create_podcast(oldp
, sparse
=False):
132 Creates a (CouchDB) Podcast document from a (ORM) Podcast object
138 update_podcast(oldp
=oldp
, newp
=p
)
143 def get_group(oldid
):
144 group
= PodcastGroup
.for_oldid(oldid
)
146 group
= create_podcastgroup(oldid
)
151 def create_podcastgroup(oldid
):
153 Creates a (CouchDB) PodcastGroup document from a
154 (ORM) PodcastGroup object
162 def get_blacklist(blacklist
):
164 Returns a list of Ids of all blacklisted podcasts
166 blacklisted
= [b
.podcast
for b
in blacklist
]
168 for p
in blacklisted
:
169 newp
= Podcast
.for_oldid(p
.id)
171 newp
= create_podcast(p
)
173 blacklist_ids
.append(newp
._id
)
177 def get_ratings(ratings
):
179 Returns a list of Rating-objects, based on the relational Ratings
181 conv
= lambda r
: Rating(rating
=r
.rating
, timestamp
=r
.timestamp
)
182 return map(conv
, ratings
)
185 def podcasts_to_ids(podcasts
):
187 podcast
= Podcast
.for_oldid(p
.id)
189 podcast
= create_podcast(p
, sparse
=True)
190 yield podcast
.get_id()
193 def get_or_migrate_podcast(oldp
):
194 return Podcast
.for_oldid(oldp
.id) or create_podcast(oldp
)
197 def create_episode_action(action
):
199 a
.action
= action
.action
200 a
.timestamp
= action
.timestamp
201 a
.device_oldid
= action
.device
.id if action
.device
else None
202 a
.started
= action
.started
203 a
.playmark
= action
.playmark
206 def create_episode(olde
, sparse
=False):
207 podcast
= get_or_migrate_podcast(olde
.podcast
)
210 e
.urls
.append(olde
.url
)
211 e
.podcast
= podcast
.get_id()
214 update_episode(olde
, e
, podcast
)
221 def get_or_migrate_episode(olde
):
222 return Episode
.for_oldid(olde
.id) or create_episode(olde
)
225 def update_episode(olde
, newe
, podcast
):
228 if not olde
.url
in newe
.urls
:
229 newe
.urls
.append(olde
.url
)
232 PROPERTIES
= ('title', 'description', 'link',
233 'author', 'duration', 'filesize', 'language',
234 'last_update', 'outdated')
237 if getattr(newe
, p
, None) != getattr(olde
, p
, None):
238 setattr(newe
, p
, getattr(olde
, p
, None))
242 if newe
.released
!= olde
.timestamp
:
243 newe
.released
= olde
.timestamp
246 if olde
.mimetype
and not olde
.mimetype
in newe
.mimetypes
:
247 newe
.mimetypes
.append(olde
.mimetype
)
250 @repeat_on_conflict(['newe'])
260 def get_or_migrate_user(user
):
261 u
= User
.for_oldid(user
.id)
267 u
.username
= user
.username
272 def get_or_migrate_device(device
, user
=None):
273 d
= Device
.for_user_uid(device
.user
, device
.uid
)
282 d
.deleted
= device
.deleted
283 u
= user
or get_or_migrate_user(device
.user
)
289 def migrate_subscription_action(old_action
):
290 action
= SubscriptionAction()
291 action
.timestamp
= old_action
.timestamp
292 action
.action
= 'subscribe' if old_action
.action
== 1 else 'unsubscribe'
293 action
.device
= get_or_migrate_device(old_action
.device
).id