Merge branch 'master' of github.com:Gluejar/regluit

pull/1/head
Andromeda Yelton 2011-11-03 16:30:36 -04:00
commit 2dcf1dfbee
18 changed files with 1056 additions and 82 deletions

29
amazon_wishlist.py Normal file
View File

@ -0,0 +1,29 @@
# scrape my amazon wishlist
import requests
import lxml.html
from lxml.cssselect import CSSSelector
def net_text(e):
children = e.getchildren()
if len(children) > 0 :
return "".join(map(net_text,children))
else:
return e.text if e.text is not None else ''
wishlist_id = '1U5EXVPVS3WP5'
url = "http://www.amazon.com/wishlist/%s/ref=cm_wl_act_print_o?_encoding=UTF8&layout=standard-print&disableNav=1&visitor-view=1&items-per-page=500&page=1" % (wishlist_id)
r = requests.get(url)
html = lxml.html.fromstring(r.content.decode("UTF-8"))
sel = CSSSelector('#itemsTable tr')
elems = sel(html)
# just realized no isbn in print version....need to do more work
for (i, tr) in enumerate(elems):
print i,
for td in tr.findall('td'):
print net_text(td),
print

View File

@ -6,6 +6,10 @@ import oauth2 as oauth
from urlparse import urlparse, urlunparse, urljoin
from urllib import urlencode
import httplib
from itertools import islice
from regluit.core import bookloader
import regluit.core
# import parse_qsl from cgi if it doesn't exist in urlparse
try:
from urlparse import parse_qsl
@ -148,10 +152,10 @@ class GoodreadsClient(object):
while (more_pages):
logger.info('request to review_list: %s %s', request_url, params)
r = request(method,request_url,params=params)
if r.status_code != httplib.OK:
#logger.info('headers, content: %s | %s ' % (r.headers,r.content))
raise GoodreadsException('Error in review_list: %s %s ' % (r.headers, r.content))
else:
#logger.info('headers, content: %s | %s ' % (r.headers,r.content))
@ -197,9 +201,37 @@ class GoodreadsClient(object):
d = dict( [ (k,int(shelves.attrib[k])) for k in shelves.attrib ] )
d["user_shelves"] = [{'name':shelf.find('name').text,
'book_count':int(shelf.find('book_count').text),
'description':shelf.find('description').text if shelf.find('description').attrib['nil'] != 'true' else None } \
'description':shelf.find('description').text if shelf.find('description').attrib['nil'] != 'true' else None,
'exclusive_flag':shelf.find('exclusive_flag').text} \
for shelf in shelves.findall('user_shelf')]
d["total_book_count"] = sum([shelf['book_count'] if shelf['exclusive_flag'] == 'true' else 0 for shelf in d["user_shelves"]])
return d
def load_goodreads_shelf_into_wishlist(user, shelf_name='all', goodreads_user_id=None, max_books=None):
"""
Load a specified Goodreads shelf (by default: all the books from the Goodreads account associated with user)
"""
gc = GoodreadsClient(key=settings.GOODREADS_API_KEY, secret=settings.GOODREADS_API_SECRET)
if goodreads_user_id is None:
if user.profile.goodreads_user_id is not None:
goodreads_user_id = user.profile.goodreads_user_id
else:
raise Exception("No Goodreads user_id is associated with user.")
for (i, review) in enumerate(islice(gc.review_list(goodreads_user_id,shelf=shelf_name),max_books)):
isbn = review["book"]["isbn10"] if review["book"]["isbn10"] is not None else review["book"]["isbn13"]
logger.info("%d %s %s %s ", i, review["book"]["title"], isbn, review["book"]["small_image_url"])
try:
edition = bookloader.add_by_isbn(isbn)
# let's not trigger too much traffic to Google books for now
# regluit.core.tasks.add_related.delay(isbn)
user.wishlist.works.add(edition.work)
logger.info("Work with isbn %s added to wishlist.", isbn)
except Exception, e:
logger.info ("error adding ISBN %s: %s", isbn, e)

67
core/librarything.py Normal file
View File

