Moar Heroku stuff.

master
Nick Sergeant 2016-11-01 14:21:39 -04:00
parent c104e7aacf
commit a2a81bbe02
14 changed files with 2021 additions and 158 deletions

View File

@ -1,4 +1,70 @@
assets:
@cat media/css/bootstrap.min.css \
media/css/blog-themes/pro-adams/style.css \
media/css/highlightjs-themes/tomorrow.css \
media/css/themes.css \
> media/css/pro.css
@cat media/css/bootstrap.min.css \
media/css/style.css \
media/css/themes.css \
media/css/chosen.css \
media/css/codemirror.css \
media/css/codemirror-themes/ambiance.css \
media/css/codemirror-themes/blackboard.css \
media/css/codemirror-themes/cobalt.css \
media/css/codemirror-themes/eclipse.css \
media/css/codemirror-themes/elegant.css \
media/css/codemirror-themes/erlang-dark.css \
media/css/codemirror-themes/lesser-dark.css \
media/css/codemirror-themes/monokai.css \
media/css/codemirror-themes/neat.css \
media/css/codemirror-themes/night.css \
media/css/codemirror-themes/rubyblue.css \
media/css/codemirror-themes/solarized.css \
media/css/codemirror-themes/twilight.css \
media/css/codemirror-themes/vibrant-ink.css \
media/css/codemirror-themes/xq-dark.css \
media/css/highlightjs-themes/tomorrow.css \
media/css/blog-themes/default/style.css \
> media/css/snipt.css
@cat media/js/src/account.js > media/js/src/account.min.js
@cat media/js/src/snipts.js > media/js/src/snipts.min.js
@cat media/js/src/jobs.js > media/js/src/jobs.min.js
@cat media/js/src/application.js > media/js/src/application.min.js
@cat media/js/src/team.js > media/js/src/team.min.js
@cat media/js/src/modules/site.js > media/js/src/modules/site.min.js
@cat media/js/src/modules/snipt.js > media/js/src/modules/snipt.min.js
@cat media/js/src/pro.js > media/js/src/pro.min.js
@cat media/js/libs/jquery.min.js \
media/js/libs/jquery-ui.min.js \
media/js/libs/angular.min.js \
media/js/libs/angular-route.min.js \
media/js/libs/underscore.js \
media/js/libs/json2.js \
media/js/libs/backbone.js \
media/js/libs/bootstrap.min.js \
media/js/plugins/jquery.hotkeys.js \
media/js/plugins/jquery.infieldlabel.js \
media/js/plugins/jquery.chosen.js \
media/js/src/application.min.js \
media/js/src/modules/site.min.js \
media/js/src/modules/snipt.min.js \
media/js/src/account.min.js \
media/js/src/snipts.min.js \
media/js/src/jobs.min.js \
media/js/src/team.min.js \
media/js/libs/codemirror.js \
media/js/libs/highlight.js \
> media/js/snipt-all.min.js
@cat media/js/libs/highlight.js \
media/js/src/pro.js \
> media/js/pro-all.min.js
deploy: deploy:
make assets
git add .
git commit -m "Asset autocompilation."
git push
git push heroku heroku:master git push heroku heroku:master
sass: sass:

View File

