From 360d11f88a4afbdcb2128d664d8c10bcc26411d5 Mon Sep 17 00:00:00 2001 From: eric Date: Fri, 23 Mar 2012 11:09:51 -0400 Subject: [PATCH 1/7] yes we should deprecate setup_work --- frontend/urls.py | 2 -- frontend/views.py | 30 +++++++++++++----------------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/frontend/urls.py b/frontend/urls.py index f147bd28..c89c500d 100644 --- a/frontend/urls.py +++ b/frontend/urls.py @@ -44,8 +44,6 @@ urlpatterns = patterns( url(r"^work/(?P\d+)/goodreads/$", "work_goodreads", name="work_goodreads"), url(r"^work/(?P\d+)/openlibrary/$", "work_openlibrary", name="work_openlibrary"), url(r"^googlebooks/(?P.+)/$", "googlebooks", name="googlebooks"), - #may want to deprecate the following - url(r"^setup/work/(?P\d+)/$", "work", {'action':'setup_campaign'}, name="setup_campaign"), url(r"^pledge/(?P\d+)/$", login_required(PledgeView.as_view()), name="pledge"), url(r"^pledge/cancel/$", login_required(PledgeCancelView.as_view()), name="pledge_cancel"), url(r"^pledge/complete/$", login_required(PledgeCompleteView.as_view()), name="pledge_complete"), diff --git a/frontend/views.py b/frontend/views.py index 10bd005e..631e8b99 100755 --- a/frontend/views.py +++ b/frontend/views.py @@ -164,23 +164,19 @@ def work(request, work_id, action='display'): base_url = request.build_absolute_uri("/")[:-1] - #may want to deprecate the following - 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), - 'claimform': claimform, - 'wishers': wishers, - 'base_url': base_url, - 'editions': editions, - 'pubdate': pubdate, - 'pledged':pledged, - 'activetab': activetab, - 'alert':alert - }) + return render(request, 'work.html', { + 'work': work, + 'premiums': premiums, + 'ungluers': userlists.supporting_users(work, 5), + 'claimform': claimform, + 'wishers': wishers, + 'base_url': base_url, + 'editions': editions, + 'pubdate': pubdate, + 'pledged':pledged, + 'activetab': activetab, + 'alert':alert + }) def manage_campaign(request, id): campaign = get_object_or_404(models.Campaign, id=id) From 137c48a70d4ceb1e80bf57b754e3b503d248c38e Mon Sep 17 00:00:00 2001 From: eric Date: Fri, 23 Mar 2012 11:10:34 -0400 Subject: [PATCH 2/7] setup campaign, I mean --- frontend/templates/setup_campaign.html | 35 -------------------------- 1 file changed, 35 deletions(-) delete mode 100644 frontend/templates/setup_campaign.html diff --git a/frontend/templates/setup_campaign.html b/frontend/templates/setup_campaign.html deleted file mode 100644 index 4a747c0e..00000000 --- a/frontend/templates/setup_campaign.html +++ /dev/null @@ -1,35 +0,0 @@ -{% extends "basedocumentation.html" %} - -{% block title %}Campaign Setup{% endblock %} - -{% block doccontent %} - -

Set up campaign

-
-

Title: {{ work.title }}

-

Authors: {{ work.author }}

-

Published: {{ work.publication_date }}

-

Language: {{ work.editions.all.0.language }}

-
-
- -

Description of the work to be offered

-This should include: -
    -
  • A synopsis of the work. -
  • Hyperlinks for the author(s), publisher making the offer, or for the work itself. -
- -

Offer details

-This should include: -
    -
  • Details about the edition being offered. -
  • Hyperlinks for the author(s), publisher making the offer, or for the work itself. -
- - -
- -{% endblock %} \ No newline at end of file From 0aba595e050648b9a99f4ac54de260c88e5c4730 Mon Sep 17 00:00:00 2001 From: eric Date: Fri, 23 Mar 2012 11:11:43 -0400 Subject: [PATCH 3/7] campaign admin broken by missing jquery --- frontend/templates/campaign_admin.html | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/templates/campaign_admin.html b/frontend/templates/campaign_admin.html index 8db0b88b..13283ca6 100644 --- a/frontend/templates/campaign_admin.html +++ b/frontend/templates/campaign_admin.html @@ -3,6 +3,7 @@ {% block extra_extra_head %} {{ form.media.css }} + {{ form.media.js }} {% endblock %} From 2c0fb79da58edf6de22036064c9ccdb27b008fad Mon Sep 17 00:00:00 2001 From: eric Date: Fri, 23 Mar 2012 11:13:11 -0400 Subject: [PATCH 4/7] minor touchups for rh admin --- frontend/templates/campaign_admin.html | 2 +- frontend/templates/manage_campaign.html | 4 ++-- frontend/templates/rh_tools.html | 11 ++++++----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/frontend/templates/campaign_admin.html b/frontend/templates/campaign_admin.html index 13283ca6..cbb77c63 100644 --- a/frontend/templates/campaign_admin.html +++ b/frontend/templates/campaign_admin.html @@ -22,7 +22,7 @@ {% if campaigns_with_active_transactions %}
{% csrf_token %} -
    +
      {% for campaign in campaigns_with_active_transactions %}
    • {{campaign.id}} | {{campaign.name}}
    • {% endfor %} diff --git a/frontend/templates/manage_campaign.html b/frontend/templates/manage_campaign.html index b5f87e3d..5748cba2 100644 --- a/frontend/templates/manage_campaign.html +++ b/frontend/templates/manage_campaign.html @@ -34,7 +34,7 @@ Please fix the following before launching your campaign: {% csrf_token %}

      This will be displayed in the Campaign tab for your work. It's your main pitch to supporters. It should include:

      -
        +
        • A synopsis of the work.
        • Hyperlinks for the author(s), publisher making the offer, or for the work itself.
        • Anything especially appealing about the work or author: awards, embedded video (460px max), etc.
        • @@ -42,7 +42,7 @@ Please fix the following before launching your campaign: {{ form.description }}{{ form.description.errors }}

          Offer details

          This will be displayed on the Details tab for your work. It gives additional information for the highly curious. It should include:

          -
            +
            • Details about the edition being offered.
            • Hyperlinks for the author(s), publisher making the offer, or for the work itself.
            diff --git a/frontend/templates/rh_tools.html b/frontend/templates/rh_tools.html index e6dfa4e7..267ff41a 100644 --- a/frontend/templates/rh_tools.html +++ b/frontend/templates/rh_tools.html @@ -3,6 +3,7 @@ {% block extra_extra_head %} + @@ -118,13 +119,13 @@ Needs to be written. What would you find helpful in a social media toolkit? Campaigns have rewards as a way to thank supporters. unglue.it includes a standard set of rewards in all campaigns. You are encouraged to add additional sweeteners to motivate people to donate.

            Here are the standard rewards:

            -
              +
              • Any level — The unglued ebook delivered to your inbox
              • -
              • $25 — Your name under "supporters" in the acknowledgements section
              • -
              • $50 — Your name & link of your choice under "benefactors"
              • -
              • $100 — Your name, link of your choice, & a brief message (140 characters max) under "bibliophiles"
              • +
              • $25 — Your username under "supporters" in the acknowledgements section
              • +
              • $50 — Your name & profile link under "benefactors"
              • +
              • $100 — Your name, profile link, & profile tagline under "bibliophiles"

              More Questions

              - +

              Check the FAQ to the left, or Send us feedback. {% endblock %} \ No newline at end of file From 6237fcebfee8059cad7c5c5bb4589fcf170749f7 Mon Sep 17 00:00:00 2001 From: eric Date: Fri, 23 Mar 2012 11:15:37 -0400 Subject: [PATCH 5/7] detabbing views code --- frontend/views.py | 54 +++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/frontend/views.py b/frontend/views.py index 631e8b99..9a7db63d 100755 --- a/frontend/views.py +++ b/frontend/views.py @@ -67,32 +67,32 @@ def slideshow(max): # on the preview site there are no active campaigns, so we should show most-wished books instead worklist = models.Work.objects.order_by('-num_wishes')[:max] else: - worklist = [] - if max > count: - # add all the works with active campaigns - for campaign in ending: - worklist.append(campaign.work) - - # then fill out the rest of the list with popular but inactive works - remainder = max - count - remainder_works = models.Work.objects.exclude(campaigns__status='ACTIVE').order_by('-num_wishes')[:remainder] - worklist.extend(remainder_works) + worklist = [] + if max > count: + # add all the works with active campaigns + for campaign in ending: + worklist.append(campaign.work) + + # then fill out the rest of the list with popular but inactive works + remainder = max - count + remainder_works = models.Work.objects.exclude(campaigns__status='ACTIVE').order_by('-num_wishes')[:remainder] + worklist.extend(remainder_works) else: - # if the active campaign list has more works than we can fit - # in our slideshow, it's the only source we need to draw from - while j < max: - worklist.append(ending[j].work) - j +=1 - + # if the active campaign list has more works than we can fit + # in our slideshow, it's the only source we need to draw from + while j < max: + worklist.append(ending[j].work) + j +=1 + return worklist def next(request): - if request.COOKIES.has_key('next'): - response = HttpResponseRedirect(urllib.unquote(request.COOKIES['next'])) - response.delete_cookie('next') - return response - else: - return HttpResponseRedirect('/') + if request.COOKIES.has_key('next'): + response = HttpResponseRedirect(urllib.unquote(request.COOKIES['next'])) + response.delete_cookie('next') + return response + else: + return HttpResponseRedirect('/') def home(request): if request.user.is_authenticated(): @@ -1542,19 +1542,19 @@ def emailshare(request): title = book.title # if title requires unicode let's ignore it for now try: - title = ', '+str(title)+', ' + title = ', '+str(title)+', ' except: - title = ' ' + title = ' ' try: - status = book.last_campaign().status + status = book.last_campaign().status except: - status = None + status = None # customize the call to action depending on campaign status if status == 'ACTIVE': message = 'Help me unglue one of my favorite books'+title+'on Unglue.It: '+next+'. If enough of us pledge to unglue this book, the creator will be paid and the ebook will become free to everyone on earth.' else: - message = 'Help me unglue one of my favorite books'+title+'on Unglue.It: '+next+'. If enough of us wishlist this book, Unglue.It may start a campaign to pay the creator and make the ebook free to everyone on earth.' + message = 'Help me unglue one of my favorite books'+title+'on Unglue.It: '+next+'. If enough of us wishlist this book, Unglue.It may start a campaign to pay the creator and make the ebook free to everyone on earth.' form = EmailShareForm(initial={'next':next, 'subject': 'Come see one of my favorite books on Unglue.It', 'message': message}) except: next = '' From e4fc2621df0e09edd821c50ea34b740dd7e06e7f Mon Sep 17 00:00:00 2001 From: eric Date: Fri, 23 Mar 2012 12:29:38 -0400 Subject: [PATCH 6/7] fixed form broken by change to TZ aware times --- frontend/forms.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/forms.py b/frontend/forms.py index 47d5632f..0916b0e9 100644 --- a/frontend/forms.py +++ b/frontend/forms.py @@ -14,7 +14,7 @@ from selectable.forms import AutoCompleteSelectWidget,AutoCompleteSelectField from regluit.core.models import UserProfile, RightsHolder, Claim, Campaign, Premium, Ebook from regluit.core.lookups import OwnerLookup -from regluit.utils.localdatetime import date_today +from regluit.utils.localdatetime import now import logging @@ -160,9 +160,9 @@ class ManageCampaignForm(forms.ModelForm): if self.instance: if self.instance.status == 'ACTIVE' and self.instance.deadline != new_deadline: raise forms.ValidationError(_('The closing date for an ACTIVE campaign cannot be changed.')) - if new_deadline-date_today() > timedelta(days=int(settings.UNGLUEIT_LONGEST_DEADLINE)): + if new_deadline - now() > timedelta(days=int(settings.UNGLUEIT_LONGEST_DEADLINE)): raise forms.ValidationError(_('The chosen closing date is more than %s days from now' % settings.UNGLUEIT_LONGEST_DEADLINE)) - elif new_deadline-date_today() < timedelta(days=int(settings.UNGLUEIT_SHORTEST_DEADLINE)): + elif new_deadline - now() < timedelta(days=int(settings.UNGLUEIT_SHORTEST_DEADLINE)): raise forms.ValidationError(_('The chosen closing date is less than %s days from now' % settings.UNGLUEIT_SHORTEST_DEADLINE)) return new_deadline From 0f61bd8d665a029eda41d69d1e8ff785641bd7a6 Mon Sep 17 00:00:00 2001 From: eric Date: Fri, 23 Mar 2012 12:30:49 -0400 Subject: [PATCH 7/7] added license selection to campaigns. Simple migration to apply. --- ...d_campaign_license__chg_field_ebook_url.py | 222 ++++++++++++++++++ core/models.py | 9 + frontend/forms.py | 10 +- frontend/templates/manage_campaign.html | 3 + frontend/templates/work.html | 2 +- 5 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 core/migrations/0027_auto__add_field_campaign_license__chg_field_ebook_url.py diff --git a/core/migrations/0027_auto__add_field_campaign_license__chg_field_ebook_url.py b/core/migrations/0027_auto__add_field_campaign_license__chg_field_ebook_url.py new file mode 100644 index 00000000..b5a227f6 --- /dev/null +++ b/core/migrations/0027_auto__add_field_campaign_license__chg_field_ebook_url.py @@ -0,0 +1,222 @@ +# 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 'Campaign.license' + db.add_column('core_campaign', 'license', self.gf('django.db.models.fields.CharField')(default='CC BY-NC-ND', max_length=255), keep_default=False) + + # Changing field 'Ebook.url' + db.alter_column('core_ebook', 'url', self.gf('django.db.models.fields.URLField')(max_length=1024)) + + + def backwards(self, orm): + + # Deleting field 'Campaign.license' + db.delete_column('core_campaign', 'license') + + # Changing field 'Ebook.url' + db.alter_column('core_ebook', 'url', self.gf('django.db.models.fields.CharField')(max_length=1024)) + + + 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'}), + 'details': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'left': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}), + 'license': ('django.db.models.fields.CharField', [], {'default': "'CC BY-NC-ND'", 'max_length': '255'}), + 'managers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'campaigns'", 'symmetrical': 'False', 'to': "orm['auth.User']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}), + 'paypal_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'INITIALIZED'", 'max_length': '15', 'null': 'True'}), + 'target': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '14', 'decimal_places': '2'}), + 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'to': "orm['core.Work']"}) + }, + 'core.campaignaction': { + 'Meta': {'object_name': 'CampaignAction'}, + 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['core.Campaign']"}), + 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '15'}) + }, + 'core.celerytask': { + 'Meta': {'object_name': 'CeleryTask'}, + 'active': ('django.db.models.fields.NullBooleanField', [], {'default': 'True', 'null': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 3, 23, 12, 0, 53, 181728)', 'auto_now_add': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'null': 'True'}), + 'function_args': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'function_name': ('django.db.models.fields.CharField', [], {'max_length': '1024'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'task_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tasks'", 'null': 'True', 'to': "orm['auth.User']"}) + }, + 'core.claim': { + 'Meta': {'object_name': 'Claim'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'rights_holder': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['core.RightsHolder']"}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '7'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['auth.User']"}), + 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claim'", 'to': "orm['core.Work']"}) + }, + 'core.ebook': { + 'Meta': {'object_name': 'Ebook'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'edition': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ebooks'", 'to': "orm['core.Edition']"}), + 'format': ('django.db.models.fields.CharField', [], {'max_length': '25'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'provider': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'rights': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '1024'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}) + }, + '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'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'public_domain': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'publication_date': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}), + 'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + '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.identifier': { + 'Meta': {'unique_together': "(('type', 'value'),)", 'object_name': 'Identifier'}, + 'edition': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'identifiers'", 'null': 'True', 'to': "orm['core.Edition']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '4'}), + 'value': ('django.db.models.fields.CharField', [], {'max_length': '31'}), + 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'identifiers'", 'to': "orm['core.Work']"}) + }, + 'core.premium': { + 'Meta': {'object_name': 'Premium'}, + 'amount': ('django.db.models.fields.DecimalField', [], {'max_digits': '10', 'decimal_places': '0'}), + 'campaign': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'premiums'", 'null': 'True', 'to': "orm['core.Campaign']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '2'}) + }, + 'core.rightsholder': { + 'Meta': {'object_name': 'RightsHolder'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'email': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rights_holder'", 'to': "orm['auth.User']"}), + 'rights_holder_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}) + }, + 'core.subject': { + 'Meta': {'ordering': "['name']", 'object_name': 'Subject'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}), + 'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subjects'", 'symmetrical': 'False', 'to': "orm['core.Work']"}) + }, + 'core.userprofile': { + 'Meta': {'object_name': 'UserProfile'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'facebook_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), + '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'}), + 'librarything_id': ('django.db.models.fields.CharField', [], {'max_length': '31', 'blank': 'True'}), + 'pic_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': '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.waswork': { + 'Meta': {'object_name': 'WasWork'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'moved': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'was': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}), + 'work': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Work']"}) + }, + 'core.wishes': { + 'Meta': {'object_name': 'Wishes', 'db_table': "'core_wishlist_works'"}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'source': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}), + 'wishlist': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Wishlist']"}), + 'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'wishes'", 'to': "orm['core.Work']"}) + }, + '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', 'through': "orm['core.Wishes']", 'to': "orm['core.Work']"}) + }, + 'core.work': { + 'Meta': {'ordering': "['title']", 'object_name': 'Work'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'language': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '2'}), + 'num_wishes': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'openlibrary_lookup': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}) + } + } + + complete_apps = ['core'] diff --git a/core/models.py b/core/models.py index 89583747..55735b57 100755 --- a/core/models.py +++ b/core/models.py @@ -81,11 +81,20 @@ class CampaignAction(models.Model): campaign = models.ForeignKey("Campaign", related_name="actions", null=False) class Campaign(models.Model): + LICENSE_CHOICES = (('CC BY-NC-ND','CC BY-NC-ND'), + ('CC BY-ND','CC BY-ND'), + ('CC BY','CC BY'), + ('CC BY-NC','CC BY-NC'), + ( 'CC BY-NC-SA','CC BY-NC-SA'), + ( 'CC BY-SA','CC BY-SA'), + ( 'CC0','CC0'), + ) created = models.DateTimeField(auto_now_add=True) name = models.CharField(max_length=500, null=True, blank=False) description = models.TextField(null=True, blank=False) details = models.TextField(null=True, blank=False) target = models.DecimalField(max_digits=14, decimal_places=2, null=True, blank=False) + license = models.CharField(max_length=255, choices = LICENSE_CHOICES, default='CC BY-NC-ND') left = models.DecimalField(max_digits=14, decimal_places=2, null=True, blank=False) deadline = models.DateTimeField() activated = models.DateTimeField(null=True) diff --git a/frontend/forms.py b/frontend/forms.py index 0916b0e9..1adacf08 100644 --- a/frontend/forms.py +++ b/frontend/forms.py @@ -139,7 +139,7 @@ class ManageCampaignForm(forms.ModelForm): target = forms.DecimalField( min_value= D('0.00') ) class Meta: model = Campaign - fields = 'description', 'details', 'target', 'deadline', 'paypal_receiver' + fields = 'description', 'details', 'license', 'target', 'deadline', 'paypal_receiver' widgets = { 'description': forms.Textarea(attrs={'cols': 80, 'rows': 20}), 'details': forms.Textarea(attrs={'cols': 80, 'rows': 20}), @@ -165,6 +165,14 @@ class ManageCampaignForm(forms.ModelForm): elif new_deadline - now() < timedelta(days=int(settings.UNGLUEIT_SHORTEST_DEADLINE)): raise forms.ValidationError(_('The chosen closing date is less than %s days from now' % settings.UNGLUEIT_SHORTEST_DEADLINE)) return new_deadline + + def clean_license(self): + new_license = self.cleaned_data['license'] + if self.instance: + if self.instance.status == 'ACTIVE': + raise forms.ValidationError(_('The license for an ACTIVE campaign cannot be changed.')) + return new_license + class CampaignPledgeForm(forms.Form): preapproval_amount = forms.DecimalField( diff --git a/frontend/templates/manage_campaign.html b/frontend/templates/manage_campaign.html index 5748cba2..9bf55c62 100644 --- a/frontend/templates/manage_campaign.html +++ b/frontend/templates/manage_campaign.html @@ -50,6 +50,9 @@ Please fix the following before launching your campaign:

              Target Price

              This is the target price for your campaign. Once you launch the campaign, you won't be able to increase it.

              {{ form.target }}{{ form.target.errors }} +

              License being offered

              +

              This is the license you are offering to use once the campaign succeeds. For more info on the licenses you can use, see Creative Commons

              +{{ form.license }}{{ form.license.errors }}

              Ending date

              This is the ending date of your campaign. Once you launch the campaign, you won't be able to change it. The ending date can't be more than six months away- that's a practical limit for credit card authorizations.

              diff --git a/frontend/templates/work.html b/frontend/templates/work.html index 4a6dbedb..462f370f 100644 --- a/frontend/templates/work.html +++ b/frontend/templates/work.html @@ -197,7 +197,7 @@ $j(document).ready(function(){ {{ claim.rights_holder.rights_holder_name }} {% endif %} {% endfor %} - , has agreed to release {{work.title}} to the world as a Creative Commons licensed ebook if ungluers can join together to raise ${{ work.last_campaign.target }} by {{ work.last_campaign.deadline }}. + , has agreed to release {{work.title}} to the world as a Creative Commons licensed ebook ({{ work.last_campaign.license }}) if ungluers can join together to raise ${{ work.last_campaign.target }} by {{ work.last_campaign.deadline }}. You can help!

              {{ work.last_campaign.description|safe }} {% else %}