@ -0,0 +1,67 @@
import mechanize
import csv
import HTMLParser
import logging
import re
logger = logging.getLogger(__name__)
class LibraryThing(object):
"""
This class retrieves and parses the CSV representation of a LibraryThing user's library.
"""
url = "https://www.librarything.com"
csv_file_url = "http://www.librarything.com/export-csv"
def __init__(self, username=None, password=None):
self.username = username
self.password = password
self.csv_handle = None
def retrieve_csv(self):
br = mechanize.Browser()
br.open(LibraryThing.url)
# select form#2
br.select_form(nr=1)
br["formusername"] = self.username
br["formpassword"] = self.password
br.submit()
self.csv_handle = br.open(LibraryThing.csv_file_url)
return self.csv_handle
def parse_csv(self):
h = HTMLParser.HTMLParser()
reader = csv.DictReader(self.csv_handle)
# There are more fields to be parsed out. Note that there is a second author column to handle
for (i,row) in enumerate(reader):
# ISBNs are written like '[123456789x]' in the CSV, suggesting possibility of a list
m = re.match(r'^\[(.*)\]$', row["'ISBNs'"])
if m:
isbn = m.group(1).split()
else:
isbn = []
yield {'title':h.unescape(row["'TITLE'"]), 'author':h.unescape(row["'AUTHOR (first, last)'"]),
'isbn':isbn, 'comment':row["'COMMENT'"],
'tags':row["'TAGS'"], 'collections':row["'COLLECTIONS'"],
'reviews':h.unescape(row["'REVIEWS'"])}
def load_librarything_into_wishlist(user, lt_username, lt_password, max_books=None):
"""
Load a specified Goodreads shelf (by default: all the books from the Goodreads account associated with user)
"""
from regluit.core import bookloader
from itertools import islice
lt = LibraryThing(lt_username,lt_password)
lt.retrieve_csv()
for (i,book) in enumerate(islice(lt.parse_csv(),max_books)):
isbn = book["isbn"][0] # grab the first one
logger.info("%d %s %s", i, book["title"], isbn)
try:
edition = bookloader.add_by_isbn(isbn)
# let's not trigger too much traffic to Google books for now
# regluit.core.tasks.add_related.delay(isbn)
user.wishlist.works.add(edition.work)
logger.info("Work with isbn %s added to wishlist.", isbn)
except Exception, e:
logger.info ("error adding ISBN %s: %s", isbn, e)

View File

@ -3,7 +3,9 @@ from regluit.core.goodreads import GoodreadsClient
from regluit.core import tasks, bookloader
from django.conf import settings
from django.contrib.auth.models import User
from itertools import islice
#from regluit.core.goodreads import load_shelf_into_wishlist
from regluit.core import tasks
class Command(BaseCommand):
help = "list books on given user bookshelf"
@ -13,15 +15,5 @@ class Command(BaseCommand):
user = User.objects.get(username=user_name)
max_books = int(max_books)
gc = GoodreadsClient(key=settings.GOODREADS_API_KEY, secret=settings.GOODREADS_API_SECRET)
for (i, review) in enumerate(islice(gc.review_list(goodreads_user_id,shelf=shelf_name),max_books)):
isbn = review["book"]["isbn10"] if review["book"]["isbn10"] is not None else review["book"]["isbn13"]
print i, review["book"]["title"], isbn, review["book"]["small_image_url"]
try:
edition = bookloader.add_by_isbn(isbn)
# add related editions asynchronously
tasks.add_related.delay(isbn)
user.wishlist.works.add(edition.work)
except Exception, e:
print "error adding ISBN %s: %s" % (isbn, e)
tasks.load_goodreads_shelf_into_wishlist.delay(user, shelf_name, goodreads_user_id, max_books)

View File

@ -0,0 +1,16 @@
from django.core.management.base import BaseCommand
from regluit.core import librarything
from regluit.core import tasks
from django.conf import settings
from django.contrib.auth.models import User
class Command(BaseCommand):
help = "load Librarything books into wishlist"
args = "<user_name lt_username lt_password max_books>"
def handle(self, user_name, lt_username, lt_password, max_books, **options):
user = User.objects.get(username=user_name)
max_books = int(max_books)
tasks.load_librarything_into_wishlist.delay(user, lt_username, lt_password, max_books)

View File