@ -1,12 +1,6 @@
import datetime
import os
import stripe
from annoying.decorators import render_to from annoying.decorators import render_to
from django.conf import settings
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.core.mail import send_mail from django.http import HttpResponseRedirect
from django.http import HttpResponseBadRequest, HttpResponseRedirect
from snipts.models import Snipt from snipts.models import Snipt
@ -19,49 +13,9 @@ def account(request):
@login_required @login_required
@render_to('activate.html') @render_to('activate.html')
def activate(request): def activate(request):
request.user.is_active = True
if request.method == 'POST': request.user.save()
return HttpResponseRedirect('/login-redirect/')
if 'stripeToken' not in request.POST:
return HttpResponseBadRequest()
token = request.POST['stripeToken']
stripe.api_key = os.environ.get('STRIPE_SECRET_KEY',
settings.STRIPE_SECRET_KEY)
try:
customer = stripe.Customer.create(card=token,
email=request.user.email)
stripe.Charge.create(amount=500,
currency='usd',
customer=customer.id,
description='Snipt.net')
except stripe.CardError as e:
error_message = e.json_body['error']['message']
return HttpResponseRedirect('/account/activate/?declined=%s' % error_message or
'Your card was declined.')
profile = request.user.profile
profile.pro_date = datetime.datetime.now()
profile.stripe_id = customer.id
profile.save()
request.user.is_active = True
request.user.save()
send_mail('[Snipt] New signup: {}'.format(request.user.username),
"""
User: https://snipt.net/{}
Email: {}
""".format(request.user.username, request.user.email),
'support@snipt.net',
['nick@snipt.net'],
fail_silently=False)
return HttpResponseRedirect('/login-redirect/')
else:
return {}
@login_required @login_required

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,14 +1,198 @@
(function(Site) {
(function(Site){var Snipt=snipt.module('snipt');Backbone.oldSync=Backbone.sync;Backbone.Model.prototype.idAttribute='resource_uri';var addSlash=function(str){return str+((str.length>0&&str.charAt(str.length-1)==='/')?'':'/');};Backbone.sync=function(method,model,options){options.headers=_.extend({'Authorization':'ApiKey '+window.user+':'+window.api_key},options.headers);return Backbone.oldSync(method,model,options);};Backbone.Model.prototype.url=function(){var url=this.id;if(!url){url=this.urlRoot;url=url||this.collection&&(_.isFunction(this.collection.url)?this.collection.url():this.collection.url);if(url&&this.has('id')){url=addSlash(url)+this.get('id');}} var Snipt = snipt.module('snipt');
url=url&&addSlash(url);if(typeof url==='undefined'){url='/api/private/snipt/';this.unset('id',{'silent':true});this.unset('user',{'silent':true});}
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_main=$('aside.main',this.$body);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.keyboardShortcuts();this.inFieldLabels();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');} Backbone.oldSync = Backbone.sync;
if(window.from_modal){window.from_modal=false;} Backbone.Model.prototype.idAttribute = 'resource_uri';
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');} var addSlash = function(str) {
if(!Stripe.validateExpiry($expMonth.val(),$expYear.val())){$expMonth.parents('div.control-group').addClass('error');errors=true;}else{$expMonth.parents('div.control-group').removeClass('error');} return str + ((str.length > 0 && str.charAt(str.length - 1) === '/') ? '' : '/');
if(!Stripe.validateCVC($cvc.val())){$cvc.parents('div.control-group').addClass('error');errors=true;}else{$cvc.parents('div.control-group').removeClass('error');} };
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');} Backbone.sync = function(method, model, options) {
return false;});} options.headers = _.extend({
if(this.$body.hasClass('login')){$('input#id_username').focus();} 'Authorization': 'ApiKey ' + window.user + ':' + window.api_key
if(window.gittip_username){this.$aside_main.html(this.$aside_main.html().replace(/\[\[.*gittip.*\]\]/,'<iframe style="border: 0; margin: 0; padding: 0;" src="https://www.gittip.com/'+window.gittip_username+'/widget.html" width="48pt" height="22pt"></iframe>'));$('iframe',this.$aside_main).parent('p').prev('p').css('margin-bottom','10px');} }, options.headers);
$('div.markdown pre code').each(function(i,e){hljs.highlightBlock(e);});var $embeddedTweets=$('div.embedded-tweet');if($embeddedTweets.length){$.each($embeddedTweets,function(){var $tweetPlaceholder=$(this);var tweetID=$tweetPlaceholder.attr('data-tweet-id');$.ajax({url:'https://api.twitter.com/1/statuses/oembed.json?id='+tweetID+'&align=center',dataType:'jsonp',type:'get',success:function(resp){$tweetPlaceholder.replaceWith($(resp.html));}});});} return Backbone.oldSync(method, model, options);
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','Ctrl+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');}}});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();}}});})(snipt.module('site')); };
Backbone.Model.prototype.url = function() {
var url = this.id;
if (!url) {
url = this.urlRoot;
url = url || this.collection && (_.isFunction(this.collection.url) ? this.collection.url() : this.collection.url);
if (url && this.has('id')) {
url = addSlash(url) + this.get('id');
}
}
url = url && addSlash(url);
if (typeof url === 'undefined') {
url = '/api/private/snipt/';
this.unset('id', {'silent': true});
this.unset('user', {'silent': true});
}
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_main = $('aside.main', this.$body);
this.$aside_nav = $('aside.nav', this.$body);
this.$teams_nav = $('li.teams-nav', this.$body);
this.$add_snipt = $('li.add-snipt', 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.keyboardShortcuts();
this.inFieldLabels();
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');
that.$teams_nav.removeClass('open');
that.$add_snipt.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('login')) {
$('input#id_username').focus();
}
// Populate any GitTip widgets.
if (window.gittip_username) {
this.$aside_main.html(this.$aside_main.html().replace(
/\[\[.*gittip.*\]\]/,
'<iframe style="border: 0; margin: 0; padding: 0;" src="https://www.gittip.com/' + window.gittip_username + '/widget.html" width="48pt" height="22pt"></iframe>')
);
$('iframe', this.$aside_main).parent('p').prev('p').css('margin-bottom', '10px');
}
// Highlight any Markdown code.
$('div.markdown pre code').each(function(i, e) {
hljs.highlightBlock(e);
});
// Populate any embedded tweets.
var $embeddedTweets = $('div.embedded-tweet');
if ($embeddedTweets.length) {
$.each($embeddedTweets, function() {
var $tweetPlaceholder = $(this);
var tweetID = $tweetPlaceholder.attr('data-tweet-id');
$.ajax({
url: 'https://api.twitter.com/1/statuses/oembed.json?id=' + tweetID + '&align=center',
dataType: 'jsonp',
type: 'get',
success: function(resp) {
$tweetPlaceholder.replaceWith($(resp.html));
}
});
});
}
window.ui_halted = false;
},
events: {
'showKeyboardShortcuts': 'showKeyboardShortcuts',
'click a.mini-profile': 'toggleMiniProfile',
'click a.teams-nav': 'toggleTeamsNav'
},
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', 'Ctrl+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');
}
}
});
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;
},
toggleTeamsNav: function(e) {
this.$teams_nav.toggleClass('open');
return false;
},
inFieldLabels: function () {
$('div.infield label', this.$body).inFieldLabels({
fadeDuration: 200
});
}
});
})(snipt.module('site'));

