1 from __future__
import unicode_literals
4 from datetime
import datetime
6 from django
.contrib
.contenttypes
.models
import ContentType
7 from django
.contrib
.auth
.models
import User
9 from mygpo
.podcasts
.models
import Tag
10 from mygpo
.users
.models
import UserProfile
, Client
, SyncGroup
, PodcastUserState
11 from mygpo
.subscriptions
.models
import Subscription
, PodcastConfig
12 from mygpo
.history
.models
import HistoryEntry
13 from mygpo
.podcasts
.models
import Podcast
16 logger
= logging
.getLogger(__name__
)
19 def to_maxlength(cls
, field
, val
):
20 """ Cut val to the maximum length of cls's field """
21 max_length
= cls
._meta
.get_field(field
).max_length
22 orig_length
= len(val
)
23 if orig_length
> max_length
:
24 val
= val
[:max_length
]
25 logger
.warn('%s.%s length reduced from %d to %d',
26 cls
.__name
__, field
, orig_length
, max_length
)
31 def migrate_pstate(state
):
32 """ migrate a podcast state """
35 user
= User
.objects
.get(profile__uuid
=state
.user
)
36 except User
.DoesNotExist
:
37 logger
.warn("User with ID '{id}' does not exist".format(
42 podcast
= Podcast
.objects
.all().get_by_any_id(state
.podcast
)
43 except Podcast
.DoesNotExist
:
44 logger
.warn("Podcast with ID '{id}' does not exist".format(
48 logger
.info('Updating podcast state for user {user} and podcast {podcast}'
49 .format(user
=user
, podcast
=podcast
))
52 for tag
in state
.tags
:
53 ctype
= ContentType
.objects
.get_for_model(podcast
)
54 tag
, created
= Tag
.objects
.get_or_create(tag
=tag
,
61 logger
.info("Created tag '{}' for user {} and podcast {}",
64 # create all history entries
65 history
= HistoryEntry
.objects
.filter(user
=user
, podcast
=podcast
)
66 for action
in state
.actions
:
67 timestamp
= action
.timestamp
68 client
= user
.client_set
.get(id=action
.device
)
69 action
= action
.action
71 'timestamp': timestamp
,
77 he
, created
= HistoryEntry
.objects
.get_or_create(**he_data
)
80 logger
.info('History Entry created: {user} {action} {podcast} '
81 'on {client} @ {timestamp}'.format(**he_data
))
83 # check which clients are currently subscribed
84 subscribed_devices
= get_subscribed_devices(state
)
85 subscribed_ids
= subscribed_devices
.keys()
86 subscribed_clients
= user
.client_set
.filter(id__in
=subscribed_ids
)
87 unsubscribed_clients
= user
.client_set
.exclude(id__in
=subscribed_ids
)
89 # create subscriptions for subscribed clients
90 for client
in subscribed_clients
:
91 ts
= subscribed_devices
[client
.id.hex]
96 'ref_url': state
.ref_url
,
99 'deleted': client
.id.hex in state
.disabled_devices
,
101 subscription
, created
= Subscription
.objects
.get_or_create(**sub_data
)
104 logger
.info('Subscription created: {user} subscribed to {podcast} '
105 'on {client} @ {created}'.format(**sub_data
))
107 # delete all other subscriptions
108 Subscription
.objects
.filter(user
=user
, podcast
=podcast
,
109 client__in
=unsubscribed_clients
).delete()
111 # only create the PodcastConfig obj if there are any settings
113 logger
.info('Updating {num} settings'.format(num
=len(state
.settings
)))
114 PodcastConfig
.objects
.update_or_create(user
=user
, podcast
=podcast
,
116 'settings': json
.dumps(state
.settings
),
121 def get_subscribed_devices(state
):
122 """ device Ids on which the user subscribed to the podcast """
125 for action
in state
.actions
:
126 if action
.action
== "subscribe":
127 if not action
.device
in state
.disabled_devices
:
128 devices
[action
.device
] = action
.timestamp
130 if action
.device
in devices
:
131 devices
.pop(action
.device
)
137 from couchdbkit
import Database
138 db
= Database('http://127.0.0.1:5984/mygpo_userdata_copy')
139 from couchdbkit
.changes
import ChangesStream
, fold
, foreach
143 'PodcastUserState': (PodcastUserState
, migrate_pstate
),
144 'User': (None, None),
145 'Suggestions': (None, None),
146 'EpisodeUserState': (None, None),
149 def migrate_change(c
):
150 logger
.info('Migrate seq %s', c
['seq'])
153 if not 'doc_type' in doc
:
154 logger
.warn('Document contains no doc_type: %r', doc
)
157 doctype
= doc
['doc_type']
159 cls
, migrate
= MIGRATIONS
[doctype
]
162 logger
.warn("Skipping '%s'", doctype
)
169 def migrate(since
=0):
170 with
ChangesStream(db
,
176 for change
in stream
:
177 migrate_change(change
)