Pro-everything

master
Nick Sergeant 2012-07-19 00:39:43 -04:00
parent 806c09495a
commit b7afdcc48b
18 changed files with 296 additions and 48 deletions

View File

@ -4,7 +4,7 @@ from accounts.models import UserProfile
class UserProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'is_pro',)
list_display = ('user', 'is_pro', 'stripe_id',)
search_fields = ('user__username',)
admin.site.register(UserProfile, UserProfileAdmin)

View File

@ -0,0 +1,68 @@
# -*- coding: 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 'UserProfile.stripe_id'
db.add_column('accounts_userprofile', 'stripe_id',
self.gf('django.db.models.fields.IntegerField')(null=True, blank=True),
keep_default=False)
def backwards(self, orm):
# Deleting field 'UserProfile.stripe_id'
db.delete_column('accounts_userprofile', 'stripe_id')
models = {
'accounts.userprofile': {
'Meta': {'object_name': 'UserProfile'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_pro': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'stripe_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'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'})
}
}
complete_apps = ['accounts']

View File

@ -0,0 +1,66 @@
# -*- coding: 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):
# Changing field 'UserProfile.stripe_id'
db.alter_column('accounts_userprofile', 'stripe_id', self.gf('django.db.models.fields.CharField')(max_length=100, null=True))
def backwards(self, orm):
# Changing field 'UserProfile.stripe_id'
db.alter_column('accounts_userprofile', 'stripe_id', self.gf('django.db.models.fields.IntegerField')(null=True))
models = {
'accounts.userprofile': {
'Meta': {'object_name': 'UserProfile'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_pro': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'stripe_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'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'})
}
}
complete_apps = ['accounts']

View File