45
media/js/src/team.min.js vendored Normal file
View File

@ -0,0 +1,45 @@
(function() { 'use strict';
if (typeof angular !== 'undefined') {
var root = this;
var $ = root.jQuery;
var controllers = {};
var app = root.app;
// Services.
app.factory('TeamStorage', function($http, $q) {
return {
searchUsers: function(query) {
var promise = $http({
method: 'GET',
url: '/api/public/user/?format=json&limit=100&username__contains=' + query
});
return promise;
}
};
});
// Controllers.
controllers.TeamController = function($scope, $timeout, TeamStorage) {
$scope.users = [];
$scope.search = '';
$scope.$watch('search', function(val) {
$timeout.cancel($scope.timeout);
if (!val) return $scope.users = [];
$scope.timeout = $timeout(function() {
TeamStorage.searchUsers(val).then(function(response) {
$scope.users = response.data.objects;
});
}, 350);
});
};
// Assign the controllers.
app.controller(controllers);
}
}).call(this);

View File

@ -1,11 +0,0 @@
<div class="google-ads" style="margin-top: 30px;">
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- New Snipt Leaderboard -->
<ins class="adsbygoogle"
style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-6776929316186576"
data-ad-slot="5792558066"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>

View File

@ -1,4 +0,0 @@
<a href="/signup" class="snipt-promo">
<button class="btn btn-success btn-large pull-right">Sign up &raquo;</button>
Sign up for Snipt!<br /><span style="font-size: 16px;">Post public snipts for free.</span>
</a>

