diff --git a/README.md b/README.md index 7b70504c..3aef8c27 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,11 @@ Here are some instructions for setting up regluit for development on an Ubuntu system. If you are on OS X see notes below to install python-setuptools in step 1: -1. `aptitude install python-setuptools git` +1. `aptitude install python-setuptools git python-lxml` 1. `sudo easy_install virtualenv virtualenvwrapper` 1. `git clone git@github.com:Gluejar/regluit.git` 1. `cd regluit` -1. `mkvirtualenv --no-site-packages regluit` +1. `mkvirtualenv regluit` 1. `pip install -r requirements.pip` 1. `add2virtualenv ..` 1. `cp settings/dev.py settings/me.py` @@ -41,23 +41,22 @@ Below are the steps for getting regluit running on EC2 with Apache and mod_wsgi, 1. create an ubuntu natty ec2 instance using ami-1aad5273 1. `sudo aptitude update` 1. `sudo aptitude upgrade` -1. `sudo aptitude install git apache libapache2-mod-wsgi mysql-client python-virtualenv python-mysqldb redis-server` +1. `sudo aptitude install git apache libapache2-mod-wsgi mysql-client python-virtualenv python-mysqldb redis-server python-lxml` 1. `sudo mkdir /opt/regluit` 1. `sudo chown ubuntu:ubuntu /opt/regluit` 1. `cd /opt` 1. `git config --global user.name "Ed Summers"` 1. `git config --global user.email "ehs@pobox.com"` 1. `ssh-keygen` -1. add `~/.ssh/id_rsa.pub` as a deploy key on github +1. add `~/.ssh/id_rsa.pub` as a deploy key on github https://github.com/Gluejar/regluit/admin/keys 1. `git clone git@github.com:Gluejar/regluit.git` 1. `cd /opt/regluit` -1. `cp settings/dev.py settings/prod.py` 1. create an Amazon RDS instance 1. connect to it, e.g. `mysql -u root -h gluejardb.cboagmr25pjs.us-east-1.rds.amazonaws.com -p` 1. `CREATE DATABASE unglueit CHARSET utf8;` 1. `GRANT ALL ON unglueit.* TO ‘unglueit’@’ip-10-244-250-168.ec2.internal’ IDENTIFIED BY 'unglueit' REQUIRE SSL` 1. update settings/prod.py with database credentials -1. `virtualenv --no-site-packages ENV` +1. `virtualenv ENV` 1. `source ENV/bin/activate` 1. `pip install -r requirements.pip` 1. `echo "/opt/" > ENV/lib/python2.7/site-packages/regluit.pth` @@ -66,9 +65,9 @@ Below are the steps for getting regluit running on EC2 with Apache and mod_wsgi, 1. `sudo a2ensite regluit` 1. `sudo /etc/init.d/apache2 restart` 1. `sudo adduser --no-create-home celery --disabled-password --disabled-login` -1. `sudo cp celeryd /etc/init.d/celeryd` +1. `sudo cp deploy/celeryd /etc/init.d/celeryd` 1. `sudo chmod 755 /etc/init.d/celeryd` -1. `sudo cp celeryd.conf /etc/default/celeryd` +1. `sudo cp deploy/celeryd.conf /etc/default/celeryd` 1. `sudo mkdir /var/log/celery` 1. `sudo chown celery:celery /var/log/celery` 1. `sudo mkdir /var/run/celery` diff --git a/core/librarything.py b/core/librarything.py index 5de52443..5f0a21a3 100644 --- a/core/librarything.py +++ b/core/librarything.py @@ -62,6 +62,13 @@ class LibraryThing(object): # title book_data["title"] = {"href":cols[1].xpath('.//a')[0].attrib['href'], "title":cols[1].xpath('.//a')[0].text} + + # extract work_id and book_id from href + try: + (book_data["work_id"], book_data["book_id"]) = re.match("^/work/(.*)/book/(.*)$",book_data["title"]["href"]).groups() + except: + (book_data["work_id"], book_data["book_id"]) = (None, None) + # author -- what if there is more than 1? or none? try: book_data["author"] = {"display_name":cols[2].xpath('.//a')[0].text, @@ -86,7 +93,46 @@ class LibraryThing(object): yield book_data def viewstyle_5(self, rows): - raise NotImplementedError() + # implement this view to get at the ISBNs + for (i,row) in enumerate(rows): + book_data = {} + cols = row.xpath('td') + + # title + book_data["title"] = {"href":cols[0].xpath('.//a')[0].attrib['href'], + "title":cols[0].xpath('.//a')[0].text} + + # extract work_id and book_id from href + try: + (book_data["work_id"], book_data["book_id"]) = re.match("^/work/(.*)/book/(.*)$",book_data["title"]["href"]).groups() + except: + (book_data["work_id"], book_data["book_id"]) = (None, None) + + # tags + tag_links = cols[1].xpath('.//a') + book_data["tags"] = filter(lambda x: x is not None, [a.text for a in tag_links]) + + # lc classification + try: + book_data["lc_call_number"] = cols[2].xpath('.//span')[0].text + except Exception, e: + logger.info("book lc call number exception: %s %s", book_data["title"], e) + book_data["lc_call_number"] = None + + # subject + + subjects = cols[3].xpath('.//div[@class="subjectLine"]') + book_data["subjects"] = [{'href':s.xpath('a')[0].attrib['href'], + 'text':s.xpath('a')[0].text} for s in subjects] + + # isbn + try: + book_data["isbn"] = cols[4].xpath('.//span')[0].text + except Exception, e: + book_data["isbn"] = None + + yield book_data + def parse_user_catalog(self, view_style=1): from lxml import html diff --git a/core/management/commands/librarything_load_books_2.py b/core/management/commands/librarything_load_books_2.py index 9c6b3fbf..d7c02672 100644 --- a/core/management/commands/librarything_load_books_2.py +++ b/core/management/commands/librarything_load_books_2.py @@ -11,6 +11,6 @@ class Command(BaseCommand): def handle(self, lt_username, **options): lt = librarything.LibraryThing(username=lt_username) - for (i, book) in enumerate(lt.parse_user_catalog()): - print i, book["title"] + for (i, book) in enumerate(lt.parse_user_catalog(view_style=5)): + print i, book["title"], book["isbn"], book["work_id"], book["book_id"] \ No newline at end of file diff --git a/core/models.py b/core/models.py index 2db43f82..4c133ef4 100755 --- a/core/models.py +++ b/core/models.py @@ -17,7 +17,7 @@ class CeleryTask(models.Model): user = models.ForeignKey(User, related_name="tasks", null=True) description = models.CharField(max_length=2048, null=True) # a description of what the task is function_name = models.CharField(max_length=1024) # used to reconstitute the AsyncTask with which to get status - function_args = models.IntegerField() # not full generalized here -- takes only a single arg for now. + function_args = models.IntegerField(null=True) # not full generalized here -- takes only a single arg for now. active = models.NullBooleanField(default=True) def __unicode__(self): @@ -43,13 +43,15 @@ class CeleryTask(models.Model): class Claim(models.Model): rights_holder = models.ForeignKey("RightsHolder", related_name="claim", null=False ) work = models.ForeignKey("Work", related_name="claim", null=False ) - user = models.ForeignKey(User, related_name="user", null=False ) + user = models.ForeignKey(User, related_name="claim", null=False ) created = models.DateTimeField(auto_now_add=True) class RightsHolder(models.Model): email = models.CharField(max_length=100, blank=True) rights_holder_name = models.CharField(max_length=100, blank=True) owner = models.ForeignKey(User, related_name="rights_holder", null=False ) + def __unicode__(self): + return self.rights_holder_name class Premium(models.Model): PREMIUM_TYPES = ((u'00', u'Default'),(u'CU', u'Custom')) diff --git a/frontend/forms.py b/frontend/forms.py index 652a8a5d..03dc94fc 100644 --- a/frontend/forms.py +++ b/frontend/forms.py @@ -1,9 +1,15 @@ from django import forms from django.db import models -from regluit.core.models import UserProfile, RightsHolder from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ from decimal import Decimal as D +from regluit.core.models import UserProfile, RightsHolder, Claim + +class ClaimForm(forms.ModelForm): + i_agree=forms.BooleanField() + class Meta: + model = Claim + widgets = { 'user': forms.HiddenInput, 'work': forms.HiddenInput } class RightsHolderForm(forms.ModelForm): class Meta: diff --git a/frontend/templates/claim.html b/frontend/templates/claim.html new file mode 100644 index 00000000..10be3679 --- /dev/null +++ b/frontend/templates/claim.html @@ -0,0 +1,20 @@ +{% extends "basedocumentation.html" %} + +{% block doccontent %} + +