@ -1,13 +1,10 @@
from django.contrib.auth.models import User
from django.db import models
import caching.base
class UserProfile(caching.base.CachingMixin, models.Model):
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
is_pro = models.BooleanField(default=False)
objects = caching.base.CachingManager()
stripe_id = models.CharField(max_length=100, null=True, blank=True)
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1282,6 +1282,26 @@ div.profile {
text-transform: uppercase;
}
}
a.pro {
background: #DFDFDF;
color: #3299B7;
clear: left;
display: block;
float: left;
font: bold italic 11px $Helvetica;
margin-top: 10px;
padding: 5px 0;
text-align: center;
text-decoration: none;
text-transform: uppercase;
width: 100%;
@include border-radius(3px);
@include box-shadow(0, 0, 3px, #FFF);
&:hover {
background: #D8D8D8;
}
}
}
div.empty-snipts {
background: rgba(128, 128, 128, .08);
@ -1750,6 +1770,33 @@ body.pro {
}
}
}
fieldset {
position: relative;
}
div.payment-errors {
display: none;
}
div.payment-loading {
background: rgba(#F2F2F2, .6);
display: none;
height: 202px;
position: absolute;
top: 37px;
width: 100%;
span {
background: #FFF;
border: 3px solid #3299B7;
color: #666;
display: block;
font-weight: bold;
margin: 80px auto 0 auto;
padding: 10px;
text-align: center;
width: 120px;
@include border-radius;
}
}
div.stripe {
color: #C2C2C2;
font: bold 11px/15px $Helvetica;
@ -1764,6 +1811,14 @@ body.pro {
}
}
}
&.form-horizontal {
fieldset {
padding-top: 18px;
}
div.form-actions {
margin-top: 18px;
}
}
}
}
body.tags {

View File

@ -134,12 +134,12 @@ url=url&&addSlash(url);if(typeof url==='undefined'){url='/api/private/snipt/';th
return url||null;};Site.SiteView=Backbone.View.extend({el:'body',initialize:function(opts){this.$body=$(this.el);this.$html=$('html');this.$html_body=this.$body.add(this.$html);this.$aside_nav=$('aside.nav',this.$body);this.$aside_nav_ul=$('ul',this.$aside_nav);this.$search_form=$('form.search',this.$body);this.$search_query=$('input#search-query',this.$body);this.$search_page_query=$('input.search-query',this.$body);this.$search_queries=this.$search_query.add(this.$search_page_query);this.$snipts=$('section#snipts article.snipt',this.$body);this.$modals=$('div.modal',this.$snipts);this.$main_edit=$('section#main-edit');this.$main=$('section#main');this.$keyboard_shortcuts=$('#keyboard-shortcuts',this.$body);this.$amazon_ads=$('section.amazon',this.$main);this.keyboardShortcuts();this.inFieldLabels();if(this.$amazon_ads.length){this.initAmazonAds();}
var SniptListView=Snipt.SniptListView;this.snipt_list=new SniptListView({'snipts':this.$snipts});var that=this;this.$body.click(function(){if(!window.ui_halted&&!window.from_modal&&window.$selected){window.$selected.trigger('deselect');}
if(window.from_modal){window.from_modal=false;}
that.$aside_nav.removeClass('open');});this.$aside_nav_ul.click(function(e){e.stopPropagation();});$search_queries=this.$search_queries;$search_queries.focus(function(){if(window.$selected){$selected.trigger('deselect');}});this.$body.on('click','a.close',function(){$(this).parent().parent().modal('hide');window.ui_halted=false;return false;});this.$keyboard_shortcuts.on('hidden',function(){window.ui_halted=false;});if(this.$body.hasClass('pro-signup')){var $form=$('form#pro-signup');var $submit=$('button[type="submit"]',$form);var $name=$('input#name');var $cardNumber=$('input#number');var $expMonth=$('select[name="exp-month"]');var $expYear=$('select[name="exp-year"]');var $cvc=$('input#cvc');$form.submit(function(){$submit.attr('disabled','disabled');var errors=false;if(!Stripe.validateCardNumber($cardNumber.val())){$cardNumber.parents('div.control-group').addClass('error');errors=true;}else{$cardNumber.parents('div.control-group').removeClass('error');}
that.$aside_nav.removeClass('open');});this.$aside_nav_ul.click(function(e){e.stopPropagation();});$search_queries=this.$search_queries;$search_queries.focus(function(){if(window.$selected){$selected.trigger('deselect');}});this.$body.on('click','a.close',function(){$(this).parent().parent().modal('hide');window.ui_halted=false;return false;});this.$keyboard_shortcuts.on('hidden',function(){window.ui_halted=false;});if(this.$body.hasClass('pro-signup')){var $form=$('form#pro-signup');var $submit=$('button[type="submit"]',$form);var $name=$('input#name');var $cardNumber=$('input#number');var $expMonth=$('select#exp-month');var $expYear=$('select#exp-year');var $cvc=$('input#cvc');$form.submit(function(){$submit.attr('disabled','disabled');var errors=false;if(!Stripe.validateCardNumber($cardNumber.val())){$cardNumber.parents('div.control-group').addClass('error');errors=true;}else{$cardNumber.parents('div.control-group').removeClass('error');}
if(!Stripe.validateExpiry($expMonth.val(),$expYear.val())){$expMonth.parents('div.control-group').addClass('error');errors=true;}else{$expMonth.parents('div.control-group').removeClass('error');}
if(!Stripe.validateCVC($cvc.val())){$cvc.parents('div.control-group').addClass('error');errors=true;}else{$cvc.parents('div.control-group').removeClass('error');}
if(!errors){Stripe.createToken({name:$name.val(),number:$cardNumber.val(),cvc:$cvc.val(),exp_month:$expMonth.val(),exp_year:$expYear.val()},that.stripeResponseHandler);}else{$submit.removeAttr('disabled');}
if(!errors){$('.payment-errors').hide();$('.payment-loading').show();Stripe.createToken({name:$name.val(),number:$cardNumber.val(),cvc:$cvc.val(),exp_month:$expMonth.val(),exp_year:$expYear.val()},that.stripeResponseHandler);}else{$submit.removeAttr('disabled');}
return false;});}
window.ui_halted=false;},events:{'showKeyboardShortcuts':'showKeyboardShortcuts','click a.mini-profile':'toggleMiniProfile'},keyboardShortcuts:function(){var $body=this.$body;var that=this;$search_queries=this.$search_queries;$search_page_query=this.$search_page_query;$search_query=this.$search_query;$document=$(document);$document.bind('keydown','/',function(e){if(!window.ui_halted){e.preventDefault();if($body.hasClass('search')){$search_page_query.focus();}else{$search_query.focus();}}});$document.bind('keydown','h',function(e){if(!window.ui_halted){window.ui_halted=true;$body.trigger('showKeyboardShortcuts');}else{if(that.$keyboard_shortcuts.is(':visible')){that.$keyboard_shortcuts.modal('hide');}}});$document.bind('keydown','t',function(e){if(!window.ui_halted){window.open('','_blank');}});$document.bind('keydown','r',function(e){if(!window.ui_halted){location.reload(true);}});$document.bind('keydown','Ctrl+h',function(e){if(!window.ui_halted){history.go(-1);}});$document.bind('keydown','Ctrl+l',function(e){if(!window.ui_halted){history.go(1);}});this.$search_queries.bind('keydown','esc',function(e){if(!window.ui_halted){e.preventDefault();this.blur();}});},showKeyboardShortcuts:function(){this.$keyboard_shortcuts.modal('toggle');},toggleMiniProfile:function(e){this.$aside_nav.toggleClass('open');return false;},inFieldLabels:function(){$('div.infield label',this.$body).inFieldLabels({fadeDuration:200});},stripeResponseHandler:function(status,response){console.log(status);console.log(response);if(response.error){}else{}},initAmazonAds:function(){var $more=$('div.more',this.$amazon_ads);var that=this;var adTemplate=$('script#amazon-ad').html();$('a',$more).on('click',function(){var $current=$('li:visible',that.$amazon_ads);$('li',that.$amazon_ads).hide();if($(this).hasClass('see-previous')){var $prev=$current.prev();if($prev.length){$prev=$prev;}else{$prev=$('li',that.$amazon_ads).eq(-1);}
window.ui_halted=false;},events:{'showKeyboardShortcuts':'showKeyboardShortcuts','click a.mini-profile':'toggleMiniProfile'},keyboardShortcuts:function(){var $body=this.$body;var that=this;$search_queries=this.$search_queries;$search_page_query=this.$search_page_query;$search_query=this.$search_query;$document=$(document);$document.bind('keydown','/',function(e){if(!window.ui_halted){e.preventDefault();if($body.hasClass('search')){$search_page_query.focus();}else{$search_query.focus();}}});$document.bind('keydown','h',function(e){if(!window.ui_halted){window.ui_halted=true;$body.trigger('showKeyboardShortcuts');}else{if(that.$keyboard_shortcuts.is(':visible')){that.$keyboard_shortcuts.modal('hide');}}});$document.bind('keydown','t',function(e){if(!window.ui_halted){window.open('','_blank');}});$document.bind('keydown','r',function(e){if(!window.ui_halted){location.reload(true);}});$document.bind('keydown','Ctrl+h',function(e){if(!window.ui_halted){history.go(-1);}});$document.bind('keydown','Ctrl+l',function(e){if(!window.ui_halted){history.go(1);}});this.$search_queries.bind('keydown','esc',function(e){if(!window.ui_halted){e.preventDefault();this.blur();}});},showKeyboardShortcuts:function(){this.$keyboard_shortcuts.modal('toggle');},toggleMiniProfile:function(e){this.$aside_nav.toggleClass('open');return false;},inFieldLabels:function(){$('div.infield label',this.$body).inFieldLabels({fadeDuration:200});},stripeResponseHandler:function(status,response){var $form=$('form#pro-signup');if(response.error){$('button[type="submit"]',$form).removeAttr('disabled');$('.payment-loading').hide();$('.payment-errors').text(response.error.message).show();}else{var token=response.id;$('input#name').val('');$('input#number').val('');$('select#exp-month').val('');$('select#exp-year').val('');$('input#cvc').val('');$form.append("<input type='hidden' name='token' value='"+token+"'/>");$form.get(0).submit();}},initAmazonAds:function(){var $more=$('div.more',this.$amazon_ads);var that=this;var adTemplate=$('script#amazon-ad').html();$('a',$more).on('click',function(){var $current=$('li:visible',that.$amazon_ads);$('li',that.$amazon_ads).hide();if($(this).hasClass('see-previous')){var $prev=$current.prev();if($prev.length){$prev=$prev;}else{$prev=$('li',that.$amazon_ads).eq(-1);}
$prev.fadeIn('fast');}else{var $next=$current.next();if($next.length){$next=$next;}else{$next=$('li',that.$amazon_ads).eq(0);}
$next.fadeIn('fast');}
return false;});$.getJSON('/api/public/a/',{'q':window.tag},function(resp){if(resp.result.length===0){that.$amazon_ads.slideUp('fast');}else{var html='';for(var i=0;i<resp.result.length;i++){if(resp.result[i].image){html+=_.template(adTemplate,{url:resp.result[i].url,title:resp.result[i].title,review:resp.result[i].review,image:resp.result[i].image});}}

View File

@ -103,8 +103,8 @@
var $name = $('input#name');
var $cardNumber = $('input#number');
var $expMonth = $('select[name="exp-month"]');
var $expYear = $('select[name="exp-year"]');
var $expMonth = $('select#exp-month');
var $expYear = $('select#exp-year');
var $cvc = $('input#cvc');
$form.submit(function() {
@ -135,6 +135,10 @@
}
if (!errors) {
$('.payment-errors').hide();
$('.payment-loading').show();
Stripe.createToken({
name: $name.val(),
number: $cardNumber.val(),
@ -142,6 +146,7 @@
exp_month: $expMonth.val(),
exp_year: $expYear.val()
}, that.stripeResponseHandler);
} else {
$submit.removeAttr('disabled');
}
@ -227,19 +232,27 @@
});
},
stripeResponseHandler: function(status, response) {
console.log(status);
console.log(response);
var $form = $('form#pro-signup');
if (response.error) {
// show the errors on the form
//$(".payment-errors").text(response.error.message);
$('button[type="submit"]', $form).removeAttr('disabled');
$('.payment-loading').hide();
$('.payment-errors').text(response.error.message).show();
} else {
//var form$ = $("#payment-form");
// token contains id, last4, and card type
//var token = response['id'];
// insert the token into the form so it gets submitted to the server
//form$.append("<input type='hidden' name='stripeToken' value='" + token + "'/>");
// and submit
//form$.get(0).submit();
var token = response.id;
// Kill all of the form details so none of it touches our server.
// Note, this is unnecessary, because the inputs themselves do not
// have a name attr, meaning they'll never get sent to begin with.
$('input#name').val('');
$('input#number').val('');
$('select#exp-month').val('');
$('select#exp-year').val('');
$('input#cvc').val('');
$form.append("<input type='hidden' name='token' value='" + token + "'/>");
$form.get(0).submit();
}
},
initAmazonAds: function() {

View File

@ -4,12 +4,12 @@ url=url&&addSlash(url);if(typeof url==='undefined'){url='/api/private/snipt/';th
return url||null;};Site.SiteView=Backbone.View.extend({el:'body',initialize:function(opts){this.$body=$(this.el);this.$html=$('html');this.$html_body=this.$body.add(this.$html);this.$aside_nav=$('aside.nav',this.$body);this.$aside_nav_ul=$('ul',this.$aside_nav);this.$search_form=$('form.search',this.$body);this.$search_query=$('input#search-query',this.$body);this.$search_page_query=$('input.search-query',this.$body);this.$search_queries=this.$search_query.add(this.$search_page_query);this.$snipts=$('section#snipts article.snipt',this.$body);this.$modals=$('div.modal',this.$snipts);this.$main_edit=$('section#main-edit');this.$main=$('section#main');this.$keyboard_shortcuts=$('#keyboard-shortcuts',this.$body);this.$amazon_ads=$('section.amazon',this.$main);this.keyboardShortcuts();this.inFieldLabels();if(this.$amazon_ads.length){this.initAmazonAds();}
var SniptListView=Snipt.SniptListView;this.snipt_list=new SniptListView({'snipts':this.$snipts});var that=this;this.$body.click(function(){if(!window.ui_halted&&!window.from_modal&&window.$selected){window.$selected.trigger('deselect');}
if(window.from_modal){window.from_modal=false;}
that.$aside_nav.removeClass('open');});this.$aside_nav_ul.click(function(e){e.stopPropagation();});$search_queries=this.$search_queries;$search_queries.focus(function(){if(window.$selected){$selected.trigger('deselect');}});this.$body.on('click','a.close',function(){$(this).parent().parent().modal('hide');window.ui_halted=false;return false;});this.$keyboard_shortcuts.on('hidden',function(){window.ui_halted=false;});if(this.$body.hasClass('pro-signup')){var $form=$('form#pro-signup');var $submit=$('button[type="submit"]',$form);var $name=$('input#name');var $cardNumber=$('input#number');var $expMonth=$('select[name="exp-month"]');var $expYear=$('select[name="exp-year"]');var $cvc=$('input#cvc');$form.submit(function(){$submit.attr('disabled','disabled');var errors=false;if(!Stripe.validateCardNumber($cardNumber.val())){$cardNumber.parents('div.control-group').addClass('error');errors=true;}else{$cardNumber.parents('div.control-group').removeClass('error');}
that.$aside_nav.removeClass('open');});this.$aside_nav_ul.click(function(e){e.stopPropagation();});$search_queries=this.$search_queries;$search_queries.focus(function(){if(window.$selected){$selected.trigger('deselect');}});this.$body.on('click','a.close',function(){$(this).parent().parent().modal('hide');window.ui_halted=false;return false;});this.$keyboard_shortcuts.on('hidden',function(){window.ui_halted=false;});if(this.$body.hasClass('pro-signup')){var $form=$('form#pro-signup');var $submit=$('button[type="submit"]',$form);var $name=$('input#name');var $cardNumber=$('input#number');var $expMonth=$('select#exp-month');var $expYear=$('select#exp-year');var $cvc=$('input#cvc');$form.submit(function(){$submit.attr('disabled','disabled');var errors=false;if(!Stripe.validateCardNumber($cardNumber.val())){$cardNumber.parents('div.control-group').addClass('error');errors=true;}else{$cardNumber.parents('div.control-group').removeClass('error');}
if(!Stripe.validateExpiry($expMonth.val(),$expYear.val())){$expMonth.parents('div.control-group').addClass('error');errors=true;}else{$expMonth.parents('div.control-group').removeClass('error');}
if(!Stripe.validateCVC($cvc.val())){$cvc.parents('div.control-group').addClass('error');errors=true;}else{$cvc.parents('div.control-group').removeClass('error');}
if(!errors){Stripe.createToken({name:$name.val(),number:$cardNumber.val(),cvc:$cvc.val(),exp_month:$expMonth.val(),exp_year:$expYear.val()},that.stripeResponseHandler);}else{$submit.removeAttr('disabled');}
if(!errors){$('.payment-errors').hide();$('.payment-loading').show();Stripe.createToken({name:$name.val(),number:$cardNumber.val(),cvc:$cvc.val(),exp_month:$expMonth.val(),exp_year:$expYear.val()},that.stripeResponseHandler);}else{$submit.removeAttr('disabled');}
return false;});}
window.ui_halted=false;},events:{'showKeyboardShortcuts':'showKeyboardShortcuts','click a.mini-profile':'toggleMiniProfile'},keyboardShortcuts:function(){var $body=this.$body;var that=this;$search_queries=this.$search_queries;$search_page_query=this.$search_page_query;$search_query=this.$search_query;$document=$(document);$document.bind('keydown','/',function(e){if(!window.ui_halted){e.preventDefault();if($body.hasClass('search')){$search_page_query.focus();}else{$search_query.focus();}}});$document.bind('keydown','h',function(e){if(!window.ui_halted){window.ui_halted=true;$body.trigger('showKeyboardShortcuts');}else{if(that.$keyboard_shortcuts.is(':visible')){that.$keyboard_shortcuts.modal('hide');}}});$document.bind('keydown','t',function(e){if(!window.ui_halted){window.open('','_blank');}});$document.bind('keydown','r',function(e){if(!window.ui_halted){location.reload(true);}});$document.bind('keydown','Ctrl+h',function(e){if(!window.ui_halted){history.go(-1);}});$document.bind('keydown','Ctrl+l',function(e){if(!window.ui_halted){history.go(1);}});this.$search_queries.bind('keydown','esc',function(e){if(!window.ui_halted){e.preventDefault();this.blur();}});},showKeyboardShortcuts:function(){this.$keyboard_shortcuts.modal('toggle');},toggleMiniProfile:function(e){this.$aside_nav.toggleClass('open');return false;},inFieldLabels:function(){$('div.infield label',this.$body).inFieldLabels({fadeDuration:200});},stripeResponseHandler:function(status,response){console.log(status);console.log(response);if(response.error){}else{}},initAmazonAds:function(){var $more=$('div.more',this.$amazon_ads);var that=this;var adTemplate=$('script#amazon-ad').html();$('a',$more).on('click',function(){var $current=$('li:visible',that.$amazon_ads);$('li',that.$amazon_ads).hide();if($(this).hasClass('see-previous')){var $prev=$current.prev();if($prev.length){$prev=$prev;}else{$prev=$('li',that.$amazon_ads).eq(-1);}
window.ui_halted=false;},events:{'showKeyboardShortcuts':'showKeyboardShortcuts','click a.mini-profile':'toggleMiniProfile'},keyboardShortcuts:function(){var $body=this.$body;var that=this;$search_queries=this.$search_queries;$search_page_query=this.$search_page_query;$search_query=this.$search_query;$document=$(document);$document.bind('keydown','/',function(e){if(!window.ui_halted){e.preventDefault();if($body.hasClass('search')){$search_page_query.focus();}else{$search_query.focus();}}});$document.bind('keydown','h',function(e){if(!window.ui_halted){window.ui_halted=true;$body.trigger('showKeyboardShortcuts');}else{if(that.$keyboard_shortcuts.is(':visible')){that.$keyboard_shortcuts.modal('hide');}}});$document.bind('keydown','t',function(e){if(!window.ui_halted){window.open('','_blank');}});$document.bind('keydown','r',function(e){if(!window.ui_halted){location.reload(true);}});$document.bind('keydown','Ctrl+h',function(e){if(!window.ui_halted){history.go(-1);}});$document.bind('keydown','Ctrl+l',function(e){if(!window.ui_halted){history.go(1);}});this.$search_queries.bind('keydown','esc',function(e){if(!window.ui_halted){e.preventDefault();this.blur();}});},showKeyboardShortcuts:function(){this.$keyboard_shortcuts.modal('toggle');},toggleMiniProfile:function(e){this.$aside_nav.toggleClass('open');return false;},inFieldLabels:function(){$('div.infield label',this.$body).inFieldLabels({fadeDuration:200});},stripeResponseHandler:function(status,response){var $form=$('form#pro-signup');if(response.error){$('button[type="submit"]',$form).removeAttr('disabled');$('.payment-loading').hide();$('.payment-errors').text(response.error.message).show();}else{var token=response.id;$('input#name').val('');$('input#number').val('');$('select#exp-month').val('');$('select#exp-year').val('');$('input#cvc').val('');$form.append("<input type='hidden' name='token' value='"+token+"'/>");$form.get(0).submit();}},initAmazonAds:function(){var $more=$('div.more',this.$amazon_ads);var that=this;var adTemplate=$('script#amazon-ad').html();$('a',$more).on('click',function(){var $current=$('li:visible',that.$amazon_ads);$('li',that.$amazon_ads).hide();if($(this).hasClass('see-previous')){var $prev=$current.prev();if($prev.length){$prev=$prev;}else{$prev=$('li',that.$amazon_ads).eq(-1);}
$prev.fadeIn('fast');}else{var $next=$current.next();if($next.length){$next=$next;}else{$next=$('li',that.$amazon_ads).eq(0);}
$next.fadeIn('fast');}
return false;});$.getJSON('/api/public/a/',{'q':window.tag},function(resp){if(resp.result.length===0){that.$amazon_ads.slideUp('fast');}else{var html='';for(var i=0;i<resp.result.length;i++){if(resp.result[i].image){html+=_.template(adTemplate,{url:resp.result[i].url,title:resp.result[i].title,review:resp.result[i].review,image:resp.result[i].image});}}

View File

@ -15,12 +15,10 @@ from snipts.utils import slugify_uniquely
import datetime, md5, re
import caching.base
site = Site.objects.all()[0]
class Snipt(caching.base.CachingMixin, models.Model):
class Snipt(models.Model):
"""An individual Snipt."""
user = models.ForeignKey(User, blank=True, null=True)
@ -44,8 +42,6 @@ class Snipt(caching.base.CachingMixin, models.Model):
modified = models.DateTimeField(auto_now=True, editable=False)
publish_date = models.DateTimeField(blank=True, null=True)
objects = caching.base.CachingManager()
def save(self, *args, **kwargs):
if not self.slug:
@ -158,14 +154,12 @@ class Snipt(caching.base.CachingMixin, models.Model):
else:
return get_lexer_by_name(self.lexer).name
class Favorite(caching.base.CachingMixin, models.Model):
class Favorite(models.Model):
snipt = models.ForeignKey(Snipt)
user = models.ForeignKey(User)
created = models.DateTimeField(auto_now_add=True, editable=False)
modified = models.DateTimeField(auto_now=True, editable=False)
objects = caching.base.CachingManager()
def __unicode__(self):
return u'{} favorited by {}'.format(self.snipt.title, self.user.username)

View File

@ -33,6 +33,9 @@
{% endif %}
{% endif %}
</div>
{% if user.profile.is_pro %}
<a class="pro" href="/pro/">Pro</a>
{% endif %}
</div>
{% include "snipts/tags-user.html" %}
{% endblock %}

View File

@ -165,7 +165,7 @@
<div class="heading">
<h1>{{ tag.name }}</h1>
</div>
<section class="amazon">
<section class="amazon {% if request.user.is_authenticated %}{% if request.user.profile.is_pro %}hidden{% endif %}{% endif %}">
<ul></ul>
<div class="more group">
<span></span>

View File

@ -0,0 +1,21 @@
{% extends "base.html" %}
{% block page-title %}Sign up for Snipt Pro{% endblock %}
{% block body-class %}{{ block.super }} static pro pro-signup{% endblock %}
{% block breadcrumb %}
<li><a href="/pro/">Snipt Pro</a></li>
<li><span class="prompt">/</span> <a href="/pro/signup/">Sign up</a></li>
<li><span class="prompt">/</span> <a href="#">Complete</a></li>
{% endblock %}
{% block content %}
<div class="static-box">
<h2>Snipt <span class="pro">Pro</span> members</h2>
<p><strong>Congratulations!</strong> You're now a Snipt Pro.</p>
<p>You should <a target="blank" href="http://twitter.com/intent/tweet?text=I'm now a Snipt Pro. Are you? https://snipt.net/pro/">tell the world</a>. If you ever need anything at all, <a href="mailto:nick@snipt.net">email Nick</a> directly.</p>
<p>We'll bill you again (for $19 USD) exactly one year from now. We'll give you a heads up.</p>
<p>Also, you rock. :)</p>
</div>
{% endblock %}

View File

@ -10,7 +10,7 @@
{% block js %}
{{ block.super }}
Stripe.setPublishableKey('pk_RUeu9JcZVSzIr9qsJAnYrNJntJ8Vd');
Stripe.setPublishableKey('pk_dHS5OwimSS1q73HB1YejiNfw37eI3');
{% endblock %}
{% block breadcrumb %}
@ -24,19 +24,21 @@
<img src="/static/images/stripe.png" alt="" />
</a>
<h2>Snipt <span class="pro">Pro</span> signup</h2>
<form class="form-horizontal" id="pro-signup" method="post" action="">
<form class="form-horizontal" id="pro-signup" method="post" action="/pro/signup/complete/">
<fieldset>
<div class="payment-loading"><span>Please wait&hellip;</span></div>
<legend>$19 USD will be charged to your card annually. Also, you rock. Tell yourself that every year, too.</legend>
<div class="payment-errors alert alert-error"></div>
<div class="control-group">
<label class="control-label" for="name">Name on card:</label>
<div class="controls">
<input type="text" class="input-xlarge" id="name">
<input type="text" class="input-xlarge" id="name" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="number">Card number:</label>
<div class="controls cards">
<input type="text" class="input-xlarge" id="number">
<input type="text" class="input-xlarge" id="number" />
<img src="/static/images/card-visa.png" alt="Visa" />
<img src="/static/images/card-mastercard.png" alt="MasterCard" />
<img src="/static/images/card-discover.png" alt="Discover" />
@ -46,7 +48,7 @@
<div class="control-group">
<label class="control-label" for="exp-month">Expiration date:</label>
<div class="controls">
<select name="exp-month" class="span2 exp-month">
<select id="exp-month" class="span2 exp-month">
<option value="">----</option>
<option value="01">01 - January</option>
<option value="02">02 - February</option>
@ -61,7 +63,7 @@
<option value="11">11 - November</option>
<option value="12">12 - December</option>
</select>
<select name="exp-year" class="span1">
<select id="exp-year" class="span1">
<option value="">----</option>
<option value="2012">2012</option>
<option value="2013">2013</option>
@ -84,6 +86,7 @@
</div>
</div>
<div class="form-actions">
{% csrf_token %}
<button type="submit" class="btn btn-success">Sign up</button>
<div class="security">
<a href="https://stripe.com/help/security">Secure</a> by default. Every page on Snipt is secured with HTTPS.

View File

@ -16,7 +16,7 @@
<ul>
<li>No advertisements.</li>
<li>&ldquo;Pro&rdquo; badge throughout the site.</li>
<li>You&rsquo;re supporting current and future development. This stuff takes time and money.</li>
<li>You&rsquo;re <strong>supporting</strong> current and future development. This stuff takes time and money.</li>
</ul>
<h6>Planned Pro features (not in order):</h6>
<ul>
@ -25,8 +25,7 @@
<li>Ability to theme your embedded snipts in a specific theme.</li>
<li>Custom domain and premium (Pro-only) themes for your <a href="https://blog.snipt.net/announcing-the-sniptnet-blogging-platform/">Snipt blog</a>.</li>
</ul>
<h3>Pro accounts are opening soon&hellip; sit tight!</h3>
<!--<h3>Pro accounts are $19/year.</h3>-->
<!--<h4><a href="/pro/signup/" class="btn btn-large btn-success">Sign Up Now</a></h4>-->
<h3>Pro accounts are just $19/year.</h3>
<h4><a href="/pro/signup/" class="btn btn-large btn-success">Sign Up Now</a></h4>
</div>
{% endblock %}

View File

@ -1,4 +1,4 @@
from views import amazon_search, amazon_image, lexers, pro_signup, sitemap, tags
from views import amazon_search, amazon_image, lexers, pro_signup, sitemap, tags, pro_signup_complete
from django.conf.urls.defaults import include, patterns, url
from django.views.generic.simple import direct_to_template
from registration.forms import RegistrationFormUniqueEmail
@ -34,9 +34,11 @@ urlpatterns = patterns('',
url(r'^robots.txt$', direct_to_template, {'template': 'robots.txt'}),
url(r'^humans.txt$', direct_to_template, {'template': 'humans.txt'}),
url(r'^sitemap.xml$', sitemap),
url(r'^tags/$', tags),
url(r'^pro/$', direct_to_template, {'template': 'pro.html'}),
url(r'^pro/signup/$', pro_signup),
url(r'^tags/$', tags),
url(r'^pro/signup/complete/$', pro_signup_complete),
url(r'^api/public/lexer/$', lexers),
url(r'^api/public/a/$', amazon_search),

View File

@ -12,6 +12,8 @@ from taggit.models import Tag
import os, urllib
import stripe
@ajax_request
def amazon_search(request):
@ -95,6 +97,31 @@ def pro_signup(request):
return HttpResponseRedirect('/' + request.user.username + '/')
return {}
@login_required
@render_to('pro-signup-complete.html')
def pro_signup_complete(request):
if request.method == 'POST':
token = request.POST['token']
stripe.api_key = '5XchbRsWVbksTRWSX67kOdBnCf01DxSh'
customer = stripe.Customer.create(
card = token,
plan = 'snipt-pro',
email = request.user.email
)
profile = request.user.profile
profile.is_pro = True
profile.stripe_id = customer.id
profile.save()
return {}
else:
return HttpResponseBadRequest()
def sitemap(request):
tags = Tag.objects.filter(snipt__public=True)