Skip to content
This repository
Newer
Older
100644 501 lines (418 sloc) 17.416 kb
04bbedb6 »
2011-09-11 Copyright header
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright © 2009-2011 Alexander Kojevnikov <alexander@kojevnikov.com>
4 #
5 # muspy is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # muspy is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Affero General Public License for more details.
14 #
15 # You should have received a copy of the GNU Affero General Public License
16 # along with muspy. If not, see <http://www.gnu.org/licenses/>.
17
a72c4cae »
2011-09-10 Email activation
18 import random
c5912e9f »
2011-10-16 daemon: Send email notifications
19 from smtplib import SMTPException
fac2b613 »
2011-11-26 api: POST user
20 import string
7c2341cc »
2011-10-11 Add UserArtists
21 from time import sleep
a72c4cae »
2011-09-10 Email activation
22
b14d6ea5 »
2011-09-10 Sign up / sign in /sign out
23 from django.contrib.auth.models import User
a72c4cae »
2011-09-10 Email activation
24 from django.core.mail import EmailMultiAlternatives
cbc53df8 »
2011-11-15 Delete account
25 from django.db import connection, IntegrityError, models, transaction
6bbd2283 »
2011-09-10 PRAGMA foreign_keys=1
26 from django.db.backends.signals import connection_created
778944b4 »
2011-10-15 Initialise and sort by is_starred
27 from django.db.models import Count, Q
47c91b75 »
2011-09-10 Add UserProfile
28 from django.db.models.signals import post_save
6bbd2283 »
2011-09-10 PRAGMA foreign_keys=1
29 from django.dispatch import receiver
a72c4cae »
2011-09-10 Email activation
30 from django.template.loader import render_to_string
6bbd2283 »
2011-09-10 PRAGMA foreign_keys=1
31
7c2341cc »
2011-10-11 Add UserArtists
32 import app.musicbrainz as mb
994a74d2 »
2011-10-13 Add the atom feed for new releases
33 from app.tools import date_to_iso8601, date_to_str, str_to_date
7c2341cc »
2011-10-11 Add UserArtists
34
97bdbd59 »
2011-10-15 Star release groups
35
13e32eea »
2011-10-04 Add Artist and ReleaseGroup models
36 class Artist(models.Model):
c0ebc697 »
2011-09-08 Add an empty app
37
13e32eea »
2011-10-04 Add Artist and ReleaseGroup models
38 mbid = models.CharField(max_length=36, unique=True)
39 name = models.CharField(max_length=512)
40 sort_name = models.CharField(max_length=512)
41 disambiguation = models.CharField(max_length=512)
be118e8b »
2011-10-15 Make UserArtist a ManyToManyField
42 users = models.ManyToManyField(User, through='UserArtist')
a72c4cae »
2011-09-10 Email activation
43
449d6cce »
2011-10-19 Blacklist special-purpose artists
44 blacklisted = [
45 '89ad4ac3-39f7-470e-963a-56509c546377', # Various Artists
aa0f9482 »
2011-10-27 Block more special-purpose artists
46 'fe5b7087-438f-4e7e-afaf-6d93c8c888b2', # Various Artists
3dd4347a »
2011-12-09 Blacklist another Various Artists alias
47 '0677ef60-6be5-4e36-9d1e-8bb2bf85b981', # Various Artists
9e4bf7b3 »
2012-04-08 Blacklist another VA alias
48 'b7c7dfd9-d735-4733-9b10-f060ac75bd6a', # Various Artists
449d6cce »
2011-10-19 Blacklist special-purpose artists
49 'f731ccc4-e22a-43af-a747-64213329e088', # [anonymous]
50 '33cf029c-63b0-41a0-9855-be2a3665fb3b', # [data]
51 '314e1c25-dde7-4e4d-b2f4-0a7b9f7c56dc', # [dialogue]
52 'eec63d3c-3b81-4ad4-b1e4-7c147d4d2b61', # [no artist]
53 '9be7f096-97ec-4615-8957-8d40b5dcbc41', # [traditional]
54 '125ec42a-7229-4250-afc5-e057484327fe', # [unknown]
aa0f9482 »
2011-10-27 Block more special-purpose artists
55 '203b6058-2401-4bf0-89e3-8dc3d37c3f12', # [unknown]
56 '5e760f5a-ea55-4b53-a18f-021c0d9779a6', # [unknown]
49aa02ff »
2011-10-28 Block even more special-purpose artists
57 '1d8bc797-ec8a-40d2-8d80-b1346b56a65f', # [unknown]
58 '7734d67f-44d9-4ba2-91e3-9b067263210e', # [unknown]
e056496a »
2011-10-25 Black list [soundtrack]
59 'd6bd72bc-b1e2-4525-92aa-0f853cbb41bf', # [soundtrack]
449d6cce »
2011-10-19 Blacklist special-purpose artists
60 ]
61 class Blacklisted(Exception): pass
87c4ecb4 »
2011-10-24 Handle unknown artists
62 class Unknown(Exception): pass
449d6cce »
2011-10-19 Blacklist special-purpose artists
63
57ddf359 »
2011-10-09 Show added artists
64 @classmethod
4c642ccc »
2011-10-11 Show artist's release groups
65 def get_by_mbid(cls, mbid):
7c2341cc »
2011-10-11 Add UserArtists
66 """ Fetches the artist and releases from MB if not in the database. """
449d6cce »
2011-10-19 Blacklist special-purpose artists
67 if mbid in cls.blacklisted:
68 raise cls.Blacklisted()
69
4c642ccc »
2011-10-11 Show artist's release groups
70 try:
71 return cls.objects.get(mbid=mbid)
72 except cls.DoesNotExist:
7c2341cc »
2011-10-11 Add UserArtists
73 pass
74
75 artist_data = mb.get_artist(mbid)
87c4ecb4 »
2011-10-24 Handle unknown artists
76 if artist_data is None:
4c642ccc »
2011-10-11 Show artist's release groups
77 return None
87c4ecb4 »
2011-10-24 Handle unknown artists
78 if not artist_data:
79 raise cls.Unknown
4c642ccc »
2011-10-11 Show artist's release groups
80
7c2341cc »
2011-10-11 Add UserArtists
81 artist = Artist(
82 mbid=mbid, name=artist_data['name'], sort_name=artist_data['sort-name'],
10a89927 »
2011-10-15 daemon: Update artist info
83 disambiguation=artist_data.get('disambiguation', ''))
2401aac8 »
2011-10-24 Fix occasional integrity errors
84 try:
85 artist.save()
86 except IntegrityError:
87 # The artist was added while we were querying MB.
88 return cls.objects.get(mbid=mbid)
7c2341cc »
2011-10-11 Add UserArtists
89
90 # Add a few release groups immediately.
2401aac8 »
2011-10-24 Fix occasional integrity errors
91 # Sleep 1s to comply with the MB web service.
92 sleep(1)
529eca91 »
2011-10-17 Add all release groups for new artists
93 LIMIT = 100
94 release_groups = mb.get_release_groups(mbid, limit=LIMIT, offset=0)
7c2341cc »
2011-10-11 Add UserArtists
95 if release_groups:
96 with transaction.commit_on_success():
97 for rg_data in release_groups:
e14b44ea »
2011-10-17 daemon: Implement ADD_ARTIST and ADD_RELEASE_GROUP jobs
98 # Ignoring releases without a release date or a type.
99 if rg_data.get('first-release-date') and rg_data.get('type'):
7c2341cc »
2011-10-11 Add UserArtists
100 release_group = ReleaseGroup(
101 artist=artist,
102 mbid=rg_data['id'],
103 name=rg_data['title'],
104 type=rg_data['type'],
c05a3b0e »
2011-10-12 Calendar
105 date=str_to_date(rg_data['first-release-date']),
7c2341cc »
2011-10-11 Add UserArtists
106 is_deleted=False)
9af209c7 »
2011-10-25 Multiple artists per release group
107 release_group.save()
529eca91 »
2011-10-17 Add all release groups for new artists
108
109 if release_groups is None or len(release_groups) == LIMIT:
110 # Add the remaining release groups
111 Job.add_release_groups(artist)
112
7c2341cc »
2011-10-11 Add UserArtists
113 return artist
114
4c642ccc »
2011-10-11 Show artist's release groups
115 @classmethod
57ddf359 »
2011-10-09 Show added artists
116 def get_by_user(cls, user):
117 # TODO: paging
be118e8b »
2011-10-15 Make UserArtist a ManyToManyField
118 return cls.objects.filter(users=user).order_by('sort_name')[:1000]
57ddf359 »
2011-10-09 Show added artists
119
97bdbd59 »
2011-10-15 Star release groups
120
3b047a0c »
2011-10-16 Job model
121 class Job(models.Model):
122
b1876ee1 »
2011-10-17 Add multiple artists
123 ADD_ARTIST = 1
529eca91 »
2011-10-17 Add all release groups for new artists
124 ADD_RELEASE_GROUPS = 2
f41cab4c »
2011-10-22 Show empty album cover
125 GET_COVER = 3
126 IMPORT_LASTFM = 4
3b047a0c »
2011-10-16 Job model
127
529eca91 »
2011-10-17 Add all release groups for new artists
128 user = models.ForeignKey(User, null=True)
3b047a0c »
2011-10-16 Job model
129 type = models.IntegerField()
130 data = models.TextField()
131
b1876ee1 »
2011-10-17 Add multiple artists
132 @classmethod
133 def add_artists(cls, user, names):
134 with transaction.commit_on_success():
135 for name in names:
136 cls(user=user, type=cls.ADD_ARTIST, data=name).save()
137
529eca91 »
2011-10-17 Add all release groups for new artists
138 @classmethod
139 def add_release_groups(cls, artist):
140 cls(user=None, type=cls.ADD_RELEASE_GROUPS, data=artist.mbid).save()
b1876ee1 »
2011-10-17 Add multiple artists
141
f41cab4c »
2011-10-22 Show empty album cover
142 @classmethod
143 def get_cover(cls, mbid):
144 cls(user=None, type=cls.GET_COVER, data=mbid).save()
145
2db316ba »
2011-10-22 Import artists from Last.fm
146 @classmethod
6b5a7890 »
2011-11-03 Allow to specify the period when importing from Last.fm
147 def import_lastfm(cls, user, username, count, period):
148 data = str(count) + ',' + period + ',' + username
149 cls(user=user, type=cls.IMPORT_LASTFM, data=data).save()
2db316ba »
2011-10-22 Import artists from Last.fm
150
151 @classmethod
152 def importing_artists(cls, user):
153 """Returns a comma-separated list of all artists yet to be imported."""
154 q = cls.objects.filter(user=user)
155 q = q.filter(type=cls.ADD_ARTIST)
156 return [r.data for r in q]
157
158 @classmethod
159 def has_import_lastfm(cls, user):
160 return cls.objects.filter(user=user).filter(type=cls.IMPORT_LASTFM).exists()
161
f41cab4c »
2011-10-22 Show empty album cover
162
861ddc0d »
2011-10-16 Add the Notification model
163 class Notification(models.Model):
164
165 class Meta:
166 db_table = 'app_notification'
167 unique_together = ('user', 'release_group')
168
169 user = models.ForeignKey(User)
170 release_group = models.ForeignKey('ReleaseGroup')
171
14bc2b28 »
2011-10-16 daemon: Add Notifications
172
13e32eea »
2011-10-04 Add Artist and ReleaseGroup models
173 class ReleaseGroup(models.Model):
9af209c7 »
2011-10-25 Multiple artists per release group
174 """De-normalised release groups
175
176 A release group can have different artists. Instead of adding a
177 many-to-many relationship between them, keep everything in one
178 table and group by mbid as needed.
179
180 """
181 class Meta:
182 unique_together = ('artist', 'mbid')
13e32eea »
2011-10-04 Add Artist and ReleaseGroup models
183
184 artist = models.ForeignKey(Artist)
9af209c7 »
2011-10-25 Multiple artists per release group
185 mbid = models.CharField(max_length=36)
13e32eea »
2011-10-04 Add Artist and ReleaseGroup models
186 name = models.CharField(max_length=512)
187 type = models.CharField(max_length=16)
188 date = models.IntegerField() # 20080101 OR 20080100 OR 20080000
189 is_deleted = models.BooleanField()
861ddc0d »
2011-10-16 Add the Notification model
190
191 users_who_starred = models.ManyToManyField(
192 User, through='Star', related_name='starred_release_groups')
193 users_to_notify = models.ManyToManyField(
194 User, through='Notification', related_name='new_release_groups')
47c91b75 »
2011-09-10 Add UserProfile
195
4c642ccc »
2011-10-11 Show artist's release groups
196 def date_str(self):
c05a3b0e »
2011-10-12 Calendar
197 return date_to_str(self.date)
4c642ccc »
2011-10-11 Show artist's release groups
198
994a74d2 »
2011-10-13 Add the atom feed for new releases
199 def date_iso8601(self):
200 return date_to_iso8601(self.date)
201
4c642ccc »
2011-10-11 Show artist's release groups
202 @classmethod
f026ba0d »
2011-10-26 Fixes
203 def get(cls, artist=None, user=None, limit=0, offset=0, feed=False):
994a74d2 »
2011-10-13 Add the atom feed for new releases
204 if not artist and not user:
205 assert 'Both artist and user are None'
206 return None
cab32cff »
2011-10-29 Fix ReleaseGroup.get()
207
208 # Unfortunately I don't see how to use ORM for these queries.
209 sql = """
210 SELECT
211 "app_releasegroup"."id",
212 "app_releasegroup"."artist_id",
213 "app_releasegroup"."mbid",
214 "app_releasegroup"."name",
215 "app_releasegroup"."type",
216 "app_releasegroup"."date",
217 "app_releasegroup"."is_deleted",
218 "app_artist"."mbid" AS "artist_mbid",
ca5d2b12 »
2011-11-25 api: GET releases
219 "app_artist"."name" AS "artist_name",
220 "app_artist"."sort_name" AS "artist_sort_name",
221 "app_artist"."disambiguation" AS "artist_disambiguation"
cab32cff »
2011-10-29 Fix ReleaseGroup.get()
222 {select}
223 FROM "app_releasegroup"
224 JOIN "app_artist" ON "app_artist"."id" = "app_releasegroup"."artist_id"
225 {join}
226 WHERE "app_releasegroup"."is_deleted" = 0
227 {where}
228 ORDER BY {order}
30f54c90 »
2011-10-29 Optimise ReleaseGroup.get()
229 LIMIT %s OFFSET %s
cab32cff »
2011-10-29 Fix ReleaseGroup.get()
230 """
231 select = join = where = ''
232 order = '"app_releasegroup"."date" DESC'
233 params = []
994a74d2 »
2011-10-13 Add the atom feed for new releases
234 if artist:
cab32cff »
2011-10-29 Fix ReleaseGroup.get()
235 where += '\nAND "app_releasegroup"."artist_id" = %s'
236 params.append(artist.id)
994a74d2 »
2011-10-13 Add the atom feed for new releases
237 if user:
cab32cff »
2011-10-29 Fix ReleaseGroup.get()
238 # Stars.
239 select += ',\n"app_star"."id" as "is_starred"'
240 join += '\nJOIN "app_userartist" ON "app_userartist"."artist_id" = "app_artist"."id"'
241 join += '\nLEFT JOIN "app_star" ON "app_star"."user_id" = "app_userartist"."user_id" AND "app_star"."release_group_id" = "app_releasegroup"."id"'
242 where += '\nAND "app_userartist"."user_id" = %s'
243 params.append(user.id)
64cb5b2c »
2011-11-10 Fix stars sort order
244 order = '"app_star"."user_id" DESC, ' + order
cab32cff »
2011-10-29 Fix ReleaseGroup.get()
245 # Release types.
ca9679db »
2011-10-26 Don't show duplicate releases for imported users
246 profile = user.get_profile()
cab32cff »
2011-10-29 Fix ReleaseGroup.get()
247 types = profile.get_types()
248 ss = ','.join('%s' for i in xrange(len(types)))
249 where += '\nAND "app_releasegroup"."type" IN (' + ss + ')'
250 params.extend(types)
251
f026ba0d »
2011-10-26 Fixes
252 if feed and profile.legacy_id:
ca9679db »
2011-10-26 Don't show duplicate releases for imported users
253 # Don't include release groups added during the import
cab32cff »
2011-10-29 Fix ReleaseGroup.get()
254 # TODO: Feel free to remove this check some time in 2013.
255 where += '\nAND "app_releasegroup"."id" > 261202'
256
257 sql = sql.format(select=select, join=join, where=where, order=order)
30f54c90 »
2011-10-29 Optimise ReleaseGroup.get()
258 params.extend([limit, offset])
259 return cls.objects.raw(sql, params)
4c642ccc »
2011-10-11 Show artist's release groups
260
261 @classmethod
c05a3b0e »
2011-10-12 Calendar
262 def get_calendar(cls, date, limit, offset):
263 """Returns the list of release groups for the date."""
264 q = cls.objects.filter(date__lte=date)
cab32cff »
2011-10-29 Fix ReleaseGroup.get()
265 q = q.select_related('artist')
266 # Calendar uses the same template as releases, adapt to conform.
267 q = q.extra(select={
268 'artist_mbid': '"app_artist"."mbid"',
ca5d2b12 »
2011-11-25 api: GET releases
269 'artist_name': '"app_artist"."name"',
270 'artist_sort_name': '"app_artist"."sort_name"',
271 'artist_disambiguation': '"app_artist"."disambiguation"',
272 })
c05a3b0e »
2011-10-12 Calendar
273 q = q.filter(is_deleted=False)
496db6a6 »
2011-10-29 Optimise ReleaseGroup.get_calendar()
274 q = q.order_by('-date')
c05a3b0e »
2011-10-12 Calendar
275 return q[offset:offset+limit]
4c642ccc »
2011-10-11 Show artist's release groups
276
97bdbd59 »
2011-10-15 Star release groups
277
278 class Star(models.Model):
279
280 class Meta:
778944b4 »
2011-10-15 Initialise and sort by is_starred
281 db_table = 'app_star'
97bdbd59 »
2011-10-15 Star release groups
282 unique_together = ('user', 'release_group')
283
284 user = models.ForeignKey(User)
285 release_group = models.ForeignKey(ReleaseGroup)
286
287 @classmethod
49302470 »
2011-10-25 Fix starring
288 def set(cls, user, id, value):
97bdbd59 »
2011-10-15 Star release groups
289 try:
49302470 »
2011-10-25 Fix starring
290 release_group = ReleaseGroup.objects.get(id=id)
97bdbd59 »
2011-10-15 Star release groups
291 except ReleaseGroup.DoesNotExist:
292 return
293 if value:
294 cls.objects.get_or_create(user=user, release_group=release_group)
295 else:
296 cls.objects.filter(user=user, release_group=release_group).delete()
297
be118e8b »
2011-10-15 Make UserArtist a ManyToManyField
298
09150725 »
2011-10-04 Add UserArtist model
299 class UserArtist(models.Model):
300
301 class Meta:
302 unique_together = ('user', 'artist')
303
304 user = models.ForeignKey(User)
305 artist = models.ForeignKey(Artist)
7c2341cc »
2011-10-11 Add UserArtists
306 date = models.DateTimeField(auto_now_add=True)
307
308 @classmethod
3ae58f84 »
2011-10-14 Filter releases by user when authenticated
309 def get(cls, user, artist):
310 try:
311 return cls.objects.get(user=user, artist=artist)
312 except cls.DoesNotExist:
313 return None
314
315 @classmethod
7c2341cc »
2011-10-11 Add UserArtists
316 def add(cls, user, artist):
317 user_artist = cls(user=user, artist=artist)
318 try:
319 user_artist.save()
320 except IntegrityError:
321 pass
09150725 »
2011-10-04 Add UserArtist model
322
3ec78858 »
2011-10-12 Remove UserArtists
323 @classmethod
324 def remove(cls, user, mbids):
325 with transaction.commit_on_success():
326 for mbid in mbids:
49302470 »
2011-10-25 Fix starring
327 q = cls.objects.filter(user=user)
3ec78858 »
2011-10-12 Remove UserArtists
328 q = q.filter(artist__mbid=mbid)
329 q.delete()
330
97bdbd59 »
2011-10-15 Star release groups
331
47c91b75 »
2011-09-10 Add UserProfile
332 class UserProfile(models.Model):
333
a72c4cae »
2011-09-10 Email activation
334 code_length = 16
335
47c91b75 »
2011-09-10 Add UserProfile
336 user = models.OneToOneField(User)
337
338 notify = models.BooleanField(default=True)
339 notify_album = models.BooleanField(default=True)
340 notify_single = models.BooleanField(default=True)
341 notify_ep = models.BooleanField(default=True)
342 notify_live = models.BooleanField(default=True)
343 notify_compilation = models.BooleanField(default=True)
344 notify_remix = models.BooleanField(default=True)
345 notify_other = models.BooleanField(default=True)
346 email_activated = models.BooleanField(default=False)
a72c4cae »
2011-09-10 Email activation
347 activation_code = models.CharField(max_length=code_length)
348 reset_code = models.CharField(max_length=code_length)
b2966917 »
2011-10-12 Add UserProfile.legacy_id, tidy
349 legacy_id = models.IntegerField(null=True)
47c91b75 »
2011-09-10 Add UserProfile
350
34a19eff »
2011-10-15 Filter user releases by type
351 def get_types(self):
352 """Return the list of release types the user wants to follow."""
353 types = []
354 if self.notify_album: types.append('Album')
355 if self.notify_single: types.append('Single')
356 if self.notify_ep: types.append('EP')
357 if self.notify_live: types.append('Live')
358 if self.notify_compilation: types.append('Compilation')
359 if self.notify_remix: types.append('Remix')
360 if self.notify_other:
361 types.extend(['Soundtrack', 'Spokenword', 'Interview', 'Audiobook', 'Other'])
362 return types
363
a72c4cae »
2011-09-10 Email activation
364 def generate_code(self):
365 code_chars = '23456789abcdefghijkmnpqrstuvwxyz'
366 return ''.join(random.choice(code_chars) for i in xrange(UserProfile.code_length))
367
cbc53df8 »
2011-11-15 Delete account
368 def purge(self):
369 user = self.user
370 with transaction.commit_on_success():
371 Job.objects.filter(user=user).delete()
372 Notification.objects.filter(user=user).delete()
373 Star.objects.filter(user=user).delete()
374 UserArtist.objects.filter(user=user).delete()
375 UserSearch.objects.filter(user=user).delete()
376 self.delete()
377 # Cannot call user.delete() because it references deprecated auth_message.
378 cursor = connection.cursor()
379 cursor.execute('DELETE FROM auth_user WHERE id=%s', [user.id])
380
a72c4cae »
2011-09-10 Email activation
381 def send_email(self, subject, text_template, html_template, **kwds):
382 text = render_to_string(text_template, kwds)
3b4ccca4 »
2011-10-30 Tidy
383 msg = EmailMultiAlternatives(
384 subject,
385 text,
5e0df8e2 »
2012-03-05 Change the sender to muspy.com
386 'muspy.com <info@muspy.com>',
3b4ccca4 »
2011-10-30 Tidy
387 [self.user.email])
a72c4cae »
2011-09-10 Email activation
388 if html_template:
389 html = render_to_string(html_template, kwds)
c5912e9f »
2011-10-16 daemon: Send email notifications
390 msg.attach_alternative(html, "text/html")
391 try:
392 msg.send()
393 except SMTPException:
394 return False
395 return True
a72c4cae »
2011-09-10 Email activation
396
397 def send_activation_email(self):
398 code = self.generate_code()
399 self.activation_code = code
400 self.save()
c5912e9f »
2011-10-16 daemon: Send email notifications
401 self.send_email(
402 subject='Email Activation',
403 text_template='email/activate.txt',
404 html_template=None,
405 code=code)
a72c4cae »
2011-09-10 Email activation
406
407 def send_reset_email(self):
408 code = self.generate_code()
409 self.reset_code = code
410 self.save()
c5912e9f »
2011-10-16 daemon: Send email notifications
411 self.send_email(
412 subject='Password Reset Confirmation',
413 text_template='email/reset.txt',
414 html_template=None,
415 code=code)
a72c4cae »
2011-09-10 Email activation
416
62a01e31 »
2012-03-05 One-click unsubscribe
417 def unsubscribe(self):
418 self.notify = False
419 self.save()
420
a72c4cae »
2011-09-10 Email activation
421 @classmethod
422 def activate(cls, code):
b2966917 »
2011-10-12 Add UserProfile.legacy_id, tidy
423 profiles = UserProfile.objects.filter(activation_code=code)
a72c4cae »
2011-09-10 Email activation
424 if not profiles:
425 return False
426 profile = profiles[0]
427 profile.activation_code = ''
428 profile.email_activated = True
429 profile.save()
430 return True
431
432 @classmethod
433 def reset(cls, code):
b2966917 »
2011-10-12 Add UserProfile.legacy_id, tidy
434 profiles = UserProfile.objects.filter(reset_code=code)
e4e63681 »
2011-09-10 Password reset fixes
435 if not profiles:
a72c4cae »
2011-09-10 Email activation
436 return None, None
e4e63681 »
2011-09-10 Password reset fixes
437 profile = profiles[0]
438 password = User.objects.make_random_password(length=16)
a72c4cae »
2011-09-10 Email activation
439 profile.reset_code = ''
440 profile.user.set_password(password)
65215082 »
2011-10-16 Save the user and the profile within a transaction
441 with transaction.commit_on_success():
442 profile.user.save()
443 profile.save()
a72c4cae »
2011-09-10 Email activation
444 return profile.user.email, password
445
446 @classmethod
b2966917 »
2011-10-12 Add UserProfile.legacy_id, tidy
447 def get_by_email(cls, email):
448 users = User.objects.filter(email=email.lower())
449 return users[0].get_profile() if users else None
450
451 @classmethod
452 def get_by_legacy_id(cls, legacy_id):
453 profiles = cls.objects.filter(legacy_id=legacy_id)
454 return profiles[0] if profiles else None
455
456 @classmethod
457 def get_by_username(cls, username):
458 users = User.objects.filter(username=username)
a72c4cae »
2011-09-10 Email activation
459 return users[0].get_profile() if users else None
13e32eea »
2011-10-04 Add Artist and ReleaseGroup models
460
fac2b613 »
2011-11-26 api: POST user
461 @classmethod
462 def create_user(cls, email, password):
463 chars = string.ascii_lowercase + string.digits
464 username = ''.join(random.choice(chars) for i in xrange(30))
465 return User.objects.create_user(username, email, password)
466
97bdbd59 »
2011-10-15 Star release groups
467
b1876ee1 »
2011-10-17 Add multiple artists
468 class UserSearch(models.Model):
469
470 user = models.ForeignKey(User)
471 search = models.CharField(max_length=512)
472
473 @classmethod
474 def get(cls, user):
475 return cls.objects.filter(user=user)
476
2f500a94 »
2011-10-17 Remove user searches
477 @classmethod
478 def remove(cls, user, searches):
479 with transaction.commit_on_success():
480 for search in searches:
481 cls.objects.filter(user=user, search=search).delete()
482
b1876ee1 »
2011-10-17 Add multiple artists
483
13e32eea »
2011-10-04 Add Artist and ReleaseGroup models
484 # Activate foreign keys for sqlite.
485 @receiver(connection_created)
486 def activate_foreign_keys(sender, connection, **kwargs):
487 if connection.vendor == 'sqlite':
488 cursor = connection.cursor()
489 cursor.execute('PRAGMA foreign_keys=1;')
490
97bdbd59 »
2011-10-15 Star release groups
491
13e32eea »
2011-10-04 Add Artist and ReleaseGroup models
492 # Create a profile for each user.
493 @receiver(post_save, sender=User)
494 def user_post_save(sender, instance, created, **kwargs):
495 if created:
496 p = UserProfile()
497 p.user = instance
498 p.save()
499
97bdbd59 »
2011-10-15 Star release groups
500
13e32eea »
2011-10-04 Add Artist and ReleaseGroup models
501 User.__unicode__ = lambda x: x.email
Something went wrong with that request. Please try again.