Rights Holder Claim Form

+
+ {% csrf_token %} +

Rightsholder making claim

+{{ rights_holder.rights_holder_name }} +

Work being claimed

+{{ work.title }}
+{{ work.author }} +

Terms and Conditions

+ {{ form.as_p }} +[legal stuff goes here] + +
+ + +{% endblock %} \ No newline at end of file diff --git a/frontend/templates/rhtools.html b/frontend/templates/rhtools.html index 2d3d2c6f..05687374 100644 --- a/frontend/templates/rhtools.html +++ b/frontend/templates/rhtools.html @@ -3,7 +3,7 @@ {% block doccontent %}

unglue.it Tools for Rightsholders

-{% if request.user.rights_holder %} +{% if request.user.rights_holder.count %}

Rights Holders That You Administer

{% for rights_holder in request.user.rights_holder.all %}

Name: {{ rights_holder.rights_holder_name }}

@@ -12,6 +12,16 @@

{% endfor %} {% endif %} +{% if request.user.rights_holder.count %} +

Works You Have Claimed

+ {% for claim in request.user.claim.all %} +

Title: {{claim.work.title }}

+

Author: {{claim.work.author }}

+

On Behalf of: {{ claim.rights_holder.rights_holder_name }}

+

PSA #: {{ claim.rights_holder.id }}

