merge all the things
commit
1a53a79752
|
@ -1,8 +1,10 @@
|
|||
from django.contrib.auth.models import User
|
||||
from django.contrib.syndication.views import Feed
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.feedgenerator import Atom1Feed
|
||||
|
||||
class SupporterWishlistFeed(Feed):
|
||||
feed_type = Atom1Feed
|
||||
def get_object(self, request, supporter):
|
||||
return get_object_or_404(User, username=supporter)
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
"campaign": null,
|
||||
"amount": 50,
|
||||
"type": "00",
|
||||
"description": "Your name and link of your choice under \"benefactors\"",
|
||||
"description": "Your name and profile URL of your choice under \"benefactors\"",
|
||||
"created": "2011-11-17 22:03:37"
|
||||
}
|
||||
},
|
||||
|
@ -71,7 +71,7 @@
|
|||
"campaign": null,
|
||||
"amount": 100,
|
||||
"type": "00",
|
||||
"description": "Your name, link of your choice, and a brief message (140 characters max) under \"bibliophiles\"",
|
||||
"description": "Your name, profile URL, and profile tagline under \"bibliophiles\"",
|
||||
"created": "2011-11-17 22:03:37"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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']
|
|
@ -0,0 +1,217 @@
|
|||
# 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 'Premium.limit'
|
||||
db.add_column('core_premium', 'limit', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting field 'Premium.limit'
|
||||
db.delete_column('core_premium', 'limit')
|
||||
|
||||
|
||||
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, 26, 14, 33, 44, 667768)', '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'}),
|
||||
'limit': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'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']
|
|
@ -66,12 +66,13 @@ class RightsHolder(models.Model):
|
|||
return self.rights_holder_name
|
||||
|
||||
class Premium(models.Model):
|
||||
PREMIUM_TYPES = ((u'00', u'Default'),(u'CU', u'Custom'))
|
||||
PREMIUM_TYPES = ((u'00', u'Default'),(u'CU', u'Custom'),(u'XX', u'Inactive'))
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
type = models.CharField(max_length=2, choices=PREMIUM_TYPES)
|
||||
campaign = models.ForeignKey("Campaign", related_name="premiums", null=True)
|
||||
amount = models.DecimalField(max_digits=10, decimal_places=0, blank=False)
|
||||
description = models.TextField(null=True, blank=False)
|
||||
limit = models.IntegerField(default = 0)
|
||||
|
||||
class CampaignAction(models.Model):
|
||||
timestamp = models.DateTimeField(auto_now_add=True)
|
||||
|
@ -81,11 +82,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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -131,6 +131,18 @@ class OpenCampaignForm(forms.ModelForm):
|
|||
fields = 'name', 'work', 'managers'
|
||||
widgets = { 'work': forms.HiddenInput }
|
||||
|
||||
class CustomPremiumForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = Premium
|
||||
fields = 'campaign', 'amount', 'description', 'type', 'limit'
|
||||
widgets = {
|
||||
'description': forms.Textarea(attrs={'cols': 80, 'rows': 2}),
|
||||
'campaign': forms.HiddenInput,
|
||||
'type': forms.HiddenInput(attrs={'value':'XX'}),
|
||||
'limit': forms.TextInput(attrs={'value':'0'}),
|
||||
}
|
||||
|
||||
class ManageCampaignForm(forms.ModelForm):
|
||||
paypal_receiver = forms.EmailField(
|
||||
label=_("email address to collect Paypal funds"),
|
||||
|
@ -139,7 +151,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}),
|
||||
|
@ -160,11 +172,19 @@ 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
|
||||
|
||||
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(
|
||||
|
@ -183,6 +203,10 @@ class CampaignPledgeForm(forms.Form):
|
|||
if data is None:
|
||||
raise forms.ValidationError(_("Please enter a pledge amount."))
|
||||
return data
|
||||
|
||||
# should we do validation on the premium_id here?
|
||||
# can see whether it corresponds to a real premium -- do that here?
|
||||
# can also figure out moreover whether it's one of the allowed premiums for that campaign....
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = self.cleaned_data
|
||||
|
@ -193,6 +217,7 @@ class CampaignPledgeForm(forms.Form):
|
|||
premium_amount = Premium.objects.get(id=premium_id).amount
|
||||
logger.info("preapproval_amount: {0}, premium_id: {1}, premium_amount:{2}".format(preapproval_amount, premium_id, premium_amount))
|
||||
if preapproval_amount < premium_amount:
|
||||
logger.info("raising form validating error")
|
||||
raise forms.ValidationError(_("Sorry, you must pledge at least $%s to select that premium." % (premium_amount)))
|
||||
except Exception, e:
|
||||
if isinstance(e, forms.ValidationError):
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
{% extends "basedocumentation.html" %}
|
||||
{% block base_js %}{% endblock %}
|
||||
|
||||
{% block extra_extra_head %}
|
||||
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/ui-lightness/jquery-ui.css" type="text/css" media="screen">
|
||||
{{ form.media.css }}
|
||||
<script type="text/javascript" src="{{ jquery_home }}"></script>
|
||||
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
|
||||
{{ form.media.js }}
|
||||
{% endblock %}
|
||||
|
@ -21,7 +22,7 @@
|
|||
{% if campaigns_with_active_transactions %}
|
||||
<form method="post" action="#">
|
||||
{% csrf_token %}
|
||||
<ul>
|
||||
<ul class="terms">
|
||||
{% for campaign in campaigns_with_active_transactions %}
|
||||
<li><input type="radio" name="active_campaign" value="{{campaign.id}}" />{{campaign.id}} | {{campaign.name}} </li>
|
||||
{% endfor %}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
<h3> Terms and Conditions for Claiming Works </h3>
|
||||
|
||||
<pre>[legal stuff]</pre>
|
||||
<p>By claiming this work, you agree that your claim is governed by a Platform Services Agreement in effect between you (or an entity that you act as agent for) and Gluejar, Inc., the operator of the Unglue.it website, and by the <a href="{% url terms %}">unglue.it website terms and conditions</a>.</p>
|
|
@ -243,7 +243,7 @@ If you want to find an interesting campaign and don't have a specific book in mi
|
|||
<dt>Are premiums required?</dt>
|
||||
|
||||
<dd>Yes. All campaigns have a required set of premiums, as follows:<br /><br />
|
||||
<ul>
|
||||
<ul class="terms">
|
||||
<li>$1 // The unglued ebook delivered to your inbox.</li>
|
||||
<li>$25 // Your name under "supporters" in the acknowledgements section.</li>
|
||||
<li>$50 // Your name and link of your choice under "benefactors"</li>
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
</script>
|
||||
|
||||
<script type="text/javascript" src="/static/js/definitions.js"></script>
|
||||
<script type="text/javascript" src="/static/js/wishlist.js"></script>
|
||||
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
|
||||
<script type="text/javascript" src="/static/js/highlight_signup.js"></script>
|
||||
<script src="/static/js/slides.min.jquery.js"></script>
|
||||
|
|
|
@ -34,7 +34,7 @@ Please fix the following before launching your campaign:
|
|||
<form action="#" method="POST">
|
||||
{% csrf_token %}
|
||||
<p>This will be displayed in the Campaign tab for your work. It's your main pitch to supporters. It should include:</p>
|
||||
<ul>
|
||||
<ul class="terms">
|
||||
<li>A synopsis of the work.</li>
|
||||
<li>Hyperlinks for the author(s), publisher making the offer, or for the work itself.</li>
|
||||
<li>Anything especially appealing about the work or author: awards, embedded video (460px max), etc.</li>
|
||||
|
@ -42,7 +42,7 @@ Please fix the following before launching your campaign:
|
|||
{{ form.description }}{{ form.description.errors }}
|
||||
<h3>Offer details</h2>
|
||||
<p>This will be displayed on the Details tab for your work. It gives additional information for the highly curious. It should include:</p>
|
||||
<ul>
|
||||
<ul class="terms">
|
||||
<li>Details about the edition being offered.</li>
|
||||
<li>Hyperlinks for the author(s), publisher making the offer, or for the work itself.</li>
|
||||
</uL>
|
||||
|
@ -50,6 +50,9 @@ Please fix the following before launching your campaign:
|
|||
<h3>Target Price</h2>
|
||||
<p> This is the target price for your campaign. Once you launch the campaign, you won't be able to increase it.</p>
|
||||
{{ form.target }}{{ form.target.errors }}
|
||||
<h3>License being offered</h2>
|
||||
<p> This is the license you are offering to use once the campaign succeeds. For more info on the licenses you can use, see <a href="http://creativecommons.org/">Creative Commons</a></p>
|
||||
{{ form.license }}{{ form.license.errors }}
|
||||
<h3>Ending date</h2>
|
||||
<p> 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.</p>
|
||||
|
@ -65,5 +68,37 @@ The ending date can't be more than six months away- that's a practical limit for
|
|||
<input type="submit" name="launch" value="Launch Campaign" />
|
||||
</form>
|
||||
|
||||
<h3>Premiums</h3>
|
||||
<div class="jsmod-content">
|
||||
<form action="#" method="POST">
|
||||
{% csrf_token %}
|
||||
<ul class="support menu">
|
||||
{% for premium in premiums %}
|
||||
<li class="{% if forloop.first %}first{% else %}{% if forloop.last %}last{% endif %}{% endif %}">
|
||||
<a href="{% url pledge work_id=campaign.work.id %}?premium_id={{premium.id}}">
|
||||
<span class="menu-item-price">${{ premium.amount }}</span>
|
||||
<span class="menu-item-desc">{{ premium.description }}</span>
|
||||
</a>
|
||||
{% if premium.type %}<span class="custom-premium"> <br />Type: {{ premium.get_type_display }}</span>{% endif %}
|
||||
{% ifnotequal premium.limit 0 %}<br />Limit: {{ premium.limit }}{% endifnotequal %}
|
||||
{% ifequal premium.type 'CU' %}<br />Deactivate? <input type="checkbox" name="premium_id" value="{{ premium.id }}" />{% endifequal %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<input type="submit" name="inactivate" value="Inactivate Checked Premiums" />
|
||||
</form>
|
||||
</div>
|
||||
<h4>Add a custom premium for this campaign</h4>
|
||||
<form action="#" method="POST">
|
||||
{% csrf_token %}
|
||||
Pledge Amount: {{ premium_form.amount }}{{ premium_form.amount.errors }}<br />
|
||||
Premium Description: {{ premium_form.description }}{{ premium_form.description.errors }}<br />
|
||||
Number Available (0 if no limit): {{ premium_form.limit }}{{ premium_form.limit.errors }}<br />
|
||||
{{ premium_form.campaign }}
|
||||
{{ premium_form.type }}{{ premium_form.type.errors }}
|
||||
<br />
|
||||
<input type="submit" name="add_premium" value="Add Premium" />
|
||||
</form>
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -6,9 +6,9 @@
|
|||
<dl>
|
||||
<dt> How many ungluers have registered?</dt>
|
||||
<dd>
|
||||
<ul>
|
||||
<ul class="terms">
|
||||
<li>{{ users.today.count }} have registered today. {% if users.today.count %}They are
|
||||
<ul>{% for user in users.today %}
|
||||
<ul class="terms">{% for user in users.today %}
|
||||
<li><a href="{% url supporter user.username %}">{{user.username}}</a></li>
|
||||
{% endfor %}</ul>{% endif %}
|
||||
<br />{{ wishlists.today.count }} of them have 1 or more items on a wishlist.
|
||||
|
@ -26,7 +26,7 @@
|
|||
<br />{{ wishlists.all.count }} of them have 1 or more items on a wishlist.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<ul class="terms">
|
||||
<li> {{ users.gr.count }} ungluers are connected to GoodReads.</li>
|
||||
<li> {{ users.lt.count }} ungluers are connected to LibraryThing.</li>
|
||||
<li> {{ users.fb.count }} ungluers are connected to FaceBook.</li>
|
||||
|
@ -38,9 +38,9 @@
|
|||
<dl>
|
||||
<dt> How many works have been added to Unglue.it?</dt>
|
||||
<dd>
|
||||
<ul>
|
||||
<ul class="terms">
|
||||
<li>{{ works.today.count }} have been added today. {% if works.today.count %}They are
|
||||
<ul>{% for work in works.today %}
|
||||
<ul class="terms">{% for work in works.today %}
|
||||
<li><a href="{% url work work.id %}">{{work.title}}</a></li>
|
||||
{% endfor %}</ul>{% endif %}
|
||||
</li>
|
||||
|
@ -56,7 +56,7 @@
|
|||
</dd>
|
||||
<dt> How often have the works been wished?</dt>
|
||||
<dd>
|
||||
<ul>
|
||||
<ul class="terms">
|
||||
<li>{{ works.wishedby50.count }} have been wished by more than 50 ungluers.
|
||||
</li>
|
||||
<li>{{ works.wishedby20.count }} have been wished by more than 20 ungluers.
|
||||
|
@ -74,9 +74,9 @@
|
|||
<dl>
|
||||
<dt> How many ebooks have been added to Unglue.it?</dt>
|
||||
<dd>
|
||||
<ul>
|
||||
<ul class="terms">
|
||||
<li>{{ ebooks.today.count }} have been added today. {% if ebooks.today.count %}They are
|
||||
<ul>{% for ebook in ebooks.today %}
|
||||
<ul class="terms">{% for ebook in ebooks.today %}
|
||||
<li><a href="{% url work ebook.edition.work.id %}">{{ebook.edition.work.title}}</a></li>
|
||||
{% endfor %}</ul>{% endif %}
|
||||
</li>
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
{% for premium in premiums %}
|
||||
<label for="{{premium.id}}">
|
||||
<li class="{% if forloop.first %}first{% else %}{% if forloop.last %}last{% endif %}{% endif %}">
|
||||
<input type="radio" name="premium_id" value="{{premium.id}}" id="{{premium.id}}" {% ifequal request.REQUEST.premium_id premium.id|stringformat:"s" %}checked="checked"{% endifequal %}" />
|
||||
<input type="radio" name="premium_id" value="{{premium.id}}" {% ifequal request.REQUEST.premium_id premium.id|stringformat:"s" %}checked="checked"{% endifequal %} />
|
||||
<span class="menu-item-price">
|
||||
${{ premium.amount }}
|
||||
</span>
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
{% extends "basepledge.html" %}
|
||||
|
||||
{% block title %}Pledge (Modify){% endblock %}
|
||||
|
||||
{% block extra_extra_head %}
|
||||
<link type="text/css" rel="stylesheet" href="/static/css/campaign.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/static/css/pledge.css" />
|
||||
{% endblock %}
|
||||
|
||||
{% block doccontent %}
|
||||
<div style="height:10px";></div>
|
||||
<div class="book-detail">
|
||||
<div class="book-detail-img">
|
||||
<a href="#"><img src="{{ work.cover_image_thumbnail }}" alt="{{ work.title }}" title="{{ work.title }}" width="131" height="192" /></a>
|
||||
</div>
|
||||
|
||||
<div class="book-detail-info">
|
||||
<h2 class="book-name">{{ work.title }}</h2>
|
||||
<h3 class="book-author">{{ work.author }}</h3>
|
||||
<h3 class="book-year">{{ work.publication_date }}</h3>
|
||||
|
||||
<div class="find-book">
|
||||
<label>Find it here</label>
|
||||
|
||||
<div class="find-link">
|
||||
<a class="find-google" href="{{ work.googlebooks_url }}"><img src="/static/images/supporter_icons/googlebooks_square.png" title="Find on Google Books" alt="Find on Google Books" /></a>
|
||||
<a rel="nofollow" class="find-openlibrary" href="{% url work_openlibrary work.id %}"><img src="/static/images/supporter_icons/openlibrary_square.png" title="Find on OpenLibrary" alt="Find on OpenLibrary"></a>
|
||||
|
||||
{% if not request.user.is_anonymous %}
|
||||
{% if request.user.profile.goodreads_user_link %}
|
||||
<a rel="nofollow" class="find-goodreads" href="{% url work_goodreads work.id %}"><img src="/static/images/supporter_icons/goodreads_square.png" title="Find on GoodReads" alt="Find on GoodReads"></a>
|
||||
{% endif %}
|
||||
{% if request.user.profile.librarything_id %}
|
||||
<a rel="nofollow" class="find-librarything" href="{% url work_librarything work.id %}"><img src="/static/images/supporter_icons/librarything_square.png" title="Find on LibraryThing" alt="Find on LibraryThing" /></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pledged-info">
|
||||
<div class="pledged-group">
|
||||
{{ work.last_campaign.supporters.count }} Ungluers have pledged ${{ work.last_campaign.current_total }}
|
||||
</div>
|
||||
<div class="status">
|
||||
<img src="/static/images/images/icon-book-37by25-{{ work.percent_unglued }}.png" title="book list status" alt="book list status" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="jsmodule rounded pledge">
|
||||
<div class="jsmod-content">
|
||||
${{ work.last_campaign.target }} needed by<br />
|
||||
{{ work.last_campaign.deadline }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="jsmodule rounded">
|
||||
<div class="jsmod-content">
|
||||
|
||||
<p>You modifying your current pledge.</p>
|
||||
{% comment %}
|
||||
Even there is a CampaignPledgeForm in frontend/forms.py , the "widget" for premium_id is implemented in HTML here for now.
|
||||
{% endcomment %}
|
||||
|
||||
<form method="POST" action="{% url pledge_modify work_id=work.id %}">
|
||||
{% csrf_token %}
|
||||
{{ form.non_field_errors }}
|
||||
{{ form.preapproval_amount.errors }}
|
||||
<div class="pledge_amount">{{ form.preapproval_amount.label_tag }}: ${{ form.preapproval_amount }}</div>
|
||||
{{ form.anonymous.errors }}
|
||||
|
||||
{% comment %}
|
||||
not supported yet; don't display
|
||||
{{ form.anonymous.label_tag }}: {{ form.anonymous }}
|
||||
{% endcomment %}
|
||||
|
||||
<ul class="support menu">
|
||||
{% for premium in premiums %}
|
||||
<label for="{{premium.id}}">
|
||||
<li class="{% if forloop.first %}first{% else %}{% if forloop.last %}last{% endif %}{% endif %}">
|
||||
<input type="radio" name="premium_id" value="{{premium.id}}" {% ifequal form.premium_id.value premium.id %}checked="checked"{% endifequal %} />
|
||||
<span class="menu-item-price">
|
||||
${{ premium.amount }}
|
||||
</span>
|
||||
<span class="menu-item-desc">
|
||||
{{ premium.description }}
|
||||
</span>
|
||||
</a></li></label>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<input type="submit" value="Modify Pledge" id="pledgesubmit"/>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
{% block extra_extra_head %}
|
||||
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/ui-lightness/jquery-ui.css" type="text/css" media="screen">
|
||||
<link href="/static/css/dj.selectable.css" type="text/css" media="all" rel="stylesheet" />
|
||||
<script type="text/javascript" src="{{ jquery_home }}"></script>
|
||||
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
|
||||
<script type="text/javascript" src="/static/js/jquery.dj.selectable.js"></script>
|
||||
|
||||
|
@ -118,13 +119,13 @@ Needs to be written. What would you find helpful in a social media toolkit? <a
|
|||
<p>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.</p>
|
||||
|
||||
<p>Here are the standard rewards:</p>
|
||||
<ul>
|
||||
<ul class="terms">
|
||||
<li><em>Any level</em> — The unglued ebook delivered to your inbox</li>
|
||||
<li><em>$25</em> — Your name under "supporters" in the acknowledgements section</li>
|
||||
<li><em>$50</em> — Your name & link of your choice under "benefactors"</li>
|
||||
<li><em>$100</em> — Your name, link of your choice, & a brief message (140 characters max) under "bibliophiles"</li>
|
||||
<li><em>$25</em> — Your username under "supporters" in the acknowledgements section</li>
|
||||
<li><em>$50</em> — Your name & profile link under "benefactors"</li>
|
||||
<li><em>$100</em> — Your name, profile link, & profile tagline under "bibliophiles"</li>
|
||||
</ul>
|
||||
|
||||
<h2>More Questions</h2>
|
||||
|
||||
<p> Check the FAQ to the left, or <a href="/feedback">Send us feedback.</a>
|
||||
{% endblock %}
|
|
@ -1,8 +1,9 @@
|
|||
{% extends "basedocumentation.html" %}
|
||||
{% block base_js %}{% endblock %}
|
||||
|
||||
{% block extra_extra_head %}
|
||||
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/ui-lightness/jquery-ui.css" type="text/css" media="screen">
|
||||
{{ form.media.css }}
|
||||
<script type="text/javascript" src="{{ jquery_home }}"></script>
|
||||
<script type="text/javascript" src="{{ jquery_ui_home }}" ></script>
|
||||
{{ form.media.js }}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
{% extends "basedocumentation.html" %}
|
||||
|
||||
{% block title %}Campaign Setup{% endblock %}
|
||||
|
||||
{% block doccontent %}
|
||||
|
||||
<h2>Set up campaign</h2>
|
||||
<div class="book-detail-info">
|
||||
<h2 class="book-name">Title: {{ work.title }}</h2>
|
||||
<h3 class="book-author">Authors: {{ work.author }}</h3>
|
||||
<h3 class="book-year">Published: {{ work.publication_date }}</h3>
|
||||
<h3 class="book-author">Language: {{ work.editions.all.0.language }}</h3>
|
||||
</div>
|
||||
<form action="#">
|
||||
|
||||
<h3>Description of the work to be offered</h3>
|
||||
This should include:
|
||||
<ul>
|
||||
<li>A synopsis of the work.
|
||||
<li>Hyperlinks for the author(s), publisher making the offer, or for the work itself.
|
||||
</ul>
|
||||
<textarea cols="80" rows="20" name="description">
|
||||
</textarea>
|
||||
<h3>Offer details</h3>
|
||||
This should include:
|
||||
<ul>
|
||||
<li>Details about the edition being offered.
|
||||
<li>Hyperlinks for the author(s), publisher making the offer, or for the work itself.
|
||||
</uL>
|
||||
<textarea cols="80" rows="20" name="details">
|
||||
</textarea>
|
||||
</ul>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
|
@ -60,6 +60,9 @@ function highlightTarget(targetdiv) {
|
|||
};
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block extra_head %}
|
||||
<link rel="alternate" type="application/atom+xml" title="feed for books from {{ supporter }}'s ungluing wishlist" href="feed" />
|
||||
{% endblock %}
|
||||
|
||||
{% comment %}
|
||||
To do:
|
||||
|
@ -259,7 +262,7 @@ there's no tab for seeing ALL my books, only the filters! huh.
|
|||
<li class="tabs3"><a href="#">Wishlisted</a></li>
|
||||
</ul>
|
||||
|
||||
<span id="rss"><a href="feed" title="RSS feed of {{ supporter }}'s latest wishbooks" ><img src="/static/images/feedicons-standard/feed-icon-14x14.png" alt="RSS feed of {{ supporter }}'s latest wishbooks" /><span>Subscribe</span></a></span>
|
||||
|
||||
|
||||
{% if not works %}
|
||||
{% comment %}
|
||||
|
|
|
@ -101,7 +101,7 @@ $j(document).ready(function(){
|
|||
</div>
|
||||
{% if status == 'ACTIVE' %}
|
||||
{% if pledged %}
|
||||
<div class="btn_support modify"><form action="/stub/modify_pledge" method="get"><input type="submit" value="Change Pledge"/></form></div>
|
||||
<div class="btn_support modify"><form action="{% url pledge_modify work_id=work.id %}" method="get"><input type="submit" value="Change Pledge"/></form></div>
|
||||
{% else %}
|
||||
<div class="btn_support"><form action="{% url pledge work_id=work.id %}" method="get"><input type="submit" value="Support"/></form></div>
|
||||
{% endif %}
|
||||
|
@ -197,7 +197,7 @@ $j(document).ready(function(){
|
|||
{{ claim.rights_holder.rights_holder_name }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
, has agreed to release <i>{{work.title}}</i> 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 <i>{{work.title}}</i> 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!</p>
|
||||
{{ work.last_campaign.description|safe }}
|
||||
{% else %}
|
||||
|
@ -355,7 +355,6 @@ $j(document).ready(function(){
|
|||
<a href="{% url pledge work_id=work.id %}?premium_id={{premium.id}}">
|
||||
<span class="menu-item-price">${{ premium.amount }}</span>
|
||||
<span class="menu-item-desc">{{ premium.description }}</span>
|
||||
{% ifequal premium.type 'CU' %}<span class="custom-premium">exclusive!</span>{% endifequal %}
|
||||
</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
|
|
@ -7,7 +7,7 @@ from django.conf import settings
|
|||
|
||||
from regluit.core.feeds import SupporterWishlistFeed
|
||||
from regluit.core.models import Campaign
|
||||
from regluit.frontend.views import CampaignFormView, GoodreadsDisplayView, LibraryThingView, PledgeView, PledgeCompleteView, PledgeCancelView, FAQView
|
||||
from regluit.frontend.views import CampaignFormView, GoodreadsDisplayView, LibraryThingView, PledgeView, PledgeCompleteView, PledgeModifyView, PledgeCancelView, FAQView
|
||||
from regluit.frontend.views import CampaignListView, DonateView, WorkListView, UngluedListView, InfoPageView
|
||||
|
||||
urlpatterns = patterns(
|
||||
|
@ -44,11 +44,10 @@ urlpatterns = patterns(
|
|||
url(r"^work/(?P<work_id>\d+)/goodreads/$", "work_goodreads", name="work_goodreads"),
|
||||
url(r"^work/(?P<work_id>\d+)/openlibrary/$", "work_openlibrary", name="work_openlibrary"),
|
||||
url(r"^googlebooks/(?P<googlebooks_id>.+)/$", "googlebooks", name="googlebooks"),
|
||||
#may want to deprecate the following
|
||||
url(r"^setup/work/(?P<work_id>\d+)/$", "work", {'action':'setup_campaign'}, name="setup_campaign"),
|
||||
url(r"^pledge/(?P<work_id>\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"),
|
||||
url(r"^pledge/modify/(?P<work_id>\d+)$", login_required(PledgeModifyView.as_view()), name="pledge_modify"),
|
||||
url(r"^subjects/$", "subjects", name="subjects"),
|
||||
url(r"^librarything/$", LibraryThingView.as_view(), name="librarything"),
|
||||
url(r"^librarything/load/$","librarything_load", name="librarything_load"),
|
||||
|
|
|
@ -45,11 +45,11 @@ from regluit.core.goodreads import GoodreadsClient
|
|||
from regluit.frontend.forms import UserData, ProfileForm, CampaignPledgeForm, GoodreadsShelfLoadingForm
|
||||
from regluit.frontend.forms import RightsHolderForm, UserClaimForm, LibraryThingForm, OpenCampaignForm
|
||||
from regluit.frontend.forms import ManageCampaignForm, DonateForm, CampaignAdminForm, EmailShareForm, FeedbackForm
|
||||
from regluit.frontend.forms import EbookForm
|
||||
from regluit.frontend.forms import EbookForm, CustomPremiumForm
|
||||
from regluit.payment.manager import PaymentManager
|
||||
from regluit.payment.models import Transaction
|
||||
from regluit.payment.parameters import TARGET_TYPE_CAMPAIGN, TARGET_TYPE_DONATION, PAYMENT_TYPE_AUTHORIZATION
|
||||
from regluit.payment.paypal import Preapproval, IPN_PAY_STATUS_NONE, IPN_PAY_STATUS_ACTIVE, IPN_PAY_STATUS_INCOMPLETE, IPN_PAY_STATUS_COMPLETED, IPN_PAY_STATUS_CANCELED, IPN_TYPE_PREAPPROVAL
|
||||
from regluit.payment.paypal import Preapproval, IPN_PAY_STATUS_NONE, IPN_PREAPPROVAL_STATUS_ACTIVE, IPN_PAY_STATUS_INCOMPLETE, IPN_PAY_STATUS_COMPLETED, IPN_PREAPPROVAL_STATUS_CANCELED, IPN_TYPE_PREAPPROVAL
|
||||
from regluit.core import goodreads
|
||||
from tastypie.models import ApiKey
|
||||
from regluit.payment.models import Transaction
|
||||
|
@ -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():
|
||||
|
@ -141,20 +141,22 @@ def work(request, work_id, action='display'):
|
|||
pledged = campaign.transactions().filter(user=request.user, status="ACTIVE")
|
||||
except:
|
||||
pledged = None
|
||||
|
||||
try:
|
||||
pubdate = work.publication_date[:4]
|
||||
except IndexError:
|
||||
pubdate = 'unknown'
|
||||
if not request.user.is_anonymous():
|
||||
claimform = UserClaimForm( request.user, data={'work':work.pk, 'user': request.user.id}, prefix = 'claim')
|
||||
claimform = UserClaimForm( request.user, data={'claim-work':work.pk, 'claim-user': request.user.id}, prefix = 'claim')
|
||||
for edition in editions:
|
||||
#edition.ebook_form = EbookForm( data = {'user':request.user.id, 'edition':edition.pk })
|
||||
edition.ebook_form = EbookForm( instance= models.Ebook(user = request.user, edition = edition, provider = 'x' ), prefix = 'ebook_%d'%edition.id)
|
||||
else:
|
||||
claimform = None
|
||||
if campaign:
|
||||
# pull up premiums explicitly tied to the campaign or generic premiums
|
||||
q = Q(campaign=campaign) | Q(campaign__isnull=True)
|
||||
premiums = models.Premium.objects.filter(q)
|
||||
premiums = models.Premium.objects.filter(q).exclude(type='XX').order_by('amount')
|
||||
else:
|
||||
premiums = None
|
||||
|
||||
|
@ -162,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)
|
||||
|
@ -188,22 +186,59 @@ def manage_campaign(request, id):
|
|||
campaign.not_manager=True
|
||||
return render(request, 'manage_campaign.html', {'campaign': campaign})
|
||||
alerts = []
|
||||
if request.method == 'POST':
|
||||
form= ManageCampaignForm(instance=campaign, data=request.POST)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
alerts.append(_('Campaign data has been saved'))
|
||||
else:
|
||||
alerts.append(_('Campaign data has NOT been saved'))
|
||||
if 'launch' in request.POST.keys():
|
||||
if campaign.launchable :
|
||||
campaign.activate()
|
||||
alerts.append(_('Campaign has been launched'))
|
||||
if request.method == 'POST' :
|
||||
if request.POST.has_key('add_premium') :
|
||||
postcopy=request.POST.copy()
|
||||
postcopy['type']='CU'
|
||||
new_premium_form = CustomPremiumForm(data=postcopy)
|
||||
if new_premium_form.is_valid():
|
||||
new_premium_form.save()
|
||||
alerts.append(_('New premium has been added'))
|
||||
new_premium_form = CustomPremiumForm(data={'campaign': campaign})
|
||||
else:
|
||||
alerts.append(_('Campaign has NOT been launched'))
|
||||
alerts.append(_('New premium has not been added'))
|
||||
form = ManageCampaignForm(instance=campaign)
|
||||
elif request.POST.has_key('save') or request.POST.has_key('launch') :
|
||||
form= ManageCampaignForm(instance=campaign, data=request.POST)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
alerts.append(_('Campaign data has been saved'))
|
||||
else:
|
||||
alerts.append(_('Campaign data has NOT been saved'))
|
||||
if 'launch' in request.POST.keys():
|
||||
if campaign.launchable :
|
||||
campaign.activate()
|
||||
alerts.append(_('Campaign has been launched'))
|
||||
else:
|
||||
alerts.append(_('Campaign has NOT been launched'))
|
||||
new_premium_form = CustomPremiumForm(data={'campaign': campaign})
|
||||
elif request.POST.has_key('inactivate') :
|
||||
if request.POST.has_key('premium_id'):
|
||||
premiums_to_stop = request.POST['premium_id']
|
||||
for premium_to_stop in premiums_to_stop:
|
||||
selected_premium = models.Premium.objects.get(id=premium_to_stop)
|
||||
if selected_premium.type == 'CU':
|
||||
selected_premium.type = 'XX'
|
||||
selected_premium.save()
|
||||
alerts.append(_('Premium %s has been inactivated'% premium_to_stop))
|
||||
form = ManageCampaignForm(instance=campaign)
|
||||
new_premium_form = CustomPremiumForm(data={'campaign': campaign})
|
||||
else:
|
||||
form= ManageCampaignForm(instance=campaign)
|
||||
return render(request, 'manage_campaign.html', {'campaign': campaign, 'form':form, 'problems': campaign.problems, 'alerts': alerts})
|
||||
form = ManageCampaignForm(instance=campaign)
|
||||
new_premium_form = CustomPremiumForm(data={'campaign': campaign})
|
||||
|
||||
# pull up premiums explicitly tied to the campaign or generic premiums
|
||||
q = Q(campaign=campaign) | Q(campaign__isnull=True)
|
||||
premiums = models.Premium.objects.filter(q).order_by('amount')
|
||||
|
||||
return render(request, 'manage_campaign.html', {
|
||||
'campaign': campaign,
|
||||
'form':form,
|
||||
'problems': campaign.problems,
|
||||
'alerts': alerts,
|
||||
'premiums' : premiums,
|
||||
'premium_form' : new_premium_form,
|
||||
})
|
||||
|
||||
def googlebooks(request, googlebooks_id):
|
||||
try:
|
||||
|
@ -330,7 +365,7 @@ class PledgeView(FormView):
|
|||
embedded = False
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
# change https://code.djangoproject.com/browser/django/tags/releases/1.3.1/django/views/generic/edit.py#L129
|
||||
# change the default behavior from https://code.djangoproject.com/browser/django/tags/releases/1.3.1/django/views/generic/edit.py#L129
|
||||
# don't automatically bind the data to the form on GET, only on POST
|
||||
# compare with https://code.djangoproject.com/browser/django/tags/releases/1.3.1/django/views/generic/edit.py#L34
|
||||
form_class = self.get_form_class()
|
||||
|
@ -376,10 +411,19 @@ class PledgeView(FormView):
|
|||
work_id = self.kwargs["work_id"]
|
||||
preapproval_amount = form.cleaned_data["preapproval_amount"]
|
||||
anonymous = form.cleaned_data["anonymous"]
|
||||
|
||||
# right now, if there is a non-zero pledge amount, go with that. otherwise, do the pre_approval
|
||||
|
||||
# right now, if there is a non-zero pledge amount, go with that. otherwise, do the pre_approval
|
||||
campaign = models.Work.objects.get(id=int(work_id)).last_campaign()
|
||||
|
||||
premium_id = form.cleaned_data["premium_id"]
|
||||
# confirm that the premium_id is a valid one for the campaign in question
|
||||
try:
|
||||
premium = models.Premium.objects.get(id=premium_id)
|
||||
if not (premium.campaign is None or premium.campaign == campaign):
|
||||
premium = None
|
||||
except models.Premium.DoesNotExist, e:
|
||||
premium = None
|
||||
|
||||
p = PaymentManager(embedded=self.embedded)
|
||||
|
||||
# PledgeView is wrapped in login_required -- so in theory, user should never be None -- but I'll keep this logic here for now.
|
||||
|
@ -397,7 +441,7 @@ class PledgeView(FormView):
|
|||
# set the expiry date based on the campaign deadline
|
||||
expiry = campaign.deadline + timedelta( days=settings.PREAPPROVAL_PERIOD_AFTER_CAMPAIGN )
|
||||
t, url = p.authorize('USD', TARGET_TYPE_CAMPAIGN, preapproval_amount, expiry=expiry, campaign=campaign, list=None, user=user,
|
||||
return_url=return_url, cancel_url=cancel_url, anonymous=anonymous)
|
||||
return_url=return_url, cancel_url=cancel_url, anonymous=anonymous, premium=premium)
|
||||
else: # embedded view -- which we're not actively using right now.
|
||||
# embedded view triggerws instant payment: send to the partnering RH
|
||||
receiver_list = [{'email':settings.PAYPAL_NONPROFIT_PARTNER_EMAIL, 'amount':preapproval_amount}]
|
||||
|
@ -406,7 +450,7 @@ class PledgeView(FormView):
|
|||
cancel_url = None
|
||||
|
||||
t, url = p.pledge('USD', TARGET_TYPE_CAMPAIGN, receiver_list, campaign=campaign, list=None, user=user,
|
||||
return_url=return_url, cancel_url=cancel_url, anonymous=anonymous)
|
||||
return_url=return_url, cancel_url=cancel_url, anonymous=anonymous, premium=premium)
|
||||
|
||||
if url:
|
||||
logger.info("PledgeView paypal: " + url)
|
||||
|
@ -417,21 +461,133 @@ class PledgeView(FormView):
|
|||
logger.info("PledgeView paypal: Error " + str(t.reference))
|
||||
return HttpResponse(response)
|
||||
|
||||
class PledgeModifyView(FormView):
|
||||
"""
|
||||
A view to handle request to change an existing pledge
|
||||
"""
|
||||
template_name="pledge_modify.html"
|
||||
form_class = CampaignPledgeForm
|
||||
embedded = False
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
context = super(PledgeModifyView, self).get_context_data(**kwargs)
|
||||
|
||||
# the following should be true since PledgeModifyView.as_view is wrapped in login_required
|
||||
assert self.request.user.is_authenticated()
|
||||
user = self.request.user
|
||||
|
||||
work = get_object_or_404(models.Work, id=self.kwargs["work_id"])
|
||||
|
||||
try:
|
||||
campaign = work.last_campaign()
|
||||
premiums = campaign.effective_premiums()
|
||||
|
||||
# which combination of campaign and transaction status required?
|
||||
# Campaign must be ACTIVE
|
||||
assert campaign.status == 'ACTIVE'
|
||||
|
||||
transactions = campaign.transactions().filter(user=user, status=IPN_PREAPPROVAL_STATUS_ACTIVE)
|
||||
assert transactions.count() == 1
|
||||
transaction = transactions[0]
|
||||
assert transaction.type == PAYMENT_TYPE_AUTHORIZATION and transaction.status == IPN_PREAPPROVAL_STATUS_ACTIVE
|
||||
|
||||
except Exception, e:
|
||||
raise e
|
||||
|
||||
# what stuff do we need to pull out to populate form?
|
||||
# preapproval_amount, premium_id (which we don't have stored yet)
|
||||
if transaction.premium is not None:
|
||||
premium_id = transaction.premium.id
|
||||
else:
|
||||
premium_id = None
|
||||
|
||||
# is there a Transaction for an ACTIVE campaign for this
|
||||
# should make sure Transaction is modifiable.
|
||||
|
||||
preapproval_amount = transaction.amount
|
||||
data = {'preapproval_amount':preapproval_amount, 'premium_id':premium_id}
|
||||
|
||||
# initialize form with the current state of the transaction if the current values empty
|
||||
form = kwargs['form']
|
||||
|
||||
if not(form.is_bound):
|
||||
form_class = self.get_form_class()
|
||||
form = form_class(initial=data)
|
||||
|
||||
context.update({'work':work,'campaign':campaign, 'premiums':premiums, 'form':form, 'premium_id':premium_id, 'faqmenu': 'pledge'})
|
||||
return context
|
||||
|
||||
|
||||
def form_invalid(self, form):
|
||||
logger.info("form.non_field_errors: {0}".format(form.non_field_errors()))
|
||||
response = self.render_to_response(self.get_context_data(form=form))
|
||||
return response
|
||||
|
||||
def form_valid(self, form):
|
||||
|
||||
# What are the situations we need to deal with?
|
||||
# 2 main situations: if the new amount is less than max_amount, no need to go out to PayPal again
|
||||
# if new amount is greater than max_amount...need to go out and get new approval.
|
||||
# to start with, we can use the standard pledge_complete, pledge_cancel machinery
|
||||
# might have to modify the pledge_complete, pledge_cancel because the messages are going to be
|
||||
# different because we're modifying a pledge rather than a new one.
|
||||
|
||||
work_id = self.kwargs["work_id"]
|
||||
preapproval_amount = form.cleaned_data["preapproval_amount"]
|
||||
anonymous = form.cleaned_data["anonymous"]
|
||||
|
||||
assert self.request.user.is_authenticated()
|
||||
user = self.request.user
|
||||
|
||||
# right now, if there is a non-zero pledge amount, go with that. otherwise, do the pre_approval
|
||||
campaign = models.Work.objects.get(id=int(work_id)).last_campaign()
|
||||
assert campaign.status == 'ACTIVE'
|
||||
|
||||
premium_id = form.cleaned_data["premium_id"]
|
||||
# confirm that the premium_id is a valid one for the campaign in question
|
||||
try:
|
||||
premium = models.Premium.objects.get(id=premium_id)
|
||||
if not (premium.campaign is None or premium.campaign == campaign):
|
||||
premium = None
|
||||
except models.Premium.DoesNotExist, e:
|
||||
premium = None
|
||||
|
||||
transactions = campaign.transactions().filter(user=user, status=IPN_PREAPPROVAL_STATUS_ACTIVE)
|
||||
assert transactions.count() == 1
|
||||
transaction = transactions[0]
|
||||
assert transaction.type == PAYMENT_TYPE_AUTHORIZATION and transaction.status == IPN_PREAPPROVAL_STATUS_ACTIVE
|
||||
|
||||
p = PaymentManager(embedded=self.embedded)
|
||||
status, url = p.modify_transaction(transaction=transaction, amount=preapproval_amount, premium=premium)
|
||||
|
||||
logger.info("status: {0}, url:{1}".format(status, url))
|
||||
|
||||
if status and url is not None:
|
||||
logger.info("PledgeModifyView paypal: " + url)
|
||||
return HttpResponseRedirect(url)
|
||||
elif status and url is None:
|
||||
# let's use the pledge_complete template for now and maybe look into customizing it.
|
||||
return HttpResponseRedirect("{0}?tid={1}".format(reverse('pledge_complete'), transaction.id))
|
||||
else:
|
||||
return HttpResponse("No modication made")
|
||||
|
||||
|
||||
class PledgeCompleteView(TemplateView):
|
||||
"""A callback for PayPal to tell unglue.it that a payment transaction has completed successfully.
|
||||
|
||||
Possible things to implement:
|
||||
|
||||
after pledging, supporter receives email including thanks, work pledged, amount, expiry date, any next steps they should expect; others?
|
||||
study other confirmation emails for their contents
|
||||
after pledging, supporters are returned to a thank-you screen
|
||||
should have prominent "thank you" or "congratulations" message
|
||||
should have prominent share options
|
||||
should suggest other works for supporters to explore (on what basis?)
|
||||
link to work page? or to page on which supporter entered the process? (if the latter, how does that work with widgets?)
|
||||
should note that a confirmation email has been sent to $email from $sender
|
||||
should briefly note next steps (e.g. if this campaign succeeds you will be emailed on date X)
|
||||
|
||||
after pledging, supporter receives email including thanks, work pledged, amount, expiry date, any next steps they should expect; others?
|
||||
study other confirmation emails for their contents
|
||||
after pledging, supporters are returned to a thank-you screen
|
||||
should have prominent "thank you" or "congratulations" message
|
||||
should have prominent share options
|
||||
should suggest other works for supporters to explore (on what basis?)
|
||||
link to work page? or to page on which supporter entered the process? (if the latter, how does that work with widgets?)
|
||||
should note that a confirmation email has been sent to $email from $sender
|
||||
should briefly note next steps (e.g. if this campaign succeeds you will be emailed on date X)
|
||||
|
||||
"""
|
||||
|
||||
template_name="pledge_complete.html"
|
||||
|
@ -467,8 +623,12 @@ should briefly note next steps (e.g. if this campaign succeeds you will be email
|
|||
try:
|
||||
if user.id == transaction.user.id:
|
||||
correct_user = True
|
||||
else:
|
||||
# should be 403 -- but let's try 404 for now -- 403 exception coming in Django 1.4
|
||||
raise Http404
|
||||
except Exception, e:
|
||||
pass
|
||||
raise Http404
|
||||
|
||||
|
||||
# check that the user had not already approved the transaction
|
||||
# do we need to first run PreapprovalDetails to check on the status
|
||||
|
@ -612,15 +772,15 @@ def claim(request):
|
|||
data = request.GET
|
||||
else:
|
||||
data = request.POST
|
||||
form = UserClaimForm(request.user, data=data)
|
||||
form = UserClaimForm(request.user, data=data, prefix='claim')
|
||||
if form.is_valid():
|
||||
# make sure we're not creating a duplicate claim
|
||||
if not models.Claim.objects.filter(work=data['work'], rights_holder=data['rights_holder'], status='pending').count():
|
||||
if not models.Claim.objects.filter(work=data['claim-work'], rights_holder=data['claim-rights_holder'], status='pending').count():
|
||||
form.save()
|
||||
return HttpResponseRedirect(reverse('work', kwargs={'work_id': data['work']}))
|
||||
return HttpResponseRedirect(reverse('work', kwargs={'work_id': data['claim-work']}))
|
||||
else:
|
||||
work = models.Work.objects.get(id=data['work'])
|
||||
rights_holder = models.RightsHolder.objects.get(id=data['rights_holder'])
|
||||
work = models.Work.objects.get(id=data['claim-work'])
|
||||
rights_holder = models.RightsHolder.objects.get(id=data['claim-rights_holder'])
|
||||
context = {'form': form, 'work': work, 'rights_holder':rights_holder }
|
||||
return render(request, "claim.html", context)
|
||||
|
||||
|
@ -700,7 +860,7 @@ def campaign_admin(request):
|
|||
# pull out Campaigns with Transactions that are ACTIVE -- and hence can be executed
|
||||
# Campaign.objects.filter(transaction__status='ACTIVE')
|
||||
|
||||
campaigns_with_active_transactions = models.Campaign.objects.filter(transaction__status=IPN_PAY_STATUS_ACTIVE)
|
||||
campaigns_with_active_transactions = models.Campaign.objects.filter(transaction__status=IPN_PREAPPROVAL_STATUS_ACTIVE)
|
||||
|
||||
# pull out Campaigns with Transactions that are INCOMPLETE
|
||||
|
||||
|
@ -712,7 +872,7 @@ def campaign_admin(request):
|
|||
|
||||
# show Campaigns with Transactions that are CANCELED
|
||||
|
||||
campaigns_with_canceled_transactions = models.Campaign.objects.filter(transaction__status=IPN_PAY_STATUS_CANCELED)
|
||||
campaigns_with_canceled_transactions = models.Campaign.objects.filter(transaction__status=IPN_PREAPPROVAL_STATUS_CANCELED)
|
||||
|
||||
return (campaigns_with_active_transactions, campaigns_with_incomplete_transactions, campaigns_with_completed_transactions,
|
||||
campaigns_with_canceled_transactions)
|
||||
|
|
|
@ -4,7 +4,7 @@ from django.contrib.auth.models import User
|
|||
from django.core.urlresolvers import reverse
|
||||
|
||||
from regluit.payment.parameters import *
|
||||
from regluit.payment.paypal import Pay, Execute, IPN, IPN_TYPE_PAYMENT, IPN_TYPE_PREAPPROVAL, IPN_TYPE_ADJUSTMENT, IPN_PAY_STATUS_ACTIVE, IPN_PAY_STATUS_INCOMPLETE, IPN_PAY_STATUS_NONE
|
||||
from regluit.payment.paypal import Pay, Execute, IPN, IPN_TYPE_PAYMENT, IPN_TYPE_PREAPPROVAL, IPN_TYPE_ADJUSTMENT, IPN_PREAPPROVAL_STATUS_ACTIVE, IPN_PAY_STATUS_INCOMPLETE, IPN_PAY_STATUS_NONE
|
||||
from regluit.payment.paypal import Preapproval, IPN_PAY_STATUS_COMPLETED, CancelPreapproval, PaymentDetails, PreapprovalDetails, IPN_SENDER_STATUS_COMPLETED, IPN_TXN_STATUS_COMPLETED
|
||||
from regluit.payment.paypal import RefundPayment
|
||||
import uuid
|
||||
|
@ -173,11 +173,12 @@ class PaymentManager( object ):
|
|||
for t in transactions:
|
||||
|
||||
if t.date_payment is None:
|
||||
preapproval_status = self.update_preapproval(t)
|
||||
preapproval_status = self.update_preapproval(t)
|
||||
logger.info("transaction: {0}, preapproval_status: {1}".format(t, preapproval_status))
|
||||
if not set(['status', 'currency', 'amount', 'approved']).isdisjoint(set(preapproval_status.keys())):
|
||||
status["preapprovals"].append(preapproval_status)
|
||||
else:
|
||||
payment_status = self.update_payment(t)
|
||||
payment_status = self.update_payment(t)
|
||||
if not set(["status", "receivers"]).isdisjoint(payment_status.keys()):
|
||||
status["payments"].append(payment_status)
|
||||
|
||||
|
@ -305,7 +306,7 @@ class PaymentManager( object ):
|
|||
if authorized:
|
||||
# return only ACTIVE transactions with approved=True
|
||||
authorized_list = transaction_list.filter(type=PAYMENT_TYPE_AUTHORIZATION,
|
||||
status=IPN_PAY_STATUS_ACTIVE,
|
||||
status=IPN_PREAPPROVAL_STATUS_ACTIVE,
|
||||
approved=True)
|
||||
else:
|
||||
authorized_list = []
|
||||
|
@ -419,7 +420,7 @@ class PaymentManager( object ):
|
|||
'''
|
||||
|
||||
# only allow active transactions to go through again, if there is an error, intervention is needed
|
||||
transactions = Transaction.objects.filter(campaign=campaign, status=IPN_PAY_STATUS_ACTIVE)
|
||||
transactions = Transaction.objects.filter(campaign=campaign, status=IPN_PREAPPROVAL_STATUS_ACTIVE)
|
||||
|
||||
for t in transactions:
|
||||
|
||||
|
@ -428,6 +429,11 @@ class PaymentManager( object ):
|
|||
|
||||
self.execute_transaction(t, receiver_list)
|
||||
|
||||
# TO DO: update campaign status
|
||||
# Should this be done first before executing the transactions?
|
||||
# How does the success/failure of transactions affect states of campaigns
|
||||
|
||||
|
||||
return transactions
|
||||
|
||||
def finish_campaign(self, campaign):
|
||||
|
@ -450,6 +456,9 @@ class PaymentManager( object ):
|
|||
for t in transactions:
|
||||
result = self.finish_transaction(t)
|
||||
|
||||
# TO DO: update campaign status
|
||||
|
||||
|
||||
return transactions
|
||||
|
||||
def cancel_campaign(self, campaign):
|
||||
|
@ -463,11 +472,13 @@ class PaymentManager( object ):
|
|||
|
||||
'''
|
||||
|
||||
transactions = Transaction.objects.filter(campaign=campaign, status=IPN_PAY_STATUS_ACTIVE)
|
||||
transactions = Transaction.objects.filter(campaign=campaign, status=IPN_PREAPPROVAL_STATUS_ACTIVE)
|
||||
|
||||
for t in transactions:
|
||||
result = self.cancel_transaction(t)
|
||||
|
||||
# TO DO: update campaign status
|
||||
|
||||
return transactions
|
||||
|
||||
|
||||
|
@ -607,7 +618,7 @@ class PaymentManager( object ):
|
|||
logger.info("Cancel Transaction " + str(transaction.id) + " Failed with error: " + p.error_string())
|
||||
return False
|
||||
|
||||
def authorize(self, currency, target, amount, expiry=None, campaign=None, list=None, user=None, return_url=None, cancel_url=None, anonymous=False):
|
||||
def authorize(self, currency, target, amount, expiry=None, campaign=None, list=None, user=None, return_url=None, cancel_url=None, anonymous=False, premium=None):
|
||||
'''
|
||||
authorize
|
||||
|
||||
|
@ -619,6 +630,10 @@ class PaymentManager( object ):
|
|||
campaign: optional campaign object(to be set with TARGET_TYPE_CAMPAIGN)
|
||||
list: optional list object(to be set with TARGET_TYPE_LIST)
|
||||
user: optional user object
|
||||
return_url: url to redirect supporter to after a successful PayPal transaction
|
||||
cancel_url: url to send supporter to if support hits cancel while in middle of PayPal transaction
|
||||
anonymous: whether this pledge is anonymous
|
||||
premium: the premium selected by the supporter for this transaction
|
||||
|
||||
return value: a tuple of the new transaction object and a re-direct url. If the process fails,
|
||||
the redirect url will be None
|
||||
|
@ -635,7 +650,8 @@ class PaymentManager( object ):
|
|||
campaign=campaign,
|
||||
list=list,
|
||||
user=user,
|
||||
anonymous=anonymous
|
||||
anonymous=anonymous,
|
||||
premium=premium
|
||||
)
|
||||
|
||||
# we might want to not allow for a return_url or cancel_url to be passed in but calculated
|
||||
|
@ -679,7 +695,7 @@ class PaymentManager( object ):
|
|||
logger.info("Authorize Error: " + p.error_string())
|
||||
return t, None
|
||||
|
||||
def modify_transaction(self, transaction, amount=None, expiry=None, return_url=None, cancel_url=None):
|
||||
def modify_transaction(self, transaction, amount, expiry=None, anonymous=None, premium=None, return_url=None, cancel_url=None):
|
||||
'''
|
||||
modify
|
||||
|
||||
|
@ -687,35 +703,34 @@ class PaymentManager( object ):
|
|||
|
||||
amount: the new amount
|
||||
expiry: the new expiration date, or if none the current expiration date will be used
|
||||
anonymous: new anonymous value; if None, then keep old value
|
||||
premium: new premium selected; if None, then keep old value
|
||||
return_url: the return URL after the preapproval(if needed)
|
||||
cancel_url: the cancel url after the preapproval(if needed)
|
||||
|
||||
return value: True if successful, false otherwise. An optional second parameter for the forward URL if a new authorhization is needed
|
||||
'''
|
||||
|
||||
if not amount:
|
||||
logger.info("Error, no amount speicified")
|
||||
return False
|
||||
return value: True if successful, False otherwise. An optional second parameter for the forward URL if a new authorhization is needed
|
||||
'''
|
||||
|
||||
# Can only modify the amount of a preapproval for now
|
||||
if transaction.type != PAYMENT_TYPE_AUTHORIZATION:
|
||||
# Can only modify the amount of a preapproval for now
|
||||
logger.info("Error, attempt to modify an invalid transaction type")
|
||||
return False, None
|
||||
|
||||
if transaction.status != IPN_PAY_STATUS_ACTIVE:
|
||||
# Can only modify an active, pending transaction. If it is completed, we need to do a refund. If it is incomplete,
|
||||
# then an IPN may be pending and we cannot touch it
|
||||
# Can only modify an active, pending transaction. If it is completed, we need to do a refund. If it is incomplete,
|
||||
# then an IPN may be pending and we cannot touch it
|
||||
if transaction.status != IPN_PREAPPROVAL_STATUS_ACTIVE:
|
||||
logger.info("Error, attempt to modify a transaction that is not active")
|
||||
return False, None
|
||||
|
||||
if not expiry:
|
||||
# Use the old expiration date
|
||||
# if any of expiry, anonymous, or premium is None, use the existing value
|
||||
if expiry is None:
|
||||
expiry = transaction.date_expired
|
||||
if anonymous is None:
|
||||
anonymous = transaction.anonymous
|
||||
if premium is None:
|
||||
premium = transaction.premium
|
||||
|
||||
if amount > transaction.max_amount or expiry != transaction.date_expired:
|
||||
|
||||
# Increase or expiuration change, cancel and start again
|
||||
self.cancel_transaction(transaction)
|
||||
|
||||
# Start a new authorization for the new amount
|
||||
|
||||
|
@ -728,27 +743,30 @@ class PaymentManager( object ):
|
|||
transaction.user,
|
||||
return_url,
|
||||
cancel_url,
|
||||
transaction.anonymous)
|
||||
transaction.anonymous,
|
||||
premium)
|
||||
|
||||
if t and url:
|
||||
# Need to re-direct to approve the transaction
|
||||
logger.info("New authorization needed, redirectiont to url %s" % url)
|
||||
logger.info("New authorization needed, redirection to url %s" % url)
|
||||
self.cancel_transaction(transaction)
|
||||
return True, url
|
||||
else:
|
||||
# No amount change necessary
|
||||
# a problem in authorize
|
||||
logger.info("Error, unable to start a new authorization")
|
||||
return False, None
|
||||
|
||||
elif amount <= transaction.max_amount:
|
||||
# Change the amount but leave the preapproval alone
|
||||
# Update transaction but leave the preapproval alone
|
||||
transaction.amount = amount
|
||||
transaction.anonymous = anonymous
|
||||
transaction.premium = premium
|
||||
|
||||
transaction.save()
|
||||
logger.info("Updated amount of transaction to %f" % amount)
|
||||
return True, None
|
||||
|
||||
else:
|
||||
# No changes
|
||||
logger.info("Error, no modifications requested")
|
||||
# this shouldn't happen
|
||||
return False, None
|
||||
|
||||
|
||||
|
@ -794,7 +812,7 @@ class PaymentManager( object ):
|
|||
logger.info("Refund Transaction " + str(transaction.id) + " Failed with error: " + p.error_string())
|
||||
return False
|
||||
|
||||
def pledge(self, currency, target, receiver_list, campaign=None, list=None, user=None, return_url=None, cancel_url=None, anonymous=False):
|
||||
def pledge(self, currency, target, receiver_list, campaign=None, list=None, user=None, return_url=None, cancel_url=None, anonymous=False, premium=None):
|
||||
'''
|
||||
pledge
|
||||
|
||||
|
@ -812,6 +830,10 @@ class PaymentManager( object ):
|
|||
campaign: optional campaign object(to be set with TARGET_TYPE_CAMPAIGN)
|
||||
list: optional list object(to be set with TARGET_TYPE_LIST)
|
||||
user: optional user object
|
||||
return_url: url to redirect supporter to after a successful PayPal transaction
|
||||
cancel_url: url to send supporter to if support hits cancel while in middle of PayPal transaction
|
||||
anonymous: whether this pledge is anonymous
|
||||
premium: the premium selected by the supporter for this transaction
|
||||
|
||||
return value: a tuple of the new transaction object and a re-direct url. If the process fails,
|
||||
the redirect url will be None
|
||||
|
@ -834,7 +856,8 @@ class PaymentManager( object ):
|
|||
list=list,
|
||||
user=user,
|
||||
date_payment=now(),
|
||||
anonymous=anonymous
|
||||
anonymous=anonymous,
|
||||
premium=premium
|
||||
)
|
||||
|
||||
t.create_receivers(receiver_list)
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
# 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 'Transaction.premium'
|
||||
db.add_column('payment_transaction', 'premium', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Premium'], null=True), keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting field 'Transaction.premium'
|
||||
db.delete_column('payment_transaction', 'premium_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.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'}),
|
||||
'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.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.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'})
|
||||
},
|
||||
'payment.paymentresponse': {
|
||||
'Meta': {'object_name': 'PaymentResponse'},
|
||||
'api': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
|
||||
'correlation_id': ('django.db.models.fields.CharField', [], {'max_length': '512', 'null': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'info': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
|
||||
'timestamp': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
|
||||
'transaction': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['payment.Transaction']"})
|
||||
},
|
||||
'payment.receiver': {
|
||||
'Meta': {'object_name': 'Receiver'},
|
||||
'amount': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '14', 'decimal_places': '2'}),
|
||||
'currency': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
|
||||
'email': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'primary': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'reason': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
|
||||
'transaction': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['payment.Transaction']"}),
|
||||
'txn_id': ('django.db.models.fields.CharField', [], {'max_length': '64'})
|
||||
},
|
||||
'payment.transaction': {
|
||||
'Meta': {'object_name': 'Transaction'},
|
||||
'amount': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '14', 'decimal_places': '2'}),
|
||||
'anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'approved': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'campaign': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Campaign']", 'null': 'True'}),
|
||||
'currency': ('django.db.models.fields.CharField', [], {'default': "'USD'", 'max_length': '10', 'null': 'True'}),
|
||||
'date_authorized': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
|
||||
'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'date_executed': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
|
||||
'date_expired': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
|
||||
'date_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'date_payment': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
|
||||
'error': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True'}),
|
||||
'execution': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Wishlist']", 'null': 'True'}),
|
||||
'max_amount': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '14', 'decimal_places': '2'}),
|
||||
'pay_key': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
|
||||
'preapproval_key': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
|
||||
'premium': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['core.Premium']", 'null': 'True'}),
|
||||
'reason': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
|
||||
'receipt': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True'}),
|
||||
'secret': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'NONE'", 'max_length': '32'}),
|
||||
'target': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'type': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['payment']
|
|
@ -1,6 +1,6 @@
|
|||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from regluit.core.models import Campaign, Wishlist
|
||||
from regluit.core.models import Campaign, Wishlist, Premium
|
||||
from regluit.payment.parameters import *
|
||||
from decimal import Decimal
|
||||
import uuid
|
||||
|
@ -16,7 +16,7 @@ class Transaction(models.Model):
|
|||
#execution: e.g. EXECUTE_TYPE_CHAINED_INSTANT, EXECUTE_TYPE_CHAINED_DELAYED, EXECUTE_TYPE_PARALLEL
|
||||
execution = models.IntegerField(default=EXECUTE_TYPE_NONE, null=False)
|
||||
|
||||
# status: constants defined in paypal.py (e.g., IPN_PAY_STATUS_ACTIVE, IPN_PAY_STATUS_CREATED)
|
||||
# status: constants defined in paypal.py (e.g., IPN_PREAPPROVAL_STATUS_ACTIVE, IPN_PAY_STATUS_CREATED)
|
||||
status = models.CharField(max_length=32, default='NONE', null=False)
|
||||
|
||||
# amount & currency -- amount of money and its currency involved for transaction
|
||||
|
@ -59,9 +59,10 @@ class Transaction(models.Model):
|
|||
date_authorized = models.DateTimeField(null=True)
|
||||
date_expired = models.DateTimeField(null=True)
|
||||
|
||||
# associated User and Campaign for this Transaction
|
||||
# associated User, Campaign, and Premium for this Transaction
|
||||
user = models.ForeignKey(User, null=True)
|
||||
campaign = models.ForeignKey(Campaign, null=True)
|
||||
premium = models.ForeignKey(Premium, null=True)
|
||||
|
||||
# list: makes allowance for pledging against a Wishlist: not currently in use
|
||||
list = models.ForeignKey(Wishlist, null=True)
|
||||
|
|
|
@ -60,15 +60,15 @@ IPN_PAY_STATUS_REVERSALERROR = 'REVERSALERROR'
|
|||
IPN_PAY_STATUS_PROCESSING = 'PROCESSING'
|
||||
IPN_PAY_STATUS_PENDING = 'PENDING'
|
||||
|
||||
# particular to preapprovals -- may want to rename these constants to IPN_PREAPPROVAL_STATUS_*
|
||||
# particular to preapprovals
|
||||
# https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_APPreapprovalDetails
|
||||
#ACTIVE - The preapproval is active
|
||||
#CANCELED - The preapproval was explicitly canceled by the sender or by PayPal
|
||||
#DEACTIVED - The preapproval is not active; you can be reactivate it by resetting the personal identification number (PIN) or by contacting PayPal
|
||||
|
||||
IPN_PAY_STATUS_ACTIVE = "ACTIVE"
|
||||
IPN_PAY_STATUS_CANCELED = "CANCELED"
|
||||
IPN_PAY_STATUS_DEACTIVED = "DEACTIVED"
|
||||
IPN_PREAPPROVAL_STATUS_ACTIVE = "ACTIVE"
|
||||
IPN_PREAPPROVAL_STATUS_CANCELED = "CANCELED"
|
||||
IPN_PREAPPROVAL_STATUS_DEACTIVED = "DEACTIVED"
|
||||
|
||||
# https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_APIPN
|
||||
#COMPLETED - The sender's transaction has completed
|
||||
|
|
|
@ -60,7 +60,8 @@ def loginSandbox(selenium):
|
|||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
def paySandbox(test, selenium, url, authorize=False):
|
||||
def paySandbox(test, selenium, url, authorize=False, already_at_url=False, sleep_time=20):
|
||||
|
||||
|
||||
if authorize:
|
||||
print "AUTHORIZE SANDBOX"
|
||||
|
@ -69,42 +70,45 @@ def paySandbox(test, selenium, url, authorize=False):
|
|||
|
||||
try:
|
||||
# We need this sleep to make sure the JS engine is finished from the sandbox loging page
|
||||
time.sleep(20)
|
||||
time.sleep(sleep_time)
|
||||
|
||||
selenium.get(url)
|
||||
print "Opened URL %s" % url
|
||||
if not already_at_url:
|
||||
selenium.get(url)
|
||||
print "Opened URL %s" % url
|
||||
|
||||
try:
|
||||
# Button is only visible if the login box is NOT open
|
||||
# If the login box is open, the email/pw fiels are already accessible
|
||||
login_element = WebDriverWait(selenium, 30).until(lambda d : d.find_element_by_id("loadLogin"))
|
||||
login_element = WebDriverWait(selenium, 10).until(lambda d : d.find_element_by_id("loadLogin"))
|
||||
login_element.click()
|
||||
|
||||
# This sleep is needed for js to slide the buyer login into view. The elements are always in the DOM
|
||||
# so selenium can find them, but we need them in view to interact
|
||||
time.sleep(20)
|
||||
time.sleep(sleep_time)
|
||||
except:
|
||||
print "Ready for Login"
|
||||
|
||||
email_element = WebDriverWait(selenium, 60).until(lambda d : d.find_element_by_id("login_email"))
|
||||
email_element.click()
|
||||
email_element.clear()
|
||||
email_element.send_keys(settings.PAYPAL_BUYER_LOGIN)
|
||||
|
||||
password_element = WebDriverWait(selenium, 60).until(lambda d : d.find_element_by_id("login_password"))
|
||||
password_element.click()
|
||||
password_element.clear()
|
||||
password_element.send_keys(settings.PAYPAL_BUYER_PASSWORD)
|
||||
|
||||
submit_button = WebDriverWait(selenium, 60).until(lambda d : d.find_element_by_id("submitLogin"))
|
||||
submit_button.click()
|
||||
|
||||
# This sleep makes sure js has time to animate out the next page
|
||||
time.sleep(20)
|
||||
time.sleep(sleep_time)
|
||||
|
||||
final_submit = WebDriverWait(selenium, 60).until(lambda d : d.find_element_by_id("submit.x"))
|
||||
final_submit.click()
|
||||
|
||||
# This makes sure the processing of the final submit is complete
|
||||
time.sleep(20)
|
||||
time.sleep(sleep_time)
|
||||
|
||||
# Don't wait too long for this, it isn't really needed. By the time JS has gotten around to
|
||||
# displaying this element, the redirect has usually occured
|
||||
|
@ -261,7 +265,7 @@ class AuthorizeTest(TestCase):
|
|||
|
||||
t = Transaction.objects.get(id=t.id)
|
||||
|
||||
self.assertEqual(t.status, IPN_PAY_STATUS_ACTIVE)
|
||||
self.assertEqual(t.status, IPN_PREAPPROVAL_STATUS_ACTIVE)
|
||||
|
||||
def tearDown(self):
|
||||
self.selenium.quit()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from regluit.core import models
|
||||
from regluit.payment.models import Transaction, PaymentResponse, Receiver
|
||||
from regluit.payment.manager import PaymentManager
|
||||
from regluit.payment.paypal import IPN_PAY_STATUS_ACTIVE, IPN_PAY_STATUS_INCOMPLETE, IPN_PAY_STATUS_COMPLETED
|
||||
from regluit.payment.paypal import IPN_PREAPPROVAL_STATUS_ACTIVE, IPN_PAY_STATUS_INCOMPLETE, IPN_PAY_STATUS_COMPLETED
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
|
@ -108,7 +108,7 @@ pm = PaymentManager()
|
|||
|
||||
def campaign_display():
|
||||
|
||||
campaigns_with_active_transactions = models.Campaign.objects.filter(transaction__status=IPN_PAY_STATUS_ACTIVE)
|
||||
campaigns_with_active_transactions = models.Campaign.objects.filter(transaction__status=IPN_PREAPPROVAL_STATUS_ACTIVE)
|
||||
campaigns_with_incomplete_transactions = models.Campaign.objects.filter(transaction__status=IPN_PAY_STATUS_INCOMPLETE)
|
||||
campaigns_with_completed_transactions = models.Campaign.objects.filter(transaction__status=IPN_PAY_STATUS_COMPLETED)
|
||||
|
||||
|
@ -117,7 +117,7 @@ def campaign_display():
|
|||
print "campaigns with completed transactions", campaigns_with_completed_transactions
|
||||
|
||||
def campaigns_active():
|
||||
return models.Campaign.objects.filter(transaction__status=IPN_PAY_STATUS_ACTIVE)
|
||||
return models.Campaign.objects.filter(transaction__status=IPN_PREAPPROVAL_STATUS_ACTIVE)
|
||||
|
||||
def campaigns_incomplete():
|
||||
return models.Campaign.objects.filter(transaction__status=IPN_PAY_STATUS_INCOMPLETE)
|
||||
|
@ -151,30 +151,36 @@ def recipient_status(clist):
|
|||
|
||||
# res = [pm.finish_campaign(c) for c in campaigns_incomplete()]
|
||||
|
||||
def support_campaign():
|
||||
|
||||
def support_campaign(do_local=True):
|
||||
"""
|
||||
programatically fire up selenium to make a Pledge
|
||||
do_local should be True only if you are running support_campaign on db tied to LIVE_SERVER_TEST_URL
|
||||
"""
|
||||
|
||||
import django
|
||||
django.db.transaction.enter_transaction_management()
|
||||
|
||||
UNGLUE_IT_URL = settings.LIVE_SERVER_TEST_URL
|
||||
# unglue.it login
|
||||
USER = settings.UNGLUEIT_TEST_USER
|
||||
PASSWORD = settings.UNGLUEIT_TEST_PASSWORD
|
||||
|
||||
# PayPal developer sandbox
|
||||
from regluit.payment.tests import loginSandbox
|
||||
from regluit.payment.tests import loginSandbox, paySandbox
|
||||
|
||||
setup_selenium()
|
||||
|
||||
# we can experiment with different webdrivers
|
||||
# sel = webdriver.Firefox()
|
||||
sel = webdriver.Firefox()
|
||||
|
||||
# Chrome
|
||||
sel = webdriver.Chrome(executable_path='/Users/raymondyee/C/src/Gluejar/regluit/test/chromedriver')
|
||||
#sel = webdriver.Chrome(executable_path='/Users/raymondyee/C/src/Gluejar/regluit/test/chromedriver')
|
||||
|
||||
# HTMLUNIT with JS -- not successful
|
||||
#sel = webdriver.Remote("http://localhost:4444/wd/hub", webdriver.DesiredCapabilities.HTMLUNITWITHJS)
|
||||
|
||||
time.sleep(5)
|
||||
time.sleep(10)
|
||||
|
||||
# find a campaign to pledge to
|
||||
loginSandbox(sel)
|
||||
|
@ -203,10 +209,11 @@ def support_campaign():
|
|||
# pull up one of the campaigns to pledge to
|
||||
# div.book-list div.title a
|
||||
# for now, take the first book and click on the link to get to the work page
|
||||
sel.find_elements_by_css_selector("div.book-list div.title a")[0].click()
|
||||
work_links = WebDriverWait(sel,10).until(lambda d: d.find_elements_by_css_selector("div.book-list div.title a"))
|
||||
work_links[0].click()
|
||||
|
||||
time.sleep(1)
|
||||
sel.find_element_by_css_selector("input[value*='Support']").click()
|
||||
support_button = WebDriverWait(sel,10).until(lambda d: d.find_element_by_css_selector("input[value*='Support']"))
|
||||
support_button.click()
|
||||
|
||||
# just click Pledge without filling out amount -- should have the form validation spot the error
|
||||
pledge_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='Pledge']"))
|
||||
|
@ -221,12 +228,102 @@ def support_campaign():
|
|||
# enter a $10 pledge
|
||||
preapproval_amount_input = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input#id_preapproval_amount"))
|
||||
preapproval_amount_input.send_keys("10")
|
||||
|
||||
# fill out a premium -- the first one for now
|
||||
premium_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector('input[type="radio"][value="1"]'))
|
||||
premium_button.click()
|
||||
|
||||
pledge_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='Pledge']"))
|
||||
pledge_button.click()
|
||||
|
||||
# grab the URL where sel is now?
|
||||
|
||||
print "Now trying to pay PayPal", sel.current_url
|
||||
paySandbox(None, sel, sel.current_url, authorize=True, already_at_url=True, sleep_time=5)
|
||||
|
||||
# should be back on a pledge complete page
|
||||
print sel.current_url, re.search(r"/pledge/complete",sel.current_url)
|
||||
|
||||
time.sleep(2)
|
||||
django.db.transaction.commit()
|
||||
|
||||
# time out to simulate an IPN -- update all the transactions
|
||||
if do_local:
|
||||
django.db.transaction.enter_transaction_management()
|
||||
pm = PaymentManager()
|
||||
print pm.checkStatus()
|
||||
transaction0 = Transaction.objects.all()[0]
|
||||
print "transaction amount:{0}, transaction premium:{1}".format(transaction0.amount, transaction0.premium.id)
|
||||
django.db.transaction.commit()
|
||||
|
||||
|
||||
django.db.transaction.enter_transaction_management()
|
||||
|
||||
# I have no idea what the a[href*="/work/"] is not displayed....so that's why I'm going up one element.
|
||||
work_url = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector('p > a[href*="/work/"]'))
|
||||
work_url.click()
|
||||
|
||||
# change_pledge
|
||||
change_pledge_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='Change Pledge']"))
|
||||
change_pledge_button.click()
|
||||
|
||||
# enter a new pledge, which is less than the previous amount and therefore doesn't require a new PayPal transaction
|
||||
preapproval_amount_input = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input#id_preapproval_amount"))
|
||||
preapproval_amount_input.clear() # get rid of existing pledge
|
||||
preapproval_amount_input.send_keys("5")
|
||||
pledge_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='Modify Pledge']"))
|
||||
pledge_button.click()
|
||||
|
||||
# return to the Work page again
|
||||
work_url = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector('p > a[href*="/work/"]'))
|
||||
work_url.click()
|
||||
change_pledge_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='Change Pledge']"))
|
||||
change_pledge_button.click()
|
||||
|
||||
# enter a new pledge, which is more than the previous amount and therefore requires a new PayPal transaction
|
||||
preapproval_amount_input = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input#id_preapproval_amount"))
|
||||
preapproval_amount_input.clear() # get rid of existing pledge
|
||||
preapproval_amount_input.send_keys("25")
|
||||
pledge_button = WebDriverWait(sel,20).until(lambda d: d.find_element_by_css_selector("input[value*='Modify Pledge']"))
|
||||
pledge_button.click()
|
||||
paySandbox(None, sel, sel.current_url, authorize=True, already_at_url=True, sleep_time=5)
|
||||
|
||||
# wait a bit to allow PayPal sandbox to be update the status of the Transaction
|
||||
time.sleep(10)
|
||||
|
||||
# Why is the status of the new transaction not being updated?
|
||||
|
||||
django.db.transaction.commit()
|
||||
|
||||
# force a db lookup -- see whether there are 1 or 2 transactions
|
||||
if do_local:
|
||||
transactions = list(Transaction.objects.all())
|
||||
print "number of transactions", Transaction.objects.count()
|
||||
|
||||
print "transactions before pm.checkStatus"
|
||||
print [(t.id, t.type, t.preapproval_key, t.status, t.premium, t.amount) for t in Transaction.objects.all()]
|
||||
|
||||
print "checkStatus:", pm.checkStatus(transactions=transactions)
|
||||
|
||||
|
||||
yield sel
|
||||
#sel.quit()
|
||||
|
||||
|
||||
|
||||
def berkeley_search():
|
||||
sel = webdriver.Firefox()
|
||||
sel.get("http://berkeley.edu")
|
||||
search = WebDriverWait(sel,5).until(lambda d: d.find_element_by_css_selector('input[id="search_text"]'))
|
||||
search.send_keys("quantum computing")
|
||||
|
||||
return sel
|
||||
|
||||
# wait for a bit and then highlight the text and fill it out with "Bach" instead
|
||||
# I was looking at using XPath natively in Firefox....
|
||||
# https://developer.mozilla.org/en/Introduction_to_using_XPath_in_JavaScript#Within_an_HTML_Document
|
||||
# document.evaluate('//input[@id="search_text"]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ).snapshotItem(0);
|
||||
|
||||
def suites():
|
||||
testcases = [GoogleWebDriverTest]
|
||||
suites = unittest.TestSuite([unittest.TestLoader().loadTestsFromTestCase(testcase) for testcase in testcases])
|
||||
|
|
6
urls.py
6
urls.py
|
@ -10,9 +10,9 @@ urlpatterns = patterns('',
|
|||
(r'^accounts/', include('registration.backends.default.urls')),
|
||||
(r'^socialauth/', include('social_auth.urls')),
|
||||
url(r"^accounts/login/welcome/$", direct_to_template,
|
||||
{'template': 'registration/welcome.html',
|
||||
'extra_context': {'suppress_search_box': True,}
|
||||
}),
|
||||
{'template': 'registration/welcome.html',
|
||||
'extra_context': {'suppress_search_box': True,}
|
||||
}),
|
||||
(r'^api/', include('regluit.api.urls')),
|
||||
(r'', include('regluit.frontend.urls')),
|
||||
(r'', include('regluit.payment.urls')),
|
||||
|
|
Loading…
Reference in New Issue