@ -0,0 +1,149 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'GoodreadsProfile'
db.create_table('core_goodreadsprofile', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('user_id', self.gf('django.db.models.fields.CharField')(max_length=32)),
('user_name', self.gf('django.db.models.fields.CharField')(max_length=200, blank=True)),
('auth_token', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
('auth_secret', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
))
db.send_create_signal('core', ['GoodreadsProfile'])
# Adding field 'UserProfile.goodreads_id'
db.add_column('core_userprofile', 'goodreads_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['core.GoodreadsProfile'], unique=True, null=True), keep_default=False)
def backwards(self, orm):
# Deleting model 'GoodreadsProfile'
db.delete_table('core_goodreadsprofile')
# Deleting field 'UserProfile.goodreads_id'
db.delete_column('core_userprofile', 'goodreads_id_id')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'core.author': {
'Meta': {'object_name': 'Author'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'editions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authors'", 'symmetrical': 'False', 'to': "orm['core.Edition']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '500'})
},
'core.campaign': {
'Meta': {'object_name': 'Campaign'},
'activated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'amazon_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'deadline': ('django.db.models.fields.DateTimeField', [], {}),
'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}),
'paypal_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'suspended': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'suspended_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'target': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
'withdrawn': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'withdrawn_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'to': "orm['core.Work']"})
},
'core.edition': {
'Meta': {'object_name': 'Edition'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True'}),
'googlebooks_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'isbn_10': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True'}),
'isbn_13': ('django.db.models.fields.CharField', [], {'max_length': '13', 'null': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '2', 'null': 'True'}),
'publication_date': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'editions'", 'null': 'True', 'to': "orm['core.Work']"})
},
'core.goodreadsprofile': {
'Meta': {'object_name': 'GoodreadsProfile'},
'auth_secret': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'auth_token': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user_id': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'user_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'})
},
'core.subject': {
'Meta': {'object_name': 'Subject'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'editions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subjects'", 'symmetrical': 'False', 'to': "orm['core.Edition']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '500'})
},
'core.userprofile': {
'Meta': {'object_name': 'UserProfile'},
'goodreads_id': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['core.GoodreadsProfile']", 'unique': 'True', 'null': 'True'}),
'home_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'tagline': ('django.db.models.fields.CharField', [], {'max_length': '140', 'blank': 'True'}),
'twitter_id': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"})
},
'core.wishlist': {
'Meta': {'object_name': 'Wishlist'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'wishlist'", 'unique': 'True', 'to': "orm['auth.User']"}),
'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'wishlists'", 'symmetrical': 'False', 'to': "orm['core.Work']"})
},
'core.work': {
'Meta': {'object_name': 'Work'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'})
}
}
complete_apps = ['core']

View File

@ -0,0 +1,137 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'GoodreadsProfile.user_link'
db.add_column('core_goodreadsprofile', 'user_link', self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), keep_default=False)
def backwards(self, orm):
# Deleting field 'GoodreadsProfile.user_link'
db.delete_column('core_goodreadsprofile', 'user_link')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'core.author': {
'Meta': {'object_name': 'Author'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'editions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authors'", 'symmetrical': 'False', 'to': "orm['core.Edition']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '500'})
},
'core.campaign': {
'Meta': {'object_name': 'Campaign'},
'activated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'amazon_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'deadline': ('django.db.models.fields.DateTimeField', [], {}),
'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}),
'paypal_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'suspended': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'suspended_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'target': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
'withdrawn': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'withdrawn_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'to': "orm['core.Work']"})
},
'core.edition': {
'Meta': {'object_name': 'Edition'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True'}),
'googlebooks_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'isbn_10': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True'}),
'isbn_13': ('django.db.models.fields.CharField', [], {'max_length': '13', 'null': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '2', 'null': 'True'}),
'publication_date': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'editions'", 'null': 'True', 'to': "orm['core.Work']"})
},
'core.goodreadsprofile': {
'Meta': {'object_name': 'GoodreadsProfile'},
'auth_secret': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'auth_token': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user_id': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'user_link': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
'user_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'})
},
'core.subject': {
'Meta': {'object_name': 'Subject'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'editions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subjects'", 'symmetrical': 'False', 'to': "orm['core.Edition']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '500'})
},
'core.userprofile': {
'Meta': {'object_name': 'UserProfile'},
'goodreads_id': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['core.GoodreadsProfile']", 'unique': 'True', 'null': 'True'}),
'home_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'tagline': ('django.db.models.fields.CharField', [], {'max_length': '140', 'blank': 'True'}),
'twitter_id': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"})
},
'core.wishlist': {
'Meta': {'object_name': 'Wishlist'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'wishlist'", 'unique': 'True', 'to': "orm['auth.User']"}),
'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'wishlists'", 'symmetrical': 'False', 'to': "orm['core.Work']"})
},
'core.work': {
'Meta': {'object_name': 'Work'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'})
}
}
complete_apps = ['core']

View File

@ -0,0 +1,143 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Deleting field 'UserProfile.goodreads_id'
db.delete_column('core_userprofile', 'goodreads_id_id')
# Adding field 'GoodreadsProfile.user_profile'
db.add_column('core_goodreadsprofile', 'user_profile', self.gf('django.db.models.fields.related.OneToOneField')(related_name='goodreads_id', unique=True, null=True, to=orm['core.UserProfile']), keep_default=False)
def backwards(self, orm):
# Adding field 'UserProfile.goodreads_id'
db.add_column('core_userprofile', 'goodreads_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['core.GoodreadsProfile'], unique=True, null=True), keep_default=False)
# Deleting field 'GoodreadsProfile.user_profile'
db.delete_column('core_goodreadsprofile', 'user_profile_id')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'core.author': {
'Meta': {'object_name': 'Author'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'editions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authors'", 'symmetrical': 'False', 'to': "orm['core.Edition']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '500'})
},
'core.campaign': {
'Meta': {'object_name': 'Campaign'},
'activated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'amazon_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'deadline': ('django.db.models.fields.DateTimeField', [], {}),
'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}),
'paypal_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'suspended': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'suspended_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'target': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
'withdrawn': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'withdrawn_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'to': "orm['core.Work']"})
},
'core.edition': {
'Meta': {'object_name': 'Edition'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True'}),
'googlebooks_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'isbn_10': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True'}),
'isbn_13': ('django.db.models.fields.CharField', [], {'max_length': '13', 'null': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '2', 'null': 'True'}),
'publication_date': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'editions'", 'null': 'True', 'to': "orm['core.Work']"})
},
'core.goodreadsprofile': {
'Meta': {'object_name': 'GoodreadsProfile'},
'auth_secret': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'auth_token': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user_id': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'user_link': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
'user_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
'user_profile': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'goodreads_id'", 'unique': 'True', 'null': 'True', 'to': "orm['core.UserProfile']"})
},
'core.subject': {
'Meta': {'object_name': 'Subject'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'editions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subjects'", 'symmetrical': 'False', 'to': "orm['core.Edition']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '500'})
},
'core.userprofile': {
'Meta': {'object_name': 'UserProfile'},
'home_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'tagline': ('django.db.models.fields.CharField', [], {'max_length': '140', 'blank': 'True'}),
'twitter_id': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"})
},
'core.wishlist': {
'Meta': {'object_name': 'Wishlist'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'wishlist'", 'unique': 'True', 'to': "orm['auth.User']"}),
'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'wishlists'", 'symmetrical': 'False', 'to': "orm['core.Work']"})
},
'core.work': {
'Meta': {'object_name': 'Work'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'})
}
}
complete_apps = ['core']

View File

@ -0,0 +1,171 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Deleting model 'GoodreadsProfile'
db.delete_table('core_goodreadsprofile')
# Adding field 'UserProfile.goodreads_user_id'
db.add_column('core_userprofile', 'goodreads_user_id', self.gf('django.db.models.fields.CharField')(max_length=32, null=True, blank=True), keep_default=False)
# Adding field 'UserProfile.goodreads_user_name'
db.add_column('core_userprofile', 'goodreads_user_name', self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), keep_default=False)
# Adding field 'UserProfile.goodreads_auth_token'
db.add_column('core_userprofile', 'goodreads_auth_token', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
# Adding field 'UserProfile.goodreads_auth_secret'
db.add_column('core_userprofile', 'goodreads_auth_secret', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False)
# Adding field 'UserProfile.goodreads_user_link'
db.add_column('core_userprofile', 'goodreads_user_link', self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), keep_default=False)
def backwards(self, orm):
# Adding model 'GoodreadsProfile'
db.create_table('core_goodreadsprofile', (
('user_id', self.gf('django.db.models.fields.CharField')(max_length=32)),
('user_link', self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True)),
('user_profile', self.gf('django.db.models.fields.related.OneToOneField')(related_name='goodreads_id', unique=True, null=True, to=orm['core.UserProfile'])),
('auth_secret', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
('user_name', self.gf('django.db.models.fields.CharField')(max_length=200, blank=True)),
('auth_token', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
))
db.send_create_signal('core', ['GoodreadsProfile'])
# Deleting field 'UserProfile.goodreads_user_id'
db.delete_column('core_userprofile', 'goodreads_user_id')
# Deleting field 'UserProfile.goodreads_user_name'
db.delete_column('core_userprofile', 'goodreads_user_name')
# Deleting field 'UserProfile.goodreads_auth_token'
db.delete_column('core_userprofile', 'goodreads_auth_token')
# Deleting field 'UserProfile.goodreads_auth_secret'
db.delete_column('core_userprofile', 'goodreads_auth_secret')
# Deleting field 'UserProfile.goodreads_user_link'
db.delete_column('core_userprofile', 'goodreads_user_link')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'core.author': {
'Meta': {'object_name': 'Author'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'editions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authors'", 'symmetrical': 'False', 'to': "orm['core.Edition']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '500'})
},
'core.campaign': {
'Meta': {'object_name': 'Campaign'},
'activated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'amazon_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'deadline': ('django.db.models.fields.DateTimeField', [], {}),
'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}),
'paypal_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'suspended': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'suspended_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'target': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}),
'withdrawn': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'withdrawn_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'to': "orm['core.Work']"})
},
'core.edition': {
'Meta': {'object_name': 'Edition'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True'}),
'googlebooks_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'isbn_10': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True'}),
'isbn_13': ('django.db.models.fields.CharField', [], {'max_length': '13', 'null': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '2', 'null': 'True'}),
'publication_date': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'editions'", 'null': 'True', 'to': "orm['core.Work']"})
},
'core.subject': {
'Meta': {'object_name': 'Subject'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'editions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subjects'", 'symmetrical': 'False', 'to': "orm['core.Edition']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '500'})
},
'core.userprofile': {
'Meta': {'object_name': 'UserProfile'},
'goodreads_auth_secret': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'goodreads_auth_token': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'goodreads_user_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
'goodreads_user_link': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
'goodreads_user_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
'home_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'tagline': ('django.db.models.fields.CharField', [], {'max_length': '140', 'blank': 'True'}),
'twitter_id': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"})
},
'core.wishlist': {
'Meta': {'object_name': 'Wishlist'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'wishlist'", 'unique': 'True', 'to': "orm['auth.User']"}),
'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'wishlists'", 'symmetrical': 'False', 'to': "orm['core.Work']"})
},
'core.work': {
'Meta': {'object_name': 'Work'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'})
}
}
complete_apps = ['core']

View File

@ -198,18 +198,18 @@ class Wishlist(models.Model):
user = models.OneToOneField(User, related_name='wishlist')
works = models.ManyToManyField('Work', related_name='wishlists')
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
tagline = models.CharField(max_length=140, blank=True)
home_url = models.URLField(blank=True)
twitter_id = models.CharField(max_length=15, blank=True)
#class GoodreadsProfile(models.Model):
# user_id = models.CharField(max_length=32)
# username = models.CharField(max_length=200, blank=True)
# auth_token = models.TextField(null=True, blank=True)
# auth_secret = models.TextField(null=True, blank=True)
goodreads_user_id = models.CharField(max_length=32, null=True, blank=True)
goodreads_user_name = models.CharField(max_length=200, null=True, blank=True)
goodreads_auth_token = models.TextField(null=True, blank=True)
goodreads_auth_secret = models.TextField(null=True, blank=True)
goodreads_user_link = models.CharField(max_length=200, null=True, blank=True)
from regluit.core import signals
from regluit.payment.manager import PaymentManager

View File

@ -1,6 +1,6 @@
from celery.decorators import task
from regluit.core import bookloader
from regluit.core import goodreads, librarything
@task
def add_related(isbn):
@ -9,3 +9,12 @@ def add_related(isbn):
@task
def add_by_isbn(isbn):
return bookloader.add_by_isbn(isbn)
@task
def load_goodreads_shelf_into_wishlist(user, shelf_name='all', goodreads_user_id=None, max_books=None):
return goodreads.load_goodreads_shelf_into_wishlist(user,shelf_name,goodreads_user_id,max_books)
@task
def load_librarything_into_wishlist(user, lt_username, lt_password, max_books=None):
return librarything.load_librarything_into_wishlist(user, lt_username, lt_password, max_books)

View File

@ -54,3 +54,8 @@ class CampaignPledgeForm(forms.Form):
raise forms.ValidationError("Only one of pledge_amount and pre_approval can be non-zero.")
return cleaned_data
class GoodreadsShelfLoadingForm(forms.Form):
goodreads_shelf_name = forms.CharField(widget=forms.Select(choices=(
('all','all'),
)))

View File

@ -1,6 +1,61 @@
{% extends "base.html" %}
{% block extra_head %}
{% block extra_head %}
<script type="application/x-javascript">
jQuery(document).ready(function($) {
// post to form_loc and alert with response
var post_and_alert = function (form_loc){
return function(bubble,params) {
$.post(form_loc, params, function (data) {
alert(data);
});
return bubble;
}
};
var update_number_of_books = function (){
$.ajax({url:'/api/v1/wishlist/1/',
data: {format:'json',
api_key:'{{api_key}}',
username: '{{user.username}}'},
success: function(json) {
$('#number_of_books_on_wishlist').html(json["works"].length);
var d = new Date();
$('#num_books_update_time').html(d.toUTCString());
},
error: function(jqXHR, textStatus, errorThrown) {
alert('error')
}
})
}
// add a current date time to the display of current number of books on wishlist
var d = new Date()
$('#num_books_update_time').html(d.toUTCString());
$('#test_click').click(update_number_of_books);
$('#clear_wishlist_form').submit(function (){
post_and_alert('{% url clear_wishlist %}')(true,{});
update_number_of_books();
return false;
});
$('#load_shelf_form').submit(function(){
post_and_alert('{% url goodreads_load_shelf%}')(false,$('#load_shelf_form').serialize());
return false;
});
});
</script>
{% endblock %}
{% block title %}Goodreads{% endblock %}
@ -13,22 +68,34 @@
<div class="content-block">
<h1>Goodreads</h1>
{% if goodreads_userid %}
<p>Welcome, Goodreads user id# {{goodreads_userid}}. Your GR username is {{goodreads_username}}. Want to see <a href="{{goodreads_userlink}}">your Goodreads profile</a>?</p>
{% if user.profile.goodreads_user_id %}
<p>Welcome, Goodreads user id# {{user.profile.goodreads_user_id}}. Your GR username is {{user.profile.goodreads_user_name}} and here is <a href="{{user.profile.goodreads_user_link}}">your Goodreads profile</a>.</p>
<form id="clear_goodreads_id" method="post" action="{% url goodreads_flush_assoc %}">
<p><input type="submit" value="Unlink your Goodreads account from Unglue.it" /></p>
</form>
<p>You can also revoke access for Unglue.it at <a href="http://www.goodreads.com/user/edit?tab=apps">Goodreads user apps panel</a>.</p>
<hr />
<form id="load_shelf_form" method="post" action="#">
{{gr_shelf_load_form.as_p}}
<input type="submit" value="Load the books from your Goodreads shelf to your wishlist" />
</form>
{% else %}
<p>We don't currently know your Goodreads user information.</p>
<p><a href="{{goodreads_auth_url}}">Enable us to link to your Goodreads account.</a></p>
{% endif %}
{% if shelves_info %}
<p>You have {{shelves_info.total}} shelves. </p>
{% if shelves_info.user_shelves %}
<ul>
{% for shelf in shelves_info.user_shelves %}
<li>{{shelf.name}}: {{shelf.book_count}} book(s)</li>
{% endfor %}
</ul>
{% endif %}
<p><a href="{{goodreads_auth_url}}">Enable Unglue.it to link to your Goodreads account</a></p>
{% endif %}
<hr />
<p><a href="#" id="test_click">Click here to update the number of books on your wishlist:</a></p>
<div id="gr_status"><p>Number of books on your wishlist: <span id="number_of_books_on_wishlist">{{user.wishlist.books.all|length}}</span> (as of <span id="num_books_update_time"></span>)</p></div>
<form id="clear_wishlist_form" method="post" action="#">
<input type="submit" value="Empty your wishlist" />
</form>
<!-- list user's books -->
{% if reviews %}
<p>Here are some of your books that you've put on your Goodreads shelves:</p>
@ -38,8 +105,6 @@
{% endfor %}
</ul>
{% endif %}
<p>Clear the association with your Goodreads account by <a href="{% url goodreads_flush_session %}">flushing your session.</a></p>
<p>Revoke access for Unglue.it at <a href="http://www.goodreads.com/user/edit?tab=apps">Goodreads user apps panel</a>.</p>
</div>
</div>

View File

@ -156,7 +156,7 @@ how do I integrate the your wishlist thing with the tabs thing?
</div>
</div>
<div class="block block3">
<h3 class="title">Other Stuff</h3>
<h3 class="title">Other Stuff (to use?)</h3>
<div class="check-list">
<label>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</label>
</div>

View File

@ -2,6 +2,7 @@ from django.conf.urls.defaults import *
from django.views.generic.simple import direct_to_template
from django.views.generic.base import TemplateView
from django.views.generic import ListView, DetailView
from django.contrib.auth.decorators import login_required
from regluit.core.models import Campaign
from regluit.frontend.views import CampaignFormView, GoodreadsDisplayView
@ -21,8 +22,10 @@ urlpatterns = patterns(
url(r"^campaigns/$", ListView.as_view(
model=Campaign,template_name="campaign_list.html", context_object_name="campaign_list")),
url(r"^campaigns/(?P<pk>\d+)/$",CampaignFormView.as_view(), name="campaign_by_id"),
url(r"^goodreads/$", GoodreadsDisplayView.as_view(), name="goodreads_display"),
url(r"^goodreads/$", login_required(GoodreadsDisplayView.as_view()), name="goodreads_display"),
url(r"^goodreads/auth_cb/$", "goodreads_cb", name="goodreads_cb"),
url(r"^goodreads/flush/$","goodreads_flush_session", name="goodreads_flush_session"),
url(r"^goodreads/flush/$","goodreads_flush_assoc", name="goodreads_flush_assoc"),
url(r"^goodreads/load_shelf/$","goodreads_load_shelf", name="goodreads_load_shelf"),
url(r"^goodreads/clear_wishlist/$","clear_wishlist", name="clear_wishlist"),
url(r"^stub/", "stub", name="stub")
)

View File

@ -5,6 +5,7 @@ from django.conf import settings
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.core.exceptions import ObjectDoesNotExist
from django.forms import Select
from django.http import HttpResponseRedirect
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
@ -21,12 +22,12 @@ from regluit.core import tasks
from regluit.core import models, bookloader
from regluit.core.search import gluejar_search
from regluit.core.goodreads import GoodreadsClient
from regluit.frontend.forms import UserData, ProfileForm
from regluit.frontend.forms import CampaignPledgeForm
from regluit.frontend.forms import UserData, ProfileForm, CampaignPledgeForm, GoodreadsShelfLoadingForm
from regluit.payment.manager import PaymentManager
from regluit.payment.parameters import TARGET_TYPE_CAMPAIGN
from regluit.core import goodreads
from tastypie.models import ApiKey
logger = logging.getLogger(__name__)
@ -234,46 +235,42 @@ class GoodreadsDisplayView(TemplateView):
template_name = "goodreads_display.html"
def get_context_data(self, **kwargs):
context = super(GoodreadsDisplayView, self).get_context_data(**kwargs)
goodreads_attribs = ["goodreads_userid", "goodreads_username", "goodreads_isauthorized", "goodreads_userlink"]
# for this round, I will use the Session to hold the Goodreads profile info
session = self.request.session
# load up context with this info even though the template can directly access the session.
# down the road, we won't store the goodreads user info in the session.
for attrib in goodreads_attribs:
context[attrib] = session.get(attrib, None)
# a Goodreads user shouldn't have to authorize us to get certain functionality
# if we don't know the Goodreads identity of user, offer to authenticate user to Goodreads and grab identity
gr_client = GoodreadsClient(key=settings.GOODREADS_API_KEY, secret=settings.GOODREADS_API_SECRET)
if session.get("goodreads_isauthorized") is None:
user = self.request.user
if user.is_authenticated():
api_key = ApiKey.objects.filter(user=user)[0].key
context['api_key'] = api_key
if user.profile.goodreads_user_id is None:
# calculate the Goodreads authorization URL
(context["goodreads_auth_url"], request_token) = gr_client.begin_authorization(self.request.build_absolute_uri(reverse('goodreads_cb')))
logger.info("goodreads_auth_url: %s" %(context["goodreads_auth_url"]))
# store request token in session so that we can redeem it for auth_token if authorization works
session['goodreads_request_token'] = request_token['oauth_token']
session['goodreads_request_secret'] = request_token['oauth_token_secret']
else:
gr_shelves = gr_client.shelves_list(user_id=user.profile.goodreads_user_id)
context["shelves_info"] = gr_shelves
gr_shelf_load_form = GoodreadsShelfLoadingForm()
# load the shelves into the form
choices = [('all','all (%d)' % (gr_shelves["total_book_count"]))] + [(s["name"],"%s (%d)" % (s["name"],s["book_count"])) for s in gr_shelves["user_shelves"]]
gr_shelf_load_form.fields['goodreads_shelf_name'].widget = Select(choices=tuple(choices))
# if we have a userid, grab info about the book shelves and books
if session.get("goodreads_userid") is not None:
context["shelves_info"] = gr_client.shelves_list(user_id=session["goodreads_userid"])
context["reviews"] = list(islice(gr_client.review_list(user_id=session["goodreads_userid"],per_page=50),50))
# also, now grab the books on the user's shelves
context["gr_shelf_load_form"] = gr_shelf_load_form
#context["reviews"] = list(islice(gr_client.review_list(user_id=user.profile.goodreads_user_id, per_page=50),50))
return context
@login_required
def goodreads_cb(request):
# handle callback from Goodreads
# how to check that Goodreads is saying it's a go?
"""handle callback from Goodreads"""
session = request.session
authorized_flag = request.GET['authorize'] # is it '1'?
request_oauth_token = request.GET['oauth_token']
# compare what Goodreads sends back in terms of a request_token vs what is stored in session
if authorized_flag == '1':
request_token = {'oauth_token': session.get('goodreads_request_token'),
'oauth_token_secret': session.get('goodreads_request_secret')}
@ -281,26 +278,64 @@ def goodreads_cb(request):
access_token = gr_client.complete_authorization(request_token)
# store the access token in the session
session["goodreads_access_token"] = access_token["oauth_token"]
session["goodreads_access_secret"] = access_token["oauth_token_secret"]
session["goodreads_isauthorized"] = True
# delete old request tokens in the session
del session['goodreads_request_token']
del session['goodreads_request_secret']
# store the access token in the user profile
profile = request.user.profile
profile.goodreads_auth_token = access_token["oauth_token"]
profile.goodreads_auth_secret = access_token["oauth_token_secret"]
# let's get the userid, username
user = gr_client.auth_user()
session["goodreads_userid"] = user["userid"]
session["goodreads_username"] = user["name"]
session["goodreads_userlink"] = user["link"]
profile.goodreads_user_id = user["userid"]
profile.goodreads_user_name = user["name"]
profile.goodreads_user_link = user["link"]
profile.save() # is this needed?
# redirect to the Goodreads display page -- should observe some next later
return HttpResponseRedirect(reverse('goodreads_display'))
def goodreads_flush_session(request):
request.session.flush()
return HttpResponse("Your session has been flushed. Go back to <a href='%s'>goodreads display</a>"
% (reverse('goodreads_display')))
@require_POST
@login_required
@csrf_exempt
def goodreads_flush_assoc(request):
user = request.user
if user.is_authenticated():
profile = user.profile
profile.goodreads_user_id = None
profile.goodreads_user_name = None
profile.goodreads_user_link = None
profile.goodreads_auth_token = None
profile.goodreads_auth_secret = None
profile.save()
return HttpResponseRedirect(reverse('goodreads_display'))
@require_POST
@login_required
@csrf_exempt
def goodreads_load_shelf(request):
"""
a view to allow user load goodreads shelf into her wishlist
"""
# Should be moved to the API
goodreads_shelf_name = request.POST.get('goodreads_shelf_name', 'all')
user = request.user
try:
logger.info('Adding task to load shelf %s to user %s', goodreads_shelf_name, user)
tasks.load_goodreads_shelf_into_wishlist.delay(user, goodreads_shelf_name)
return HttpResponse("Shelf loading placed on task queue.")
except Exception,e:
return HttpResponse("Error in loading shelf: %s " % (e))
logger.info("Error in loading shelf: %s ", e)
@require_POST
@login_required
@csrf_exempt
def clear_wishlist(request):
try:
request.user.wishlist.works.clear()
return HttpResponse('wishlist cleared')
except Exception, e:
return HttpResponse("Error in clearing wishlist: %s " % (e))
logger.info("Error in clearing wishlist: %s ", e)

View File

@ -13,3 +13,5 @@ django-kombu
django-celery
redis
oauth2
mechanize
pyzotero

119
zotero_books.py Normal file
View File

@ -0,0 +1,119 @@
from zoteroconf import user_id, user_key
from itertools import islice
from functools import partial
from pyzotero.zotero import Zotero
import logging
logger = logging.getLogger(__name__)
class Zotero2(Zotero):
def __init__(self, user_id = None, user_key = None):
self.__params = {}
super(Zotero2,self).__init__(user_id,user_key)
def set_parameters(self, **kwargs):
self.__params.update(kwargs)
def _to_iterator(self, f, *args, **kwargs):
current_start = self.__params.get("start", 0)
params = self.__params.copy()
params["start"] = current_start
more_items = True
while more_items:
self.add_parameters(**params)
items = f(*args,**kwargs)
for item in items:
yield item
params["start"] += len(items)
if len(items) == 0:
more_items = False
def __getattribute__(self, name):
if name in ['items','item','top','children','tag_items', 'group_items','group_top',
'group_item','group_item_children', 'group_items_tag',
'group_collection_items', 'group_collection_item',
'group_collection_top','collection_items','get_subset',
'collections','collections_sub','group_collections',
'group_collection',
'groups','tags','item_tags','group_tags','group_item_tags']:
#f = super(Zotero2,self).items
f = getattr(super(Zotero2,self),name)
#return self._to_iterator(f)
return partial(self._to_iterator,f)
else:
return super(Zotero2,self).__getattribute__(name)
#def items(self):
# f = super(Zotero2,self).items
# return self._to_iterator(f)
#def items0(self):
# current_start = self._params.get("start", 1)
# params = self._params
#
# params["start"] = current_start
# more_items = True
#
# while more_items:
# self.add_parameters(**params)
# items = super(Zotero2,self).items()
# for item in items:
# yield item
# params["start"] += len(items)
# if len(items) == 0:
# more_items = False
class MyZotero(Zotero2):
def __init__(self, user_id=user_id, user_key=user_key):
super(MyZotero,self).__init__(user_id,user_key)
def items_in_unglue_it_collection(self):
return self.collection_items('3RKQ23IP')
def compare_keys(self,max,pagesize1,pagesize2):
set1 = self.item_keys(max,pagesize1)
set2 = self.item_keys(max,pagesize2)
print "length: ", len(set1), len(set2)
print set1 ^ set2
def item_keys(self, max, page_size):
self.set_parameters(limit=page_size)
items = self.items()
item_set = set()
for (i, item) in enumerate(islice(items,max)):
item_set.add((item["group_id"], item["key"], item["title"]))
print i, (item["group_id"], item["key"], item["title"])
return item_set
def get_all_items(self):
print len(self.item_keys(5000,99))
def get_books(self,max=10000):
self.set_parameters(sort="type")
items = self.items()
for (i, item) in enumerate(islice(items,max)):
if item.get("itemType") == 'book':
yield {'group_id':item["group_id"], 'key':item["key"], 'title':item["title"],
'itemType':item.get("itemType"), 'isbn':item.get("ISBN", None)}
def upload_to_unglue_it(self,unglueit_user_name, max):
from regluit.core import bookloader
from django.contrib.auth.models import User
user = User.objects.get(username=unglueit_user_name)
books = self.get_books(max=max)
for book in books:
try:
isbn = book['isbn']
if isbn:
edition = bookloader.add_by_isbn(isbn)
# let's not trigger too much traffic to Google books for now
# regluit.core.tasks.add_related.delay(isbn)
user.wishlist.works.add(edition.work)
logger.info("Work with isbn %s added to wishlist.", isbn)
except Exception, e:
logger.info ("error adding ISBN %s: %s", isbn, e)
zot = MyZotero()
#zot.compare_keys(24,7,3)
to_unglue = list(zot.items_in_unglue_it_collection())
print len(to_unglue), [item["title"] for item in to_unglue]
for b in zot.get_books(50):
print b
zot.upload_to_unglue_it('RaymondYee',5000)
#print zot.get_all_items()