View File

@ -1,5 +0,0 @@
<a href="/for-teams/" class="snipt-promo">
<button class="btn btn-success btn-large pull-right">More info &raquo;</button>
Announcing Snipt for Teams! <br />
<span style="font-size: 80%;">Share access to snippets, detailed diffs, and more.</span>
</a>

View File

@ -1,4 +0,0 @@
<a href="/signup/" class="snipt-promo">
<button class="btn btn-success btn-large pull-right">Sign up &raquo;</button>
Sign up for <span class="pro -logo">Snip<span>t</span></span>: store and share your own code snippets.
</a>

View File

@ -1,7 +0,0 @@
<div style="margin-left: 15px; margin-bottom: 30px;">
<div style="background-color: white; border-radius: 5px; padding: 10px 10px 7px 10px; box-sizing: border-box;" class="ad-inner">
<!-- BuySellAds Zone Code -->
<div id="bsap_1305837" class="bsarocks bsap_b70f66b78b7f9318d905def548557dc9"></div>
<!-- End BuySellAds Zone Code -->
</div>
</div>

View File

@ -222,13 +222,6 @@
<aside class="main"> <aside class="main">
{% block aside-top %}{% endblock %} {% block aside-top %}{% endblock %}
{% block aside-inner %}{% endblock %} {% block aside-inner %}{% endblock %}
{% if not request.user.is_authenticated %}
<div style="margin-left: 15px; margin-bottom: 30px;">
<div style="background-color: white; border-radius: 5px; margin-top: 30px; padding: 10px; box-sizing: border-box;">
<script type="text/javascript" src="https://d21djfthp4qopy.cloudfront.net/humanitybox.js"></script>
</div>
</div>
{% endif %}
<nav class="footer"> <nav class="footer">
<ul> <ul>
<li class="api"> <li class="api">

View File

@ -21,10 +21,6 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
<fieldset> <fieldset>
<div class="info" style="line-height: 35px;">
Create an account for a one-time fee of <span>$5</span>.<br />
<small style="font-size: 14px; color: #C0C0C0;">Fully refundable within 3 days of signup. All ads removed for paid accounts.</small>
</div>
<div style="padding-top: 30px;" class="control-group {% if form.errors.username %}error{% endif %}"> <div style="padding-top: 30px;" class="control-group {% if form.errors.username %}error{% endif %}">
<label class="control-label" for="id_username">Username</label> <label class="control-label" for="id_username">Username</label>
<div class="controls"> <div class="controls">

View File

@ -7,13 +7,13 @@ from django.http import HttpResponseRedirect
from django.views.generic import RedirectView, TemplateView from django.views.generic import RedirectView, TemplateView
from django.views.static import serve from django.views.static import serve
from forms import AuthenticationFormWithInactiveUsersOkay from forms import AuthenticationFormWithInactiveUsersOkay
from registration.backends.default.views import RegistrationView
from snipts.api import (PublicSniptResource, from snipts.api import (PublicSniptResource,
PublicUserResource, PrivateSniptResource, PublicUserResource, PrivateSniptResource,
PrivateFavoriteResource, PrivateUserProfileResource, PrivateFavoriteResource, PrivateUserProfileResource,
PrivateUserResource, PublicTagResource) PrivateUserResource, PublicTagResource)
from snipts.views import search from snipts.views import search
from tastypie.api import Api from tastypie.api import Api
from utils.views import SniptRegistrationView
from views import (homepage, lexers, login_redirect, from views import (homepage, lexers, login_redirect,
tags, user_api_key) tags, user_api_key)
@ -53,6 +53,8 @@ urlpatterns = [
url(r'^search/$', search), url(r'^search/$', search),
url(r'^register/$', lambda x: HttpResponseRedirect('/signup/')),
url(r'^signup/$', RegistrationView.as_view()),
url(r'^activate/complete/$', RedirectView.as_view( url(r'^activate/complete/$', RedirectView.as_view(
url='/login-redirect/')), url='/login-redirect/')),
url(r'^login/?$', login, { url(r'^login/?$', login, {