+

+ {% endfor %} +{% endif %}

Rights Holder FAQ/How to launch a campaign

diff --git a/frontend/templates/rights_holders.html b/frontend/templates/rights_holders.html index 7a7e3e7b..9ead80fd 100644 --- a/frontend/templates/rights_holders.html +++ b/frontend/templates/rights_holders.html @@ -10,7 +10,7 @@ {{ form.as_p }} - +

Accepted Rights Holders

{% for rights_holder in rights_holders %}

{{ rights_holder.rights_holder_name }}

diff --git a/frontend/templates/work.html b/frontend/templates/work.html index 190e76a9..ec8b7721 100644 --- a/frontend/templates/work.html +++ b/frontend/templates/work.html @@ -110,7 +110,26 @@
- Want to Unglue infomation xxx +

Details for {{ work.title }}

+ {% if work.claim.count %} +

Rights Information

+

This work has been claimed by:

+ + {% endif %} + {% if request.user.rights_holder.all.count %} +

Claim this work:

+
+ {% csrf_token %} + {{ claimform.user }} + {{ claimform.work }} + {{ claimform.rights_holder }} + +
+ {% endif %}
diff --git a/frontend/urls.py b/frontend/urls.py index 3f0ca97a..7ae16700 100644 --- a/frontend/urls.py +++ b/frontend/urls.py @@ -17,6 +17,7 @@ urlpatterns = patterns( name="privacy"), url(r"^rightsholders/$", TemplateView.as_view(template_name="rhtools.html"), name="rightsholders"), + url(r"^rightsholders/claim/$", "claim", name="claim"), url(r"^rh_admin/$", "rh_admin", name="rh_admin"), url(r"^faq/$", TemplateView.as_view(template_name="faq.html"), name="faq"), diff --git a/frontend/views.py b/frontend/views.py index 8069b67a..6dcbe9e4 100755 --- a/frontend/views.py +++ b/frontend/views.py @@ -26,7 +26,7 @@ from regluit.core import models, bookloader from regluit.core import userlists from regluit.core.search import gluejar_search from regluit.core.goodreads import GoodreadsClient -from regluit.frontend.forms import UserData, ProfileForm, CampaignPledgeForm, GoodreadsShelfLoadingForm, RightsHolderForm +from regluit.frontend.forms import UserData, ProfileForm, CampaignPledgeForm, GoodreadsShelfLoadingForm, RightsHolderForm, ClaimForm from regluit.payment.manager import PaymentManager from regluit.payment.parameters import TARGET_TYPE_CAMPAIGN @@ -53,6 +53,8 @@ def stub(request): def work(request, work_id, action='display'): work = get_object_or_404(models.Work, id=work_id) campaign = work.last_campaign() + + claimform = ClaimForm(data={'work':work_id, 'user':request.user.id }) if campaign: q = Q(campaign=campaign) | Q(campaign__isnull=True) premiums = models.Premium.objects.filter(q) @@ -61,15 +63,20 @@ def work(request, work_id, action='display'): if action == 'setup_campaign': return render(request, 'setup_campaign.html', {'work': work}) else: - return render(request, 'work.html', {'work': work, 'premiums': premiums, 'ungluers': userlists.supporting_users(work, 5)}) + return render(request, 'work.html', { + 'work': work, + 'premiums': premiums, + 'ungluers': userlists.supporting_users(work, 5), + 'claimform': claimform, + }) def workstub(request, title, imagebase, image, author, googlebooks_id, action='display'): - premiums = None - title = urllib.unquote_plus(title) - imagebase = urllib.unquote_plus(imagebase) - image = urllib.unquote_plus(image) - author = urllib.unquote_plus(author) - return render(request, 'workstub.html', {'title': title, 'image': image, 'imagebase': imagebase, 'author': author, 'googlebooks_id': googlebooks_id, 'premiums': premiums, 'ungluers': userlists.other_users(supporter, 5)}) + premiums = None + title = urllib.unquote_plus(title) + imagebase = urllib.unquote_plus(imagebase) + image = urllib.unquote_plus(image) + author = urllib.unquote_plus(author) + return render(request, 'workstub.html', {'title': title, 'image': image, 'imagebase': imagebase, 'author': author, 'googlebooks_id': googlebooks_id, 'premiums': premiums, 'ungluers': userlists.other_users(supporter, 5)}) def subjects(request): order = request.GET.get('order') @@ -100,6 +107,22 @@ def pledge(request,work_id): return render(request,'pledge.html',{'work':work,'campaign':campaign, 'premiums':premiums, 'form':form}) +def claim(request): + if request.method == 'GET': + data = request.GET + else: + data = request.POST + form = ClaimForm(data=data) + if form.is_valid(): + if not models.Claim.objects.filter(work=data['work'], rights_holder=data['rights_holder']).count(): + form.save() + return HttpResponseRedirect(reverse('work', kwargs={'work_id': data['work']})) + else: + work = models.Work.objects.get(id=data['work']) + rights_holder = models.RightsHolder.objects.get(id=data['rights_holder']) + context = {'form': form, 'work': work, 'rights_holder':rights_holder } + return render(request, "claim.html", context) + def rh_admin(request): if not is_admin(request.user): return render(request, "admins_only.html") @@ -225,9 +248,9 @@ def search(request): # also urlencode some parameters we'll need to pass to workstub in the title links # needs to be done outside the if condition for result in results: - result['urlimage'] = urllib.quote_plus(sub('^https?:\/\/','', result['image']).encode("utf-8"), safe='') - result['urlauthor'] = urllib.quote_plus(result['author'].encode("utf-8"), safe='') - result['urltitle'] = urllib.quote_plus(result['title'].encode("utf-8"), safe='') + result['urlimage'] = urllib.quote_plus(sub('^https?:\/\/','', result['image']).encode("utf-8"), safe='') + result['urlauthor'] = urllib.quote_plus(result['author'].encode("utf-8"), safe='') + result['urltitle'] = urllib.quote_plus(result['title'].encode("utf-8"), safe='') context = { "q": q, diff --git a/requirements.pip b/requirements.pip index 7ab660d6..acd72259 100644 --- a/requirements.pip +++ b/requirements.pip @@ -16,4 +16,3 @@ oauth2 mechanize pyzotero freebase -lxml \ No newline at end of file diff --git a/settings/prod.py b/settings/prod.py index c9243533..9e20dfca 100644 --- a/settings/prod.py +++ b/settings/prod.py @@ -17,8 +17,8 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'unglueit_dev', - 'USER': 'unglueit_dev', - 'PASSWORD': 'unglu3it', + 'USER': 'please', + 'PASSWORD': 'unglueit', 'HOST': 'gluejardb.cboagmr25pjs.us-east-1.rds.amazonaws.com', 'PORT': '', } @@ -88,5 +88,3 @@ BROKER_TRANSPORT = "redis" BROKER_HOST = "localhost" BROKER_PORT = 6379 BROKER_VHOST = "0" - -