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:
make assets
git add .
git commit -m "Asset autocompilation."
git push
git push heroku heroku:master
sass:

View File

@ -1,12 +1,6 @@
import datetime
import os
import stripe
from annoying.decorators import render_to
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.core.mail import send_mail
from django.http import HttpResponseBadRequest, HttpResponseRedirect
from django.http import HttpResponseRedirect
from snipts.models import Snipt
@ -19,50 +13,10 @@ def account(request):
@login_required
@render_to('activate.html')
def activate(request):
if request.method == 'POST':
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
@render_to('stats.html')

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');}}
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');}
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#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){$('.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;});}
if(this.$body.hasClass('login')){$('input#id_username').focus();}
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');}
$('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));}});});}
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'));
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');
}
}
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">
{% block aside-top %}{% 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">
<ul>
<li class="api">

View File

@ -21,10 +21,6 @@
{% endif %}
{% endif %}
<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 %}">
<label class="control-label" for="id_username">Username</label>
<div class="controls">

View File

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