migrate publisher functionality to CouchDB backend
[mygpo.git] / mygpo / users / models.py
blob9125d52a8125bfdcc96fc1d5161985310de9de14
1 import uuid
2 from datetime import datetime
3 from couchdbkit import ResourceNotFound
4 from couchdbkit.ext.django.schema import *
6 from mygpo.core.models import Podcast
9 class Rating(DocumentSchema):
10 rating = IntegerProperty()
11 timestamp = DateTimeProperty(default=datetime.utcnow)
14 class Suggestions(Document):
15 user = StringProperty()
16 user_oldid = IntegerProperty()
17 podcasts = StringListProperty()
18 blacklist = StringListProperty()
19 ratings = SchemaListProperty(Rating)
21 @classmethod
22 def for_user_oldid(cls, oldid):
23 r = cls.view('users/suggestions_by_user_oldid', key=oldid, \
24 include_docs=True)
25 if r:
26 return r.first()
27 else:
28 s = Suggestions()
29 s.user_oldid = oldid
30 return s
33 def get_podcasts(self):
34 from mygpo.api.models import Subscription
35 subscriptions = [x.podcast for x in Subscription.objects.filter(user__id=self.user_oldid)]
36 subscriptions = [Podcast.for_oldid(x.id) for x in subscriptions]
37 subscriptions = [x._id for x in subscriptions if x]
39 for p in self.podcasts:
40 if not p in self.blacklist and not p in subscriptions:
41 try:
42 podcast = Podcast.get(p)
43 except ResourceNotFound:
44 continue
46 if podcast:
47 yield podcast
50 def __repr__(self):
51 if not self._id:
52 return super(Suggestions, self).__repr__()
53 else:
54 return '%d Suggestions for %s (%s)' % \
55 (len(self.podcasts),
56 self.user[:10] if self.user else self.user_oldid,
57 self._id[:10])
60 class EpisodeAction(DocumentSchema):
61 """
62 One specific action to an episode. Must
63 always be part of a EpisodeUserState
64 """
66 action = StringProperty(required=True)
67 timestamp = DateTimeProperty(required=True)
68 device_oldid = IntegerProperty()
69 started = IntegerProperty()
70 playmark = IntegerProperty()
71 total = IntegerProperty()
73 def __eq__(self, other):
74 if not isinstance(other, EpisodeAction):
75 return False
76 vals = ('action', 'timestamp', 'device_oldid', 'started', 'playmark',
77 'total')
78 return all([getattr(self, v, None) == getattr(other, v, None) for v in vals])
81 def __repr__(self):
82 return '%s-Action on %s at %s (in %s)' % \
83 (self.action, self.device_oldid, self.timestamp, self._id)
86 class EpisodeUserState(Document):
87 """
88 Contains everything a user has done with an Episode
89 """
91 episode_oldid = IntegerProperty()
92 episode = StringProperty(required=True)
93 actions = SchemaListProperty(EpisodeAction)
94 settings = DictProperty()
97 def add_actions(self, actions):
98 self.actions += actions
99 self.actions = list(set(self.actions))
100 self.actions.sort(key=lambda x: x.timestamp)
103 def is_favorite(self):
104 return self.settings.get('is_favorite', False)
107 def set_favorite(self, set_to=True):
108 self.settings['is_favorite'] = set_to
111 def __repr__(self):
112 return 'Episode-State %s (in %s)' % \
113 (self.episode, self._id)
115 def __eq__(self, other):
116 if not isinstance(other, EpisodeUserState):
117 return False
119 return (self.episode_oldid == other.episode_oldid and \
120 self.episode == other.episode and
121 self.actions == other.actions)
125 class SubscriptionAction(Document):
126 action = StringProperty()
127 timestamp = DateTimeProperty(default=datetime.utcnow)
128 device = StringProperty()
130 def __eq__(self, other):
131 return self.actions == other.action and \
132 self.timestamp == other.timestamp and \
133 self.device == other.device
136 class PodcastUserState(Document):
138 Contains everything that a user has done
139 with a specific podcast and all its episodes
142 podcast = StringProperty(required=True)
143 episodes = SchemaDictProperty(EpisodeUserState)
144 user_oldid = IntegerProperty()
145 settings = DictProperty()
146 actions = SchemaListProperty(SubscriptionAction)
147 tags = StringListProperty()
150 @classmethod
151 def for_user_podcast(cls, user, podcast):
152 r = PodcastUserState.view('users/podcast_states_by_podcast', \
153 key=[podcast.get_id(), user.id], limit=1, include_docs=True)
154 if r:
155 return r.first()
156 else:
157 p = PodcastUserState()
158 p.podcast = podcast.get_id()
159 p.user_oldid = user.id
160 return p
163 @classmethod
164 def for_user(cls, user):
165 r = PodcastUserState.view('users/podcast_states_by_user',
166 startkey=[user.id, None], endkey=[user.id, 'ZZZZ'],
167 include_docs=True)
168 return list(r)
171 def get_episode(self, e_id):
172 if e_id in self.episodes:
173 return self.episodes[e_id]
175 e = EpisodeUserState()
176 e.episode = e_id
177 self.episodes[e_id] = e
178 return e
180 def add_actions(self, actions):
181 self.actions += actions
182 self.actions = list(set(self.actions))
183 self.actions.sort(key=lambda x: x.timestamp)
186 def add_tags(self, tags):
187 self.tags = list(set(self.tags + tags))
190 def __eq__(self, other):
191 if other is None:
192 return False
194 return self.podcast == other.podcast and \
195 self.user_oldid == other.user_oldid
197 def __repr__(self):
198 return 'Podcast %s for User %s (%s)' % \
199 (self.podcast, self.user_oldid, self._id)
202 class Device(Document):
203 id = StringProperty(default=lambda: uuid.uuid4().hex)
204 oldid = IntegerProperty()
205 uid = StringProperty()
206 name = StringProperty()
207 type = StringProperty()
208 settings = DictProperty()
210 @classmethod
211 def for_user_uid(cls, user, uid):
212 r = cls.view('users/devices_by_user_uid', key=[user.id, uid], limit=1)
213 return r.one() if r else None
216 class User(Document):
217 oldid = IntegerProperty()
218 settings = DictProperty()
219 devices = SchemaListProperty(Device)
222 @classmethod
223 def for_oldid(cls, oldid):
224 r = cls.view('users/users_by_oldid', key=oldid, limit=1, include_docs=True)
225 return r.one() if r else None
228 def get_device(self, uid):
229 for device in self.devices:
230 if device.uid == uid:
231 return device
233 return None
236 def published_podcasts(self):
238 Returns a list of the Ids (or full objects) of podcasts for which the
239 user has publisher permissions
242 r = Podcast.view('publisher/podcasts_by_publisher', key=self._id)
243 return [x['value'] for x in r]
246 def __repr__(self):
247 return 'User %s' % self._id