Merge pull request #160 from nicksergeant/heroku

Heroku
master
Nick Sergeant 2016-11-29 23:07:59 -05:00 committed by GitHub
commit 49d83461ac
98 changed files with 2196 additions and 3408 deletions

View File

@ -1,61 +0,0 @@
#!/bin/bash
ACTION=$1
function stop_stack() {
docker stop snipt-proxy > /dev/null
docker stop snipt-app > /dev/null
docker stop snipt-es > /dev/null
docker stop snipt-pg > /dev/null
}
function start_stack() {
docker start snipt-pg > /dev/null
docker start snipt-es > /dev/null
docker start snipt-app > /dev/null
docker start snipt-proxy > /dev/null
}
if [ "$ACTION" = "syncdb" ]; then
docker run -it --rm -e DB_USER=postgres -e DB_NAME=postgres --net container:snipt-net snipt/snipt python manage.py syncdb --noinput
fi
if [ "$ACTION" = "migrate" ]; then
docker run -it --rm -e DB_USER=postgres -e DB_NAME=postgres --net container:snipt-net snipt/snipt python manage.py migrate --noinput
fi
if [ "$ACTION" = "collectstatic" ]; then
docker run -it --rm -v $(pwd)/static:/app/snipt/static --net container:snipt-net snipt/snipt python manage.py collectstatic --noinput
fi
if [ "$ACTION" = "deploy" ]; then
echo "pulling latest image"
docker pull snipt/snipt
echo "stopping app"
docker kill snipt-app
docker rm snipt-app
echo "deploying new container"
docker run -it --name snipt-app -d -e DB_PORT_5432_TCP_ADDR=127.0.0.1 -e DB_PORT_5432_TCP_PORT=5432 -e DB_USER=postgres -e DB_NAME=snipt -e DEBUG=false -v /etc/settings_local.py:/app/snipt/settings_local.py --net container:snipt-net snipt/snipt
sleep 5
docker restart snipt-proxy
echo "done"
fi
if [ "$ACTION" = "restart" ]; then
echo "restarting app"
docker restart snipt-app
fi
if [ "$ACTION" = "restart-stack" ]; then
echo "restarting stack"
stop_stack
start_stack
fi
if [ "$ACTION" = "backupdb" ]; then
echo "backing up db"
docker run --rm --net container:snipt-net --entrypoint pg_dump postgres:9.1 -h 127.0.0.1 -U postgres snipt
fi
if [ "$ACTION" = "psql" ]; then
docker run it --rm --net container:snipt-net --entrypoint psql postgres:9.1 -h 127.0.0.1 -U postgres snipt
fi

View File

@ -1,35 +0,0 @@
#!/bin/bash
COMPONENTS=$*
if [ -z "$COMPONENTS" ]; then
echo "Usage: $0 [components]"
exit 1
fi
for CMP in $COMPONENTS; do
if [ "$CMP" = "postgres" -o "$CMP" = "all" ]; then
echo "destroying postgres"
docker kill snipt-pg > /dev/null
docker rm snipt-pg > /dev/null
fi
if [ "$CMP" = "elasticsearch" -o "$CMP" = "all" ]; then
echo "destroying elasticsearch"
docker kill snipt-es > /dev/null
docker rm snipt-es > /dev/null
fi
if [ "$CMP" = "app" -o "$CMP" = "all" ]; then
echo "destroying app"
docker kill snipt-app > /dev/null
docker rm snipt-app > /dev/null
fi
if [ "$CMP" = "proxy" -o "$CMP" = "all" ]; then
echo "destroying proxy"
docker kill snipt-proxy > /dev/null
docker rm snipt-proxy > /dev/null
fi
if [ "$CMP" = "all" ]; then
echo "destroying shared net"
docker kill snipt-net > /dev/null
docker rm snipt-net > /dev/null
fi
done

View File

@ -1,119 +0,0 @@
user root;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log off;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
upstream backend_snipt {
server 127.0.0.1:8000;
}
server {
listen 80;
server_name *.snipt.net;
if ($host ~* "^([^.]+(\.[^.]+)*)\.snipt.net$"){
set $subd $1;
rewrite ^(.*)$ https://$subd.snipt.net$1 permanent;
break;
}
}
server {
listen 80;
server_name snipt.net www.snipt.net beta.snipt.net;
rewrite ^(.*) https://snipt.net$1 permanent;
}
server {
listen 443;
server_name www.snipt.net;
access_log off;
error_log /logs/nginx.log;
ssl on;
ssl_certificate /etc/certs/2013-dnsimple/snipt.net.crt;
ssl_certificate_key /etc/certs/2013-dnsimple/snipt.net.key;
rewrite ^(.*) https://snipt.net$1 permanent;
}
server {
listen 443;
server_name snipt.net *.snipt.net;
access_log off;
error_log /logs/nginx.log;
ssl on;
ssl_certificate /etc/certs/2013-dnsimple/snipt.net.crt;
ssl_certificate_key /etc/certs/2013-dnsimple/snipt.net.key;
location ~* /favicon.ico {
root /app/snipt/static/img/;
expires max;
}
location / {
rewrite_by_lua '
if string.find(ngx.var.host, "_") then
local newHost, n = ngx.re.gsub(ngx.var.host, "_", "-")
ngx.redirect(ngx.var.scheme .. "://" .. newHost .. ngx.var.uri)
end
';
proxy_pass http://backend_snipt;
proxy_set_header Host $host;
}
location /static/ {
alias /app/snipt/static/;
expires max;
}
location /public/feed/ {
rewrite ^/public/feed/$ https://snipt.net/public/?rss permanent;
}
}
server {
listen 80 default_server;
access_log off;
error_log /logs/nginx.log;
location ~* /favicon.ico {
root /app/snipt/static/img/;
expires max;
}
location / {
proxy_pass http://backend_snipt;
proxy_set_header Host $host;
}
location /static/ {
alias /app/snipt/static/;
expires max;
}
}
}

View File

@ -1,17 +0,0 @@
#!/bin/bash
APP_ROOT=/app
APP_DIR=$APP_ROOT/snipt
COOKIE_DOMAIN=${SESSION_COOKIE_DOMAIN:-.snipt.net}
SECRET_KEY=${SECRET_KEY:-changeme}
if [ ! -e "$APP_DIR/settings_local.py" ]; then
cp $APP_DIR/settings_local-template.py $APP_DIR/settings_local.py
sed -i "s/^SESSION_COOKIE_DOMAIN.*/SESSION_COOKIE_DOMAIN = '$COOKIE_DOMAIN'/g" $APP_DIR/settings_local.py
sed -i "s/^SECRET_KEY.*/SECRET_KEY = '$SECRET_KEY'/g" $APP_DIR/settings_local.py
fi
pushd $APP_DIR
python manage.py syncdb --noinput
python manage.py migrate --noinput
popd
pushd $APP_DIR
python manage.py run_gunicorn -c $APP_DIR/gunicorn.conf.server.py

View File

@ -1,46 +0,0 @@
#!/bin/bash
COMPONENTS=$*
if [ -z "$COMPONENTS" ]; then
echo "Usage: $0 [components]"
exit 1
fi
for CMP in $COMPONENTS; do
if [ "$CMP" = "net" -o "$CMP" = "all" ]; then
# start net container
docker run -it -p 80:80 -p 443:443 --name snipt-net -d debian:jessie bash > /dev/null
sleep 1
fi
if [ "$CMP" = "postgres" -o "$CMP" = "all" ]; then
echo "starting postgres"
docker run -it -d --name snipt-pg --net container:snipt-net postgres:9.1 > /dev/null
# wait for PG to start
sleep 5
# create db
docker run -it --rm --net container:snipt-net --entrypoint createdb postgres:9.1 -h 127.0.0.1 -U postgres -E UTF8 -O postgres snipt
fi
if [ "$CMP" = "elasticsearch" -o "$CMP" = "all" ]; then
echo "starting elasticsearch"
docker run -it -d --name snipt-es --net container:snipt-net arcus/elasticsearch > /dev/null
sleep 1
fi
if [ "$CMP" = "app" -o "$CMP" = "all" ]; then
echo "starting app"
# migrate
docker run -it --rm -e DB_USER=postgres -e DB_NAME=snipt --net container:snipt-net snipt/snipt python manage.py syncdb --noinput
docker run -it --rm -e DB_USER=postgres -e DB_NAME=snipt --net container:snipt-net snipt/snipt python manage.py migrate --noinput
# collect static
docker run -it --rm -v $(pwd)/static:/app/snipt/static --net container:snipt-net snipt/snipt python manage.py collectstatic --noinput
# run app
docker run -it --name snipt-app -d -e DB_PORT_5432_TCP_ADDR=127.0.0.1 -e DB_PORT_5432_TCP_PORT=5432 -e DB_USER=postgres -e DB_NAME=snipt -e DEBUG=false -v /etc/settings_local.py:/app/snipt/settings_local.py --net container:snipt-net snipt/snipt > /dev/null
sleep 1
fi
if [ "$CMP" = "proxy" -o "$CMP" = "all" ]; then
echo "starting proxy"
docker run -d --name snipt-proxy -it -v /var/log/snipt:/logs -v $(pwd)/.docker/nginx.conf:/etc/nginx/nginx.conf -v $(pwd)/static:/app/snipt/static -v /etc/certs:/etc/certs --net container:snipt-net snipt/proxy nginx -g 'daemon off;' -c /etc/nginx/nginx.conf > /dev/null
fi
done

View File

@ -1,8 +0,0 @@
syntax: literal
/migrations/
/static/
/media/js/libs/
syntax: re
/.*\.min\.js$
/.*\jquery.*\.js$

13
.kick
View File

@ -1,13 +0,0 @@
process do |files|
files.take_and_map do |file|
case file
when %r{^(.+).s?css$}
execute "scss -t compressed media/css/style.scss media/css/style.css"
execute "scss -t compressed media/css/blog-themes/default/style.scss media/css/blog-themes/default/style.css"
execute "scss -t compressed media/css/blog-themes/pro-adams/style.scss media/css/blog-themes/pro-adams/style.css"
execute "media/css/compile-css.sh"
when %r{^(.+).js$}
execute "media/js/compile-js.sh"
end
end
end

View File

@ -1,4 +1,4 @@
Copyright (c) 2009-2013 Nick Sergeant
Copyright (c) 2009-2017 Nick Sergeant
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

106
Makefile
View File

@ -1,8 +1,3 @@
pm = /var/www/.virtualenvs/snipt/bin/python /var/www/snipt/manage.py
ssh-server-deploy = ssh deploy@96.126.110.160 -p 55555
ssh-server-root = ssh root@96.126.110.160
ssh-vagrant = ssh vagrant@localhost -p 2222 -i ~/.vagrant.d/insecure_private_key
assets:
@cat media/css/bootstrap.min.css \
media/css/blog-themes/pro-adams/style.css \
@ -56,7 +51,6 @@ assets:
media/js/src/modules/snipt.min.js \
media/js/src/account.min.js \
media/js/src/snipts.min.js \
media/js/src/search.min.js \
media/js/src/jobs.min.js \
media/js/src/team.min.js \
media/js/libs/codemirror.js \
@ -66,106 +60,10 @@ assets:
media/js/src/pro.js \
> media/js/pro-all.min.js
db:
@echo Creating database user snipt:
@sudo -u postgres bash -c 'createuser snipt -P'
@sudo -u postgres bash -c 'createdb snipt -O snipt'
deploy:
@$(ssh-server-deploy) 'cd /var/www/snipt; git pull;'
@$(ssh-server-deploy) 'cd /var/www/snipt; make assets;'
@$(ssh-server-deploy) '$(pm) collectstatic --noinput'
@$(ssh-server-deploy) '$(pm) migrate'
@$(ssh-server-deploy) 'sudo supervisorctl restart snipt'
deploy-heroku:
@git push heroku
run:
@vagrant up
@vagrant ssh -c 'sudo supervisorctl restart snipt && sudo supervisorctl tail -f snipt stderr'
salt-server:
@scp -q -P 55555 settings_local_server.py deploy@96.126.110.160:/var/www/snipt/settings_local.py
@scp -q -P 55555 -r ./salt/ deploy@96.126.110.160:salt
@scp -q -P 55555 -r ./pillar/ deploy@96.126.110.160:pillar
@$(ssh-server-deploy) 'sudo rm -rf /srv'
@$(ssh-server-deploy) 'sudo mkdir /srv'
@$(ssh-server-deploy) 'sudo mv ~/salt /srv/salt'
@$(ssh-server-deploy) 'sudo mv ~/pillar /srv/pillar'
@$(ssh-server-deploy) 'sudo salt-call --local state.highstate'
salt-vagrant:
@scp -q -P 2222 -i ~/.vagrant.d/insecure_private_key -r ./salt/ vagrant@localhost:salt
@scp -q -P 2222 -i ~/.vagrant.d/insecure_private_key -r ./pillar/ vagrant@localhost:pillar
@$(ssh-vagrant) 'sudo rm -rf /srv'
@$(ssh-vagrant) 'sudo mkdir /srv'
@$(ssh-vagrant) 'sudo mv ~/salt /srv/salt'
@$(ssh-vagrant) 'sudo mv ~/pillar /srv/pillar'
@$(ssh-vagrant) 'sudo salt-call --local state.highstate'
server:
@$(ssh-server-root) 'sudo apt-get update'
@$(ssh-server-root) 'sudo apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade'
@$(ssh-server-root) 'sudo apt-get install -y software-properties-common python-software-properties'
@$(ssh-server-root) 'sudo add-apt-repository -y ppa:saltstack/salt'
@$(ssh-server-root) 'sudo apt-get update'
@$(ssh-server-root) 'sudo apt-get install -y salt-minion'
@scp -q -r ./salt/ root@96.126.110.160:salt
@scp -q -r ./pillar/ root@96.126.110.160:pillar
@$(ssh-server-root) 'sudo rm -rf /srv'
@$(ssh-server-root) 'sudo mkdir /srv'
@$(ssh-server-root) 'sudo mv ~/salt /srv/salt'
@$(ssh-server-root) 'sudo mv ~/pillar /srv/pillar'
@$(ssh-server-root) 'sudo salt-call --local state.highstate'
@scp -q -P 55555 settings_local_server.py root@96.126.110.160:/var/www/snipt/settings_local.py
@$(ssh-server-deploy) 'cd /var/www/snipt; make db;'
@$(ssh-server-deploy) '$(pm) syncdb --noinput;'
@$(ssh-server-deploy) '$(pm) migrate;'
@$(ssh-server-deploy) '$(pm) backfill_api_keys;'
@$(ssh-server-deploy) '$(pm) rebuild_index --noinput;'
vagrant:
@vagrant up --provider=vmware_fusion
@$(ssh-vagrant) 'sudo apt-get update'
@$(ssh-vagrant) 'sudo apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade'
@$(ssh-vagrant) 'sudo apt-get install -y software-properties-common python-software-properties'
@$(ssh-vagrant) 'sudo add-apt-repository -y ppa:saltstack/salt'
@$(ssh-vagrant) 'sudo apt-get update'
@$(ssh-vagrant) 'sudo apt-get install -y salt-minion'
@scp -q -P 2222 -i ~/.vagrant.d/insecure_private_key -r ./salt/ vagrant@localhost:salt
@scp -q -P 2222 -i ~/.vagrant.d/insecure_private_key -r ./pillar/ vagrant@localhost:pillar
@$(ssh-vagrant) 'sudo rm -rf /srv'
@$(ssh-vagrant) 'sudo mkdir /srv'
@$(ssh-vagrant) 'sudo mv ~/salt /srv/salt'
@$(ssh-vagrant) 'sudo mv ~/pillar /srv/pillar'
@$(ssh-vagrant) 'sudo salt-call --local state.highstate'
@vagrant ssh -c 'cd /var/www/snipt; make db;'
@vagrant ssh -c '$(pm) syncdb;'
@$(ssh-vagrant) '$(pm) migrate;'
@$(ssh-vagrant) '$(pm) backfill_api_keys;'
@$(ssh-vagrant) '$(pm) rebuild_index --noinput;'
pulldb:
@ssh nick@snipt.net -p 55555 'sudo su -c "pg_dump snipt|gzip > /tmp/snipt.dump" postgres'
@scp -q -P 55555 nick@snipt.net:/tmp/snipt.dump snipt.dump.gz
@dropdb snipt
@createdb snipt
@cat snipt.dump.gz | gunzip | psql snipt
@rm snipt.dump.gz
git push heroku heroku:master
sass:
sass --sourcemap=none --watch -t compressed --scss media/css/style.scss:media/css/style.css
.PHONY: assets, \
db, \
deploy, \
deploy-heroku, \
pulldb, \
provision-server, \
provision-vagrant, \
salt-server, \
salt-vagrant, \
sass, \
server, \
vagrant
.PHONY: deploy sass

View File

@ -1 +1 @@
web: gunicorn wsgi:application --log-file -
web: gunicorn wsgi --log-file -

View File

@ -1,41 +1,48 @@
# Snipt
This is the codebase for the website, [Snipt.net](https://snipt.net/).
## Automatic deploy to Heroku
# Running the Django app locally with Vagrant
You can click the button below to automatically deploy Snipt to Heroku.
Install [Vagrant](https://www.vagrantup.com/) and either [VirtualBox](https://www.virtualbox.org/) or
[VMWare Fusion](http://www.vmware.com/products/fusion).
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/nicksergeant/snipt/tree/heroku)
1. Clone the repo.
2. `cp settings_local.py-template settings_local.py`
3. Edit local settings (choose a database password - you'll be prompted for it).
4. `make vagrant`
5. Visit [http://local.snipt.net:8080/](http://local.snipt.net:8080/).
## Manual deploy to Heroku
# Deploying to a VM
- Clone the repo.
- `heroku create`
- `heroku addons:add heroku-postgresql:hobby-dev`
- `heroku addons:add searchbox`
- `heroku config:add SECRET_KEY=<some-secret-key>`
- `git push heroku`
- `heroku run python manage.py migrate`
- `heroku run python manage.py createsuperuser`
- Visit yourapp.herokuapp.com and login with the user you just created.
1. Clone the repo.
2. `cp settings_local.py-template settings_local_server.py`
3. Edit local server settings (choose a database password - you'll be prompted for it).
4. Manually change the VM IP address in the Makefile.
5. `make server`
## Updating your Heroku instance after an automatic deploy
# Deploying to Heroku
- `git clone https://github.com/nicksergeant/snipt`
- `cd snipt`
- `git checkout heroku`
- `heroku git:remote -a <your-instance-name>`
- `git push heroku heroku:master`
1. Clone the repo.
2. `heroku create`
3. `heroku addons:add heroku-postgresql:hobby-dev`
4. `heroku addons:add searchbox`
8. `heroku config:add DEBUG=False`
9. `heroku config:add INTERCOM_SECRET_KEY=`
9. `heroku config:add POSTMARK_API_KEY=`
11. `heroku config:add RAVEN_CONFIG_DSN=`
12. `heroku config:add SECRET_KEY=`
13. `heroku config:add STRIPE_SECRET_KEY=`
14. `heroku config:add USE_SSL=False`
15. `git push heroku`
16. `heroku run python manage.py syncdb`
17. `heroku run python manage.py migrate`
## Options
Any problems / questions / bugs, [create an issue](https://github.com/nicksergeant/snipt/issues). Thanks! :)
If you want email support (for password resets, server errors, etc):
- `heroku addons:create postmark:10k`
- `heroku run addons:open postmark` -> use an email you control and confirm it
- `heroku config:add POSTMARK_EMAIL=<email_from_above>`
If you want to disable user-facing signup:
- `heroku config:set DISABLE_SIGNUP=true`
If you want to enable Django's DEBUG mode:
- `heroku config:add DEBUG=False`
If you want to enable SSL on a custom domain after you've configured your
Heroku SSL cert:
- `heroku config:add USE_SSL=False`

6
Vagrantfile vendored
View File

@ -1,6 +0,0 @@
Vagrant.configure("2") do |config|
config.vm.box = "phusion/ubuntu-14.04-amd64"
config.vm.hostname = "local.snipt.net"
config.vm.synced_folder ".", "/var/www/snipt/"
config.vm.network "forwarded_port", guest: 80, host: 80
end

View File

@ -1,44 +0,0 @@
{% load static %}
{% extends "base.html" %}
{% block page-title %}Activate account{% endblock %}
{% block body-class %}{{ block.super }} static signup pro pro-signup{% endblock %}
{% block breadcrumb %}
<li><a href="/account/activate/">Activate</a></li>
{% endblock %}
{% block content %}
{% if request.GET.declined %}
<div class="alert alert-error" style="margin: 30px;">
<strong>{{ request.GET.declined }}</strong> You have not been charged. Please try again.
</div>
{% endif %}
<form class="form-horizontal static-box" id="pro-signup" method="post" action="/account/activate/">
<fieldset>
<div class="info">
Activate 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 class="payment-form">
<div class="payment-errors alert alert-error"></div>
<script
src="https://checkout.stripe.com/checkout.js"
class="stripe-button"
data-email="{{ request.user.email }}"
data-key="{% if debug %}pk_test_cgknmaWRMQeJt2adEdvH3T9l{% else %}pk_live_gUO2nCl7dhx6j0posz6gnbhA{% endif %}"
data-image="{{ STATIC_URL }}img/avatar.png"
data-name="Snipt"
data-description="Full Snipt.net Account ($5.00)"
data-amount="500">
</script>
{% csrf_token %}
</div>
<div class="form-actions" style="color: #A2A2A2;">
Prefer to pay with PayPal? Email <a href="mailto:support@snipt.net">support@snipt.net</a>.
</div>
</fieldset>
</form>
{% endblock %}

View File

@ -3,8 +3,6 @@ from django.conf.urls import url
urlpatterns = [
url(r'^activate/$', views.activate,
name='account-activate'),
url(r'^stats/$', views.stats, name='account-stats'),
url(r'^', views.account, name='account-detail')
]

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
@ -16,54 +10,6 @@ def account(request):
return {}
@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')
def stats(request):

25
app.json Normal file
View File

@ -0,0 +1,25 @@
{
"name": "Snipt",
"description": "Code snippets for teams and individuals.",
"keywords": [
"snipt",
"code snippets"
],
"website": "https://snipt.net",
"repository": "https://github.com/nicksergeant/snipt",
"logo": "https://snipt.s3.amazonaws.com/logo.png",
"success_url": "/",
"scripts": {
"postdeploy": "python manage.py migrate"
},
"env": {
"SECRET_KEY": {
"description": "Secret key for Django to use.",
"generator": "secret"
}
},
"addons": [
"heroku-postgresql:hobby-dev",
"searchbox"
]
}

View File

@ -21,29 +21,4 @@
{% endfor %}
{% paginate %}
</section>
<script type="text/javascript" id="disqus">
var disqus_shortname = '{% firstof blog_user.profile.disqus_shortname "snipt-net" %}';
{% if debug %}
var disqus_developer = 1;
{% endif %}
(function () {
var s = document.createElement('script'); s.async = true;
s.type = 'text/javascript';
s.src = 'https://' + disqus_shortname + '.disqus.com/count.js';
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
}());
</script>
<script type="text/html" id="disqus-template">
var disqus_shortname = 'snipt-net';
{% if debug %}
var disqus_developer = 1;
{% endif %}
(function () {
var s = document.createElement('script'); s.async = true;
s.type = 'text/javascript';
s.src = 'https://' + disqus_shortname + '.disqus.com/count.js';
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
}());
</script>
{% endblock %}

View File

@ -20,7 +20,7 @@
{% endwith %}
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_shortname = '{% firstof blog_user.profile.disqus_shortname "snipt-net" %}';
var disqus_shortname = '{{ blog_user.profile.disqus_shortname }}';
{% if debug %}
var disqus_developer = 1;
{% endif %}

View File

@ -11,7 +11,7 @@
{% endfor %}
{% paginate %}
<script type="text/javascript">
var disqus_shortname = '{% firstof blog_user.profile.disqus_shortname "snipt-net" %}';
var disqus_shortname = '{{ blog_user.profile.disqus_shortname }}';
{% if debug %}
var disqus_developer = 1;
{% endif %}

View File

@ -37,7 +37,7 @@
{% if detail %}
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_shortname = '{% firstof blog_user.profile.disqus_shortname "snipt-net" %}';
var disqus_shortname = '{{ firstof blog_user.profile.disqus_shortname }}';
{% if debug %}
var disqus_developer = 1;
{% endif %}

View File

@ -2,7 +2,6 @@ import datetime
from annoying.functions import get_object_or_None
from django.shortcuts import get_object_or_404, render
from django.template import RequestContext
from snipts.models import Snipt
THEME_CHOICES = {

View File

@ -1,6 +0,0 @@
from django.contrib.auth.forms import AuthenticationForm
class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm):
def confirm_login_allowed(self, user):
pass

View File

@ -1,72 +0,0 @@
#!/bin/bash
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|jsmin > media/js/src/account.min.js
cat media/js/src/snipts.js|jsmin > media/js/src/snipts.min.js
cat media/js/src/jobs.js|jsmin > media/js/src/jobs.min.js
cat media/js/src/application.js|jsmin > media/js/src/application.min.js
cat media/js/src/team.js|jsmin > media/js/src/team.min.js
cat media/js/src/modules/site.js|jsmin > media/js/src/modules/site.min.js
cat media/js/src/modules/snipt.js|jsmin > media/js/src/modules/snipt.min.js
cat media/js/src/pro.js|jsmin > 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/search.min.js \
media/js/src/jobs.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
git add /Users/Nick/Code/snipt/media/css/pro.css
git add /Users/Nick/Code/snipt/media/css/snipt.css
git add /Users/Nick/Code/snipt/media/js/snipt-all.min.js
git add /Users/Nick/Code/snipt/media/js/pro-all.min.js
git add /Users/Nick/Code/snipt/media/js/src/modules/site.min.js

View File

@ -1,12 +0,0 @@
bind = "127.0.0.1:8000"
daemon = False # Whether work in the background
debug = False # Some extra logging
logfile = ".gunicorn.log" # Name of the log file
loglevel = "info" # The level at which to log
pidfile = ".gunicorn.pid" # Path to a PID file
workers = 9 # Number of workers to initialize
umask = 0 # Umask to set when daemonizing
user = None # Change process owner to user
group = None # Change process group to group
proc_name = "gunicorn-snipt" # Change the process name
tmp_upload_dir = None # Set path used to store temporary uploads

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2667,6 +2667,7 @@ body.homepage {
color: white;
font: bold 16px $Helvetica;
display: inline-block;
margin-top: 30px;
margin-left: 20px;
padding: 5px 20px 7px 20px;
text-decoration: none;
@ -2747,7 +2748,7 @@ body.homepage {
color: #344547;
font: normal 20px $Rockwell;
margin: 0;
margin-bottom: 15px;
margin: 50px 0;
}
a.button {
background: #D4F5F9;
@ -3306,28 +3307,3 @@ div.inline-ad {
text-transform: uppercase;
}
}
div.closing {
background: #D9534F;
color: white;
font-size: 18px;
padding: 50px;
text-align: center;
a {
color: white;
text-decoration: underline;
}
strong {
display: block;
font-size: 24px;
line-height: 30px;
margin-bottom: 20px;
}
p {
line-height: 22px;
font-size: 18px;
}
}

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'));

View File

@ -478,9 +478,6 @@
this.$el.removeClass('expandable');
}
$('script#disqus').remove();
window.site.$body.append('<script id="disqus" type="text/javascript">' + $('script#disqus-template').text() + '</script>');
// For new snipts.
if (this.$el.attr('id') === 'new-snipt') {
this.$el.fadeIn('fast');

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,113 +0,0 @@
import os
import sys
import time
import signal
import threading
import atexit
import Queue
_interval = 1.0
_times = {}
_files = []
_running = False
_queue = Queue.Queue()
_lock = threading.Lock()
def _restart(path):
_queue.put(True)
prefix = 'monitor (pid=%d):' % os.getpid()
print >> sys.stderr, '%s Change detected to \'%s\'.' % (prefix, path)
print >> sys.stderr, '%s Triggering process restart.' % prefix
os.kill(os.getpid(), signal.SIGINT)
def _modified(path):
try:
# If path doesn't denote a file and were previously
# tracking it, then it has been removed or the file type
# has changed so force a restart. If not previously
# tracking the file then we can ignore it as probably
# pseudo reference such as when file extracted from a
# collection of modules contained in a zip file.
if not os.path.isfile(path):
return path in _times
# Check for when file last modified.
mtime = os.stat(path).st_mtime
if path not in _times:
_times[path] = mtime
# Force restart when modification time has changed, even
# if time now older, as that could indicate older file
# has been restored.
if mtime != _times[path]:
return True
except:
# If any exception occured, likely that file has been
# been removed just before stat(), so force a restart.
return True
return False
def _monitor():
while 1:
# Check modification times on all files in sys.modules.
for module in sys.modules.values():
if not hasattr(module, '__file__'):
continue
path = getattr(module, '__file__')
if not path:
continue
if os.path.splitext(path)[1] in ['.pyc', '.pyo', '.pyd']:
path = path[:-1]
if _modified(path):
return _restart(path)
# Check modification times on files which have
# specifically been registered for monitoring.
for path in _files:
if _modified(path):
return _restart(path)
# Go to sleep for specified interval.
try:
return _queue.get(timeout=_interval)
except:
pass
_thread = threading.Thread(target=_monitor)
_thread.setDaemon(True)
def _exiting():
try:
_queue.put(True)
except:
pass
_thread.join()
atexit.register(_exiting)
def track(path):
if not path in _files:
_files.append(path)
def start(interval=1.0):
global _interval
if interval < _interval:
_interval = interval
global _running
_lock.acquire()
if not _running:
prefix = 'monitor (pid=%d):' % os.getpid()
print >> sys.stderr, '%s Starting change monitor.' % prefix
_running = True
_thread.start()
_lock.release()

View File

@ -1,18 +0,0 @@
env_name: production
hostname: snipt.net
deploy_user: deploy
users:
-
name: deploy
groups:
- deploy
- wheel
-
name: nick
groups:
- deploy
- wheel
ssh:
port: 55555

View File

@ -1,5 +0,0 @@
base:
'*':
- production
'local.snipt.net':
- vagrant

View File

@ -1,13 +0,0 @@
env_name: vagrant
hostname: local.snipt.net
deploy_user: vagrant
users:
-
name: vagrant
groups:
- deploy
- wheel
ssh:
port: 22

View File

@ -2,6 +2,7 @@ Django==1.10.3
Fabric==1.12.0
PyYAML==3.12
Pygments==2.1.3
certifi==2016.9.26
dj-database-url==0.4.1
dj-static==0.0.6
django-annoying==0.10.3
@ -23,9 +24,9 @@ py-bcrypt==0.4
pycrypto==2.6.1
python-dateutil==2.5.3
python-postmark==0.4.10
raven==5.31.0
requests==2.11.1
six==1.9.0
smartypants==1.8.6
stripe==1.41.1
urllib3==1.11
whitenoise==3.2.2

View File

@ -1,85 +0,0 @@
python-virtualenv:
pkg.installed
virtualenvwrapper:
pip.installed
/var/www:
file.directory:
- user: {{ pillar.deploy_user }}
- group: deploy
- mode: 775
- require:
- user: {{ pillar.deploy_user }}
- group: deploy
/var/www/.virtualenvs:
file.directory:
- user: {{ pillar.deploy_user }}
- group: deploy
- mode: 775
- require:
- group: deploy
{% if pillar.env_name != 'vagrant' %}
/var/www/snipt:
file.directory:
- user: {{ pillar.deploy_user }}
- group: deploy
- mode: 775
- require:
- group: deploy
git.latest:
- name: https://github.com/nicksergeant/snipt.git
- rev: master
- target: /var/www/snipt
- user: deploy
{% endif %}
/var/www/.virtualenvs/snipt:
file.directory:
- user: {{ pillar.deploy_user }}
- group: deploy
- mode: 775
- require:
- group: deploy
virtualenv.managed:
- system_site_packages: False
- requirements: /var/www/snipt/requirements.txt
/home/{{ pillar.deploy_user }}/tmp:
file.absent
/etc/supervisor/conf.d/snipt.conf:
file.managed:
- source: salt://application/snipt.supervisor.conf
- template: jinja
- makedirs: True
cmd.run:
- name: supervisorctl restart snipt
snipt-site:
file.managed:
- name: /etc/nginx/sites-available/snipt
- source: salt://application/snipt.nginx.conf
- template: jinja
- group: deploy
- mode: 755
- require:
- pkg: nginx-extras
- group: deploy
enable-snipt-site:
file.symlink:
- name: /etc/nginx/sites-enabled/snipt
- target: /etc/nginx/sites-available/snipt
- force: false
- require:
- pkg: nginx-extras
cmd.run:
- name: service nginx restart
- require:
- pkg: nginx-extras

View File

@ -1,131 +0,0 @@
upstream backend_snipt {
server 127.0.0.1:8000;
}
{% if pillar.env_name != 'vagrant' %}
server {
listen 80;
server_name *.{{ pillar.hostname }};
if ($host ~* "^([^.]+(\.[^.]+)*)\.{{ pillar.hostname }}$"){
set $subd $1;
rewrite ^(.*)$ https://$subd.{{ pillar.hostname }}$1 permanent;
break;
}
}
server {
listen 80;
server_name {{ pillar.hostname }} www.{{ pillar.hostname }} beta.{{ pillar.hostname }};
rewrite ^(.*) https://{{ pillar.hostname }}$1 permanent;
}
server {
listen 443;
server_name www.{{ pillar.hostname }};
ssl on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";
ssl_certificate /etc/certs/{{ pillar.hostname }}.crt;
ssl_certificate_key /etc/certs/{{ pillar.hostname }}.key;
rewrite ^(.*) https://{{ pillar.hostname }}$1 permanent;
}
server {
listen 443;
server_name {{ pillar.hostname }} *.{{ pillar.hostname }};
ssl on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";
ssl_certificate /etc/certs/{{ pillar.hostname }}.crt;
ssl_certificate_key /etc/certs/{{ pillar.hostname }}.key;
location ~* /favicon.ico {
root /var/www/snipt/static/img/;
expires max;
}
location / {
# Open CORS config from https://gist.github.com/michiel/1064640.
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
rewrite_by_lua '
if string.find(ngx.var.host, "_") then
local newHost, n = ngx.re.gsub(ngx.var.host, "_", "-")
ngx.redirect(ngx.var.scheme .. "://" .. newHost .. ngx.var.uri)
end
';
proxy_pass http://backend_snipt;
proxy_set_header Host $host;
}
location /static/ {
alias /var/www/snipt/static/;
expires max;
}
location /public/feed/ {
rewrite ^/public/feed/$ https://{{ pillar.hostname }}/public/?rss permanent;
}
}
server {
listen 80 default_server;
location / {
proxy_pass http://backend_snipt;
proxy_set_header Host $host;
}
location /static/ {
alias /var/www/snipt/static/;
expires max;
}
location ~* /favicon.ico {
root /var/www/snipt/static/img/;
expires max;
}
}
{% else %}
server {
listen 80 default_server;
location / {
proxy_pass http://backend_snipt;
proxy_set_header Host $host;
}
location /static/ {
alias /var/www/snipt/media/;
expires max;
}
location ~* /favicon.ico {
root /var/www/snipt/media/img/;
expires max;
}
}
{% endif %}

View File

@ -1,7 +0,0 @@
[program:snipt]
directory=/var/www/snipt
user={{ pillar.deploy_user }}
command={% if pillar.env_name != 'vagrant' %}/var/www/.virtualenvs/snipt/bin/gunicorn wsgi:application{% else %}/var/www/.virtualenvs/snipt/bin/python /var/www/snipt/manage.py runserver{% endif %}
autostart=true
autorestart=true
stopasgroup=true

View File

@ -1,24 +0,0 @@
elasticsearch-file:
file.managed:
- name: /tmp/elasticsearch-1.3.4.deb
- source: https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.3.4.deb
- unless: test -d /usr/local/elasticsearch/bin
- source_hash: sha1=6a4b6a12825f141245bb581c76052464d17de874
elasticsearch-install:
cmd:
- cwd: /tmp
- names:
- dpkg -i elasticsearch-1.3.4.deb
- unless: test -d /usr/local/elasticsearch/bin
- run
- require:
- file: elasticsearch-file
elasticsearch:
service:
- running
- enable: True
- reload: True
- require:
- file: elasticsearch-file

View File

@ -1,103 +0,0 @@
# Directories {{{
function l
tree --dirsfirst -ChFL 1 $args
end
function ll
tree --dirsfirst -ChFupDaL 1 $args
end
# }}}
# Directories {{{
set -g -x fish_greeting ''
set -g -x EDITOR vim
# }}}
# Git and Mercurial functions {{{
function gca
git commit -a $argv
end
function gco
git checkout $argv
end
function gd
git diff HEAD
end
function gl
git pull $argv
end
function gp
git push $argv
end
function gst
git status $argv
end
# }}}
# Programs {{{
function logs
sudo supervisorctl tail -f snipt stdout
end
function pm
python manage.py $argv
end
function run
sudo supervisorctl restart snipt
sudo supervisorctl tail -f snipt stdout
end
function rs
sudo supervisorctl restart snipt
end
function ssc
sudo supervisorctl $argv
end
function wo
workon (cat .venv) $argv
end
# }}}
# Prompt {{{
set -x fish_color_command 005fd7\x1epurple
set -x fish_color_search_match --background=purple
function prompt_pwd --description 'Print the current working directory, shortend to fit the prompt'
echo $PWD | sed -e "s|^$HOME|~|"
end
function virtualenv_prompt
if [ -n "$VIRTUAL_ENV" ]
printf '\033[0;37m(%s) ' (basename "$VIRTUAL_ENV") $argv
end
end
function fish_prompt
z --add "$PWD"
echo ' '
printf '\033[0;31m%s\033[0;37m on ' (whoami)
printf '\033[0;31m%s ' (hostname -f)
printf '\033[0;32m%s' (prompt_pwd)
echo
virtualenv_prompt
printf '\033[0;37m> '
end
# }}}
# Virtualenv {{{
set -x WORKON_HOME '/var/www/.virtualenvs'
. ~/.config/fish/virtualenv.fish
# }}}
# Z {{{
. /etc/z.fish
function j
z $argv
end
# }}}

View File

@ -1,35 +0,0 @@
fish:
pkgrepo.managed:
- ppa: fish-shell/release-2
- require_in:
- pkg: fish
pkg.latest:
- name: fish
- refresh: True
/etc/z.fish:
file.managed:
- source: salt://fish/z.fish
- mode: 755
{% for user in pillar.users %}
fish-{{ user.name }}:
file.managed:
- name: /home/{{ user.name }}/.config/fish/config.fish
- user: {{ user.name }}
- source: salt://fish/config.fish
- makedirs: True
- require:
- user: {{ user.name }}
fish-{{ user.name }}-virtualenv:
file.managed:
- name: /home/{{ user.name }}/.config/fish/virtualenv.fish
- user: {{ user.name }}
- source: salt://fish/virtualenv.fish
- makedirs: True
- require:
- user: {{ user.name }}
{% endfor %}

View File

@ -1,46 +0,0 @@
# mostly from http://coderseye.com/2010/using-virtualenv-with-fish-shell.html
function workon -d "Activate virtual environment in $WORKON_HOME"
set tgt {$WORKON_HOME}/$argv[1]
if [ ! -d $tgt ]
mkdir -p "$WORKON_HOME"
virtualenv $tgt
end
if [ -d $tgt ]
cd $tgt
deactivate
set -gx VIRTUAL_ENV "$tgt"
set -gx _OLD_VIRTUAL_PATH $PATH
set -gx PATH "$VIRTUAL_ENV/bin" $PATH
# unset PYTHONHOME if set
if set -q PYTHONHOME
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
set -e PYTHONHOME
end
cd -
echo "activated $tgt"
else
echo "$tgt not found"
end
end
complete -c workon -a "(cd $WORKON_HOME; ls -d *)"
function deactivate -d "Exit virtualenv and return to normal shell environment"
# reset old environment variables
if test -n "$_OLD_VIRTUAL_PATH"
set -gx PATH $_OLD_VIRTUAL_PATH
set -e _OLD_VIRTUAL_PATH
end
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
set -e _OLD_VIRTUAL_PYTHONHOME
end
set -e VIRTUAL_ENV
end

View File

@ -1,195 +0,0 @@
# maintains a jump-list of the directories you actually use
#
# INSTALL:
# * put something like this in your config.fish:
# . /path/to/z.fish
# * put something like this in your fish_prompt function:
# z --add "$PWD"
# * cd around for a while to build up the db
# * PROFIT!!
#
# USE:
# * z foo # goes to most frecent dir matching foo
# * z foo bar # goes to most frecent dir matching foo and bar
# * z -r foo # goes to highest ranked dir matching foo
# * z -t foo # goes to most recently accessed dir matching foo
# * z -l foo # list all dirs matching foo (by frecency)
function z -d "Jump to a recent directory."
set -l datafile "$HOME/.z"
# add entries
if [ "$argv[1]" = "--add" ]
set -e argv[1]
# $HOME isn't worth matching
[ "$argv" = "$HOME" ]; and return
set -l tempfile (mktemp $datafile.XXXXXX)
test -f $tempfile; or return
# maintain the file
awk -v path="$argv" -v now=(date +%s) -F"|" '
BEGIN {
rank[path] = 1
time[path] = now
}
$2 >= 1 {
if( $1 == path ) {
rank[$1] = $2 + 1
time[$1] = now
} else {
rank[$1] = $2
time[$1] = $3
}
count += $2
}
END {
if( count > 1000 ) {
for( i in rank ) print i "|" 0.9*rank[i] "|" time[i] # aging
} else for( i in rank ) print i "|" rank[i] "|" time[i]
}
' $datafile ^/dev/null > $tempfile
mv -f $tempfile $datafile
# tab completion
else
if [ "$argv[1]" = "--complete" ]
awk -v q="$argv[2]" -F"|" '
BEGIN {
if( q == tolower(q) ) nocase = 1
split(q,fnd," ")
}
{
if( system("test -d \"" $1 "\"") ) next
if( nocase ) {
for( i in fnd ) tolower($1) !~ tolower(fnd[i]) && $1 = ""
if( $1 ) print $1
} else {
for( i in fnd ) $1 !~ fnd[i] && $1 = ""
if( $1 ) print $1
}
}
' "$datafile" 2>/dev/null
else
# list/go
set -l last ''
set -l list 0
set -l typ ''
set -l fnd ''
while [ (count $argv) -gt 0 ]
switch "$argv[1]"
case -- '-h'
echo "z [-h][-l][-r][-t] args" >&2
return
case -- '-l'
set list 1
case -- '-r'
set typ "rank"
case -- '-t'
set typ "recent"
case -- '--'
while [ "$argv[1]" ]
set -e argv[1]
set fnd "$fnd $argv[1]"
end
case '*'
set fnd "$fnd $argv[1]"
end
set last $1
set -e argv[1]
end
[ "$fnd" ]; or set list 1
# if we hit enter on a completion just go there
[ -d "$last" ]; and cd "$last"; and return
# no file yet
[ -f "$datafile" ]; or return
set -l tempfile (mktemp $datafile.XXXXXX)
test -f $tempfile; or return
set -l target (awk -v t=(date +%s) -v list="$list" -v typ="$typ" -v q="$fnd" -v tmpfl="$tempfile" -F"|" '
function frecent(rank, time) {
dx = t-time
if( dx < 3600 ) return rank*4
if( dx < 86400 ) return rank*2
if( dx < 604800 ) return rank/2
return rank/4
}
function output(files, toopen, override) {
if( list ) {
if( typ == "recent" ) {
cmd = "sort -nr >&2"
} else cmd = "sort -n >&2"
for( i in files ) if( files[i] ) printf "%-10s %s\n", files[i], i | cmd
if( override ) printf "%-10s %s\n", "common:", override > "/dev/stderr"
} else {
if( override ) toopen = override
print toopen
}
}
function common(matches, fnd, nc) {
for( i in matches ) {
if( matches[i] && (!short || length(i) < length(short)) ) short = i
}
if( short == "/" ) return
for( i in matches ) if( matches[i] && i !~ short ) x = 1
if( x ) return
if( nc ) {
for( i in fnd ) if( tolower(short) !~ tolower(fnd[i]) ) x = 1
} else for( i in fnd ) if( short !~ fnd[i] ) x = 1
if( !x ) return short
}
BEGIN { split(q, a, " ") }
{
if( system("test -d \"" $1 "\"") ) next
print $0 >> tmpfl
if( typ == "rank" ) {
f = $2
} else if( typ == "recent" ) {
f = t-$3
} else f = frecent($2, $3)
wcase[$1] = nocase[$1] = f
for( i in a ) {
if( $1 !~ a[i] ) delete wcase[$1]
if( tolower($1) !~ tolower(a[i]) ) delete nocase[$1]
}
if( wcase[$1] > oldf ) {
cx = $1
oldf = wcase[$1]
} else if( nocase[$1] > noldf ) {
ncx = $1
noldf = nocase[$1]
}
}
END {
if( cx ) {
output(wcase, cx, common(wcase, a, 0))
} else if( ncx ) output(nocase, ncx, common(nocase, a, 1))
}
' "$datafile")
if [ $status -gt 0 ]
rm -f "$tempfile"
else
mv -f "$tempfile" "$datafile"
[ "$target" ]; and cd "$target"
end
end
end
end
function __z_init -d 'Set up automatic population of the directory list for z'
functions fish_prompt | grep -q 'z --add'
if [ $status -gt 0 ]
functions fish_prompt | sed -e '$ i\\
z --add "$PWD"' | .
end
end
__z_init

View File

@ -1,27 +0,0 @@
/etc/iptables.up.rules:
file.managed:
- source: salt://iptables/iptables.up.rules
- template: jinja
- require:
- pkg: iptables
flush-iptables:
cmd.run:
- names:
- /sbin/iptables -F
- /sbin/iptables-restore < /etc/iptables.up.rules
- watch:
- file: /etc/iptables.up.rules
- require:
- pkg: iptables
/etc/network/if-pre-up.d/iptables:
file.managed:
- mode: 644
- source: salt://iptables/iptables-restore.sh
- require:
- pkg: iptables
cmd.run:
- name: chmod +x /etc/network/if-pre-up.d/iptables
- require:
- pkg: iptables

View File

@ -1,2 +0,0 @@
#!/bin/sh
sudo sh -c '/sbin/iptables-restore < /etc/iptables.up.rules'

View File

@ -1,43 +0,0 @@
*filter
# Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
# Accepts all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allows all outbound traffic
# You can modify this to only allow certain traffic
-A OUTPUT -j ACCEPT
# Allows HTTP and HTTPS connections from anywhere (the normal ports for websites)
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
# Allows SSH connections
#
# THE -dport NUMBER IS THE SAME ONE YOU SET UP IN THE SSHD_CONFIG FILE
#
-A INPUT -p tcp -m state --state NEW --dport {{ pillar.ssh.port }} -j ACCEPT
# Allow ping
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
# log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
# Reject all other inbound - default deny unless explicitly allowed policy
-A INPUT -j REJECT
-A FORWARD -j REJECT
COMMIT

View File

@ -1,46 +0,0 @@
nginx-extras:
pkg:
- installed
nginx:
service:
- running
- enable: True
- require:
- pkg: nginx-extras
- watch:
- file: /etc/nginx/nginx.conf
- file: /etc/nginx/sites-enabled/*
/etc/nginx/sites-available:
file.directory:
- mode: 755
- require:
- pkg: nginx-extras
/etc/nginx/sites-enabled:
file.directory:
- mode: 755
- require:
- pkg: nginx-extras
{% if pillar.env_name != 'vagrant' %}
/etc/certs:
file.directory:
- mode: 644
- require:
- pkg: nginx-extras
{% endif %}
/etc/nginx/nginx.conf:
file.managed:
- source: salt://nginx/nginx.conf
- mode: 400
- template: jinja
- require:
- pkg: nginx-extras
/etc/nginx/sites-enabled/default:
file.absent

View File

@ -1,26 +0,0 @@
user {% if pillar.env_name == 'vagrant' %}vagrant{% else %}www-data{% endif %};
worker_processes 4;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
gzip on;
gzip_disable "msie6";
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
include /etc/nginx/sites-enabled/*;
types_hash_max_size 4096;
server_names_hash_bucket_size 64;
}

View File

@ -1,29 +0,0 @@
postgresql:
pkg:
- installed
service.running:
- watch:
- file: /etc/postgresql/9.3/main/pg_hba.conf
- require:
- pkg: postgresql
pg_hba.conf:
file.managed:
- name: /etc/postgresql/9.3/main/pg_hba.conf
- source: salt://postgresql/pg_hba.conf
- user: postgres
- group: postgres
- mode: 644
- require:
- pkg: postgresql
postgresql.conf:
file.managed:
- name: /etc/postgresql/9.3/main/postgresql.conf
- source: salt://postgresql/postgresql.conf
- template: jinja
- user: postgres
- group: postgres
- mode: 644
- require:
- pkg: postgresql

View File

@ -1,99 +0,0 @@
# PostgreSQL Client Authentication Configuration File
# ===================================================
#
# Refer to the "Client Authentication" section in the PostgreSQL
# documentation for a complete description of this file. A short
# synopsis follows.
#
# This file controls: which hosts are allowed to connect, how clients
# are authenticated, which PostgreSQL user names they can use, which
# databases they can access. Records take one of these forms:
#
# local DATABASE USER METHOD [OPTIONS]
# host DATABASE USER ADDRESS METHOD [OPTIONS]
# hostssl DATABASE USER ADDRESS METHOD [OPTIONS]
# hostnossl DATABASE USER ADDRESS METHOD [OPTIONS]
#
# (The uppercase items must be replaced by actual values.)
#
# The first field is the connection type: "local" is a Unix-domain
# socket, "host" is either a plain or SSL-encrypted TCP/IP socket,
# "hostssl" is an SSL-encrypted TCP/IP socket, and "hostnossl" is a
# plain TCP/IP socket.
#
# DATABASE can be "all", "sameuser", "samerole", "replication", a
# database name, or a comma-separated list thereof. The "all"
# keyword does not match "replication". Access to replication
# must be enabled in a separate record (see example below).
#
# USER can be "all", a user name, a group name prefixed with "+", or a
# comma-separated list thereof. In both the DATABASE and USER fields
# you can also write a file name prefixed with "@" to include names
# from a separate file.
#
# ADDRESS specifies the set of hosts the record matches. It can be a
# host name, or it is made up of an IP address and a CIDR mask that is
# an integer (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that
# specifies the number of significant bits in the mask. A host name
# that starts with a dot (.) matches a suffix of the actual host name.
# Alternatively, you can write an IP address and netmask in separate
# columns to specify the set of hosts. Instead of a CIDR-address, you
# can write "samehost" to match any of the server's own IP addresses,
# or "samenet" to match any address in any subnet that the server is
# directly connected to.
#
# METHOD can be "trust", "reject", "md5", "password", "gss", "sspi",
# "krb5", "ident", "peer", "pam", "ldap", "radius" or "cert". Note that
# "password" sends passwords in clear text; "md5" is preferred since
# it sends encrypted passwords.
#
# OPTIONS are a set of options for the authentication in the format
# NAME=VALUE. The available options depend on the different
# authentication methods -- refer to the "Client Authentication"
# section in the documentation for a list of which options are
# available for which authentication methods.
#
# Database and user names containing spaces, commas, quotes and other
# special characters must be quoted. Quoting one of the keywords
# "all", "sameuser", "samerole" or "replication" makes the name lose
# its special character, and just match a database or username with
# that name.
#
# This file is read on server startup and when the postmaster receives
# a SIGHUP signal. If you edit the file on a running system, you have
# to SIGHUP the postmaster for the changes to take effect. You can
# use "pg_ctl reload" to do that.
# Put your actual configuration here
# ----------------------------------
#
# If you want to allow non-local connections, you need to add more
# "host" records. In that case you will also need to make PostgreSQL
# listen on a non-local interface via the listen_addresses
# configuration parameter, or via the -i or -h command line switches.
# DO NOT DISABLE!
# If you change this first entry you will need to make sure that the
# database superuser can access the database using some other method.
# Noninteractive access to all databases is required during automatic
# maintenance (custom daily cronjobs, replication, and similar tasks).
#
# Database administrative login by Unix domain socket
local all postgres peer
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all peer
# IPv4 local connections:
host all all 127.0.0.1/32 md5
# IPv6 local connections:
host all all ::1/128 md5
# Allow replication connections from localhost, by a user with the
# replication privilege.
#local replication postgres peer
#host replication postgres 127.0.0.1/32 md5
#host replication postgres ::1/128 md5

View File

@ -1,596 +0,0 @@
# -----------------------------
# PostgreSQL configuration file
# -----------------------------
#
# This file consists of lines of the form:
#
# name = value
#
# (The "=" is optional.) Whitespace may be used. Comments are introduced with
# "#" anywhere on a line. The complete list of parameter names and allowed
# values can be found in the PostgreSQL documentation.
#
# The commented-out settings shown in this file represent the default values.
# Re-commenting a setting is NOT sufficient to revert it to the default value;
# you need to reload the server.
#
# This file is read on server startup and when the server receives a SIGHUP
# signal. If you edit the file on a running system, you have to SIGHUP the
# server for the changes to take effect, or use "pg_ctl reload". Some
# parameters, which are marked below, require a server shutdown and restart to
# take effect.
#
# Any parameter can also be given as a command-line option to the server, e.g.,
# "postgres -c log_connections=on". Some parameters can be changed at run time
# with the "SET" SQL command.
#
# Memory units: kB = kilobytes Time units: ms = milliseconds
# MB = megabytes s = seconds
# GB = gigabytes min = minutes
# h = hours
# d = days
#------------------------------------------------------------------------------
# FILE LOCATIONS
#------------------------------------------------------------------------------
# The default values of these variables are driven from the -D command-line
# option or PGDATA environment variable, represented here as ConfigDir.
data_directory = '/var/lib/postgresql/9.3/main' # use data in another directory
# (change requires restart)
hba_file = '/etc/postgresql/9.3/main/pg_hba.conf' # host-based authentication file
# (change requires restart)
ident_file = '/etc/postgresql/9.3/main/pg_ident.conf' # ident configuration file
# (change requires restart)
# If external_pid_file is not explicitly set, no extra PID file is written.
external_pid_file = '/var/run/postgresql/9.3-main.pid' # write an extra PID file
# (change requires restart)
#------------------------------------------------------------------------------
# CONNECTIONS AND AUTHENTICATION
#------------------------------------------------------------------------------
# - Connection Settings -
#listen_addresses = 'localhost' # what IP address(es) to listen on;
# comma-separated list of addresses;
# defaults to 'localhost'; use '*' for all
# (change requires restart)
port = 5432 # (change requires restart)
max_connections = 100 # (change requires restart)
# Note: Increasing max_connections costs ~400 bytes of shared memory per
# connection slot, plus lock space (see max_locks_per_transaction).
#superuser_reserved_connections = 3 # (change requires restart)
unix_socket_directories = '/var/run/postgresql' # comma-separated list of directories
# (change requires restart)
#unix_socket_group = '' # (change requires restart)
#unix_socket_permissions = 0777 # begin with 0 to use octal notation
# (change requires restart)
#bonjour = off # advertise server via Bonjour
# (change requires restart)
#bonjour_name = '' # defaults to the computer name
# (change requires restart)
# - Security and Authentication -
#authentication_timeout = 1min # 1s-600s
ssl = true # (change requires restart)
#ssl_ciphers = 'DEFAULT:!LOW:!EXP:!MD5:@STRENGTH' # allowed SSL ciphers
# (change requires restart)
#ssl_renegotiation_limit = 512MB # amount of data between renegotiations
ssl_cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem' # (change requires restart)
ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key' # (change requires restart)
#ssl_ca_file = '' # (change requires restart)
#ssl_crl_file = '' # (change requires restart)
#password_encryption = on
#db_user_namespace = off
# Kerberos and GSSAPI
#krb_server_keyfile = ''
#krb_srvname = 'postgres' # (Kerberos only)
#krb_caseins_users = off
# - TCP Keepalives -
# see "man 7 tcp" for details
#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds;
# 0 selects the system default
#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds;
# 0 selects the system default
#tcp_keepalives_count = 0 # TCP_KEEPCNT;
# 0 selects the system default
#------------------------------------------------------------------------------
# RESOURCE USAGE (except WAL)
#------------------------------------------------------------------------------
# - Memory -
shared_buffers = 128MB # min 128kB
# (change requires restart)
#temp_buffers = 8MB # min 800kB
#max_prepared_transactions = 0 # zero disables the feature
# (change requires restart)
# Note: Increasing max_prepared_transactions costs ~600 bytes of shared memory
# per transaction slot, plus lock space (see max_locks_per_transaction).
# It is not advisable to set max_prepared_transactions nonzero unless you
# actively intend to use prepared transactions.
#work_mem = 1MB # min 64kB
#maintenance_work_mem = 16MB # min 1MB
#max_stack_depth = 2MB # min 100kB
# - Disk -
#temp_file_limit = -1 # limits per-session temp file space
# in kB, or -1 for no limit
# - Kernel Resource Usage -
#max_files_per_process = 1000 # min 25
# (change requires restart)
#shared_preload_libraries = '' # (change requires restart)
# - Cost-Based Vacuum Delay -
#vacuum_cost_delay = 0 # 0-100 milliseconds
#vacuum_cost_page_hit = 1 # 0-10000 credits
#vacuum_cost_page_miss = 10 # 0-10000 credits
#vacuum_cost_page_dirty = 20 # 0-10000 credits
#vacuum_cost_limit = 200 # 1-10000 credits
# - Background Writer -
#bgwriter_delay = 200ms # 10-10000ms between rounds
#bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round
#bgwriter_lru_multiplier = 2.0 # 0-10.0 multipler on buffers scanned/round
# - Asynchronous Behavior -
#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching
#------------------------------------------------------------------------------
# WRITE AHEAD LOG
#------------------------------------------------------------------------------
# - Settings -
#wal_level = minimal # minimal, archive, or hot_standby
# (change requires restart)
#fsync = on # turns forced synchronization on or off
#synchronous_commit = on # synchronization level;
# off, local, remote_write, or on
#wal_sync_method = fsync # the default is the first option
# supported by the operating system:
# open_datasync
# fdatasync (default on Linux)
# fsync
# fsync_writethrough
# open_sync
#full_page_writes = on # recover from partial page writes
#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers
# (change requires restart)
#wal_writer_delay = 200ms # 1-10000 milliseconds
#commit_delay = 0 # range 0-100000, in microseconds
#commit_siblings = 5 # range 1-1000
# - Checkpoints -
#checkpoint_segments = 3 # in logfile segments, min 1, 16MB each
#checkpoint_timeout = 5min # range 30s-1h
#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0
#checkpoint_warning = 30s # 0 disables
# - Archiving -
#archive_mode = off # allows archiving to be done
# (change requires restart)
#archive_command = '' # command to use to archive a logfile segment
# placeholders: %p = path of file to archive
# %f = file name only
# e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'
#archive_timeout = 0 # force a logfile segment switch after this
# number of seconds; 0 disables
#------------------------------------------------------------------------------
# REPLICATION
#------------------------------------------------------------------------------
# - Sending Server(s) -
# Set these on the master and on any standby that will send replication data.
#max_wal_senders = 0 # max number of walsender processes
# (change requires restart)
#wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables
#wal_sender_timeout = 60s # in milliseconds; 0 disables
# - Master Server -
# These settings are ignored on a standby server.
#synchronous_standby_names = '' # standby servers that provide sync rep
# comma-separated list of application_name
# from standby(s); '*' = all
#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed
# - Standby Servers -
# These settings are ignored on a master server.
#hot_standby = off # "on" allows queries during recovery
# (change requires restart)
#max_standby_archive_delay = 30s # max delay before canceling queries
# when reading WAL from archive;
# -1 allows indefinite delay
#max_standby_streaming_delay = 30s # max delay before canceling queries
# when reading streaming WAL;
# -1 allows indefinite delay
#wal_receiver_status_interval = 10s # send replies at least this often
# 0 disables
#hot_standby_feedback = off # send info from standby to prevent
# query conflicts
#wal_receiver_timeout = 60s # time that receiver waits for
# communication from master
# in milliseconds; 0 disables
#------------------------------------------------------------------------------
# QUERY TUNING
#------------------------------------------------------------------------------
# - Planner Method Configuration -
#enable_bitmapscan = on
#enable_hashagg = on
#enable_hashjoin = on
#enable_indexscan = on
#enable_indexonlyscan = on
#enable_material = on
#enable_mergejoin = on
#enable_nestloop = on
#enable_seqscan = on
#enable_sort = on
#enable_tidscan = on
# - Planner Cost Constants -
#seq_page_cost = 1.0 # measured on an arbitrary scale
#random_page_cost = 4.0 # same scale as above
#cpu_tuple_cost = 0.01 # same scale as above
#cpu_index_tuple_cost = 0.005 # same scale as above
#cpu_operator_cost = 0.0025 # same scale as above
#effective_cache_size = 128MB
# - Genetic Query Optimizer -
#geqo = on
#geqo_threshold = 12
#geqo_effort = 5 # range 1-10
#geqo_pool_size = 0 # selects default based on effort
#geqo_generations = 0 # selects default based on effort
#geqo_selection_bias = 2.0 # range 1.5-2.0
#geqo_seed = 0.0 # range 0.0-1.0
# - Other Planner Options -
#default_statistics_target = 100 # range 1-10000
#constraint_exclusion = partition # on, off, or partition
#cursor_tuple_fraction = 0.1 # range 0.0-1.0
#from_collapse_limit = 8
#join_collapse_limit = 8 # 1 disables collapsing of explicit
# JOIN clauses
#------------------------------------------------------------------------------
# ERROR REPORTING AND LOGGING
#------------------------------------------------------------------------------
# - Where to Log -
#log_destination = 'stderr' # Valid values are combinations of
# stderr, csvlog, syslog, and eventlog,
# depending on platform. csvlog
# requires logging_collector to be on.
# This is used when logging to stderr:
#logging_collector = off # Enable capturing of stderr and csvlog
# into log files. Required to be on for
# csvlogs.
# (change requires restart)
# These are only used if logging_collector is on:
#log_directory = 'pg_log' # directory where log files are written,
# can be absolute or relative to PGDATA
#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern,
# can include strftime() escapes
#log_file_mode = 0600 # creation mode for log files,
# begin with 0 to use octal notation
#log_truncate_on_rotation = off # If on, an existing log file with the
# same name as the new log file will be
# truncated rather than appended to.
# But such truncation only occurs on
# time-driven rotation, not on restarts
# or size-driven rotation. Default is
# off, meaning append to existing files
# in all cases.
#log_rotation_age = 1d # Automatic rotation of logfiles will
# happen after that time. 0 disables.
#log_rotation_size = 10MB # Automatic rotation of logfiles will
# happen after that much log output.
# 0 disables.
# These are relevant when logging to syslog:
#syslog_facility = 'LOCAL0'
#syslog_ident = 'postgres'
# This is only relevant when logging to eventlog (win32):
#event_source = 'PostgreSQL'
# - When to Log -
#client_min_messages = notice # values in order of decreasing detail:
# debug5
# debug4
# debug3
# debug2
# debug1
# log
# notice
# warning
# error
#log_min_messages = warning # values in order of decreasing detail:
# debug5
# debug4
# debug3
# debug2
# debug1
# info
# notice
# warning
# error
# log
# fatal
# panic
#log_min_error_statement = error # values in order of decreasing detail:
# debug5
# debug4
# debug3
# debug2
# debug1
# info
# notice
# warning
# error
# log
# fatal
# panic (effectively off)
#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements
# and their durations, > 0 logs only
# statements running at least this number
# of milliseconds
# - What to Log -
#debug_print_parse = off
#debug_print_rewritten = off
#debug_print_plan = off
#debug_pretty_print = on
#log_checkpoints = off
#log_connections = off
#log_disconnections = off
#log_duration = off
#log_error_verbosity = default # terse, default, or verbose messages
#log_hostname = off
log_line_prefix = '%t ' # special values:
# %a = application name
# %u = user name
# %d = database name
# %r = remote host and port
# %h = remote host
# %p = process ID
# %t = timestamp without milliseconds
# %m = timestamp with milliseconds
# %i = command tag
# %e = SQL state
# %c = session ID
# %l = session line number
# %s = session start timestamp
# %v = virtual transaction ID
# %x = transaction ID (0 if none)
# %q = stop here in non-session
# processes
# %% = '%'
# e.g. '<%u%%%d> '
#log_lock_waits = off # log lock waits >= deadlock_timeout
#log_statement = 'none' # none, ddl, mod, all
#log_temp_files = -1 # log temporary files equal or larger
# than the specified size in kilobytes;
# -1 disables, 0 logs all temp files
log_timezone = 'UTC'
#------------------------------------------------------------------------------
# RUNTIME STATISTICS
#------------------------------------------------------------------------------
# - Query/Index Statistics Collector -
#track_activities = on
#track_counts = on
#track_io_timing = off
#track_functions = none # none, pl, all
#track_activity_query_size = 1024 # (change requires restart)
#update_process_title = on
#stats_temp_directory = 'pg_stat_tmp'
# - Statistics Monitoring -
#log_parser_stats = off
#log_planner_stats = off
#log_executor_stats = off
#log_statement_stats = off
#------------------------------------------------------------------------------
# AUTOVACUUM PARAMETERS
#------------------------------------------------------------------------------
#autovacuum = on # Enable autovacuum subprocess? 'on'
# requires track_counts to also be on.
#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and
# their durations, > 0 logs only
# actions running at least this number
# of milliseconds.
#autovacuum_max_workers = 3 # max number of autovacuum subprocesses
# (change requires restart)
#autovacuum_naptime = 1min # time between autovacuum runs
#autovacuum_vacuum_threshold = 50 # min number of row updates before
# vacuum
#autovacuum_analyze_threshold = 50 # min number of row updates before
# analyze
#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum
#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze
#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum
# (change requires restart)
#autovacuum_multixact_freeze_max_age = 400000000 # maximum Multixact age
# before forced vacuum
# (change requires restart)
#autovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for
# autovacuum, in milliseconds;
# -1 means use vacuum_cost_delay
#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for
# autovacuum, -1 means use
# vacuum_cost_limit
#------------------------------------------------------------------------------
# CLIENT CONNECTION DEFAULTS
#------------------------------------------------------------------------------
# - Statement Behavior -
#search_path = '"$user",public' # schema names
#default_tablespace = '' # a tablespace name, '' uses the default
#temp_tablespaces = '' # a list of tablespace names, '' uses
# only default tablespace
#check_function_bodies = on
#default_transaction_isolation = 'read committed'
#default_transaction_read_only = off
#default_transaction_deferrable = off
#session_replication_role = 'origin'
#statement_timeout = 0 # in milliseconds, 0 is disabled
#lock_timeout = 0 # in milliseconds, 0 is disabled
#vacuum_freeze_min_age = 50000000
#vacuum_freeze_table_age = 150000000
#vacuum_multixact_freeze_min_age = 5000000
#vacuum_multixact_freeze_table_age = 150000000
#bytea_output = 'hex' # hex, escape
#xmlbinary = 'base64'
#xmloption = 'content'
# - Locale and Formatting -
datestyle = 'iso, mdy'
#intervalstyle = 'postgres'
timezone = 'UTC'
#timezone_abbreviations = 'Default' # Select the set of available time zone
# abbreviations. Currently, there are
# Default
# Australia
# India
# You can create your own file in
# share/timezonesets/.
#extra_float_digits = 0 # min -15, max 3
#client_encoding = sql_ascii # actually, defaults to database
# encoding
# These settings are initialized by initdb, but they can be changed.
lc_messages = 'en_US.UTF-8' # locale for system error message
# strings
lc_monetary = 'en_US.UTF-8' # locale for monetary formatting
lc_numeric = 'en_US.UTF-8' # locale for number formatting
lc_time = 'en_US.UTF-8' # locale for time formatting
# default configuration for text search
default_text_search_config = 'pg_catalog.english'
# - Other Defaults -
#dynamic_library_path = '$libdir'
#local_preload_libraries = ''
#------------------------------------------------------------------------------
# LOCK MANAGEMENT
#------------------------------------------------------------------------------
#deadlock_timeout = 1s
#max_locks_per_transaction = 64 # min 10
# (change requires restart)
# Note: Each lock table slot uses ~270 bytes of shared memory, and there are
# max_locks_per_transaction * (max_connections + max_prepared_transactions)
# lock table slots.
#max_pred_locks_per_transaction = 64 # min 10
# (change requires restart)
#------------------------------------------------------------------------------
# VERSION/PLATFORM COMPATIBILITY
#------------------------------------------------------------------------------
# - Previous PostgreSQL Versions -
#array_nulls = on
#backslash_quote = safe_encoding # on, off, or safe_encoding
#default_with_oids = off
#escape_string_warning = on
#lo_compat_privileges = off
#quote_all_identifiers = off
#sql_inheritance = on
#standard_conforming_strings = on
#synchronize_seqscans = on
# - Other Platforms and Clients -
#transform_null_equals = off
#------------------------------------------------------------------------------
# ERROR HANDLING
#------------------------------------------------------------------------------
#exit_on_error = off # terminate session on any error?
#restart_after_crash = on # reinitialize after backend crash?
#------------------------------------------------------------------------------
# CONFIG FILE INCLUDES
#------------------------------------------------------------------------------
# These options allow settings to be loaded from files other than the
# default postgresql.conf.
#include_dir = 'conf.d' # include files ending in '.conf' from
# directory 'conf.d'
#include_if_exists = 'exists.conf' # include file only if it exists
#include = 'special.conf' # include file
#------------------------------------------------------------------------------
# CUSTOMIZED OPTIONS
#------------------------------------------------------------------------------
# Add settings for extensions here

View File

@ -1,20 +0,0 @@
openssh-server:
pkg:
- installed
/etc/ssh/sshd_config:
file.managed:
- user: root
- group: root
- mode: 644
- source: salt://ssh/sshd_config
- template: jinja
ssh:
service:
- running
- watch:
- file: /etc/ssh/sshd_config
- file: /etc/network/if-pre-up.d/iptables
- require:
- pkg: openssh-server

View File

@ -1,90 +0,0 @@
# Package generated configuration file
# See the sshd_config(5) manpage for details
# Use these options to restrict which interfaces/protocols sshd will bind to
#ListenAddress ::
#ListenAddress 0.0.0.0
Protocol 2
# HostKeys for protocol version 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
#Privilege Separation is turned on for security
UsePrivilegeSeparation yes
# Lifetime and size of ephemeral version 1 server key
KeyRegenerationInterval 3600
ServerKeyBits 768
# Logging
SyslogFacility AUTH
LogLevel INFO
# Authentication:
LoginGraceTime 120
StrictModes yes
RSAAuthentication yes
PubkeyAuthentication yes
#AuthorizedKeysFile %h/.ssh/authorized_keys
# Don't read the user's ~/.rhosts and ~/.shosts files
IgnoreRhosts yes
# For this to work you will also need host keys in /etc/ssh_known_hosts
RhostsRSAAuthentication no
# similar for protocol version 2
HostbasedAuthentication no
# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
#IgnoreUserKnownHosts yes
# To enable empty passwords, change to yes (NOT RECOMMENDED)
PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no
# Change to no to disable tunnelled clear text passwords
#PasswordAuthentication yes
# Kerberos options
#KerberosAuthentication no
#KerberosGetAFSToken no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
X11Forwarding yes
X11DisplayOffset 10
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
#UseLogin no
#MaxStartups 10:30:60
#Banner /etc/issue.net
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes
UseDNS no
Port {{ pillar.ssh.port }}
PermitRootLogin no
PasswordAuthentication no
AllowUsers {% for user in pillar.users %}{{ user.name }} {% endfor %}

View File

@ -1,35 +0,0 @@
python-pip:
pkg.installed
supervisor:
pip.installed
/etc/supervisord.conf:
file.managed:
- source: salt://supervisor/supervisord.conf
- mode: 755
/etc/init.d/supervisord:
file.managed:
- source: salt://supervisor/supervisord.init.d
- mode: 755
/var/log/supervisor:
file.directory
/etc/supervisor:
file.directory
/etc/supervisor/conf.d:
file.directory
supervisord:
service.running:
- require:
- file: /etc/init.d/supervisord
- file: /var/log/supervisor
- watch:
- file: /etc/supervisord.conf
- file: /etc/supervisor/conf.d/*
cmd.run:
- name: update-rc.d supervisord defaults

View File

@ -1,17 +0,0 @@
[unix_http_server]
file = /var/run/supervisor.sock
chmod = 0700
[supervisord]
logfile = /var/log/supervisor/supervisord.log
pidfile = /var/run/supervisord.pid
childlogdir = /var/log/supervisor
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl = unix:///var/run/supervisor.sock
[include]
files = /etc/supervisor/conf.d/*.conf

View File

@ -1,187 +0,0 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: supervisord
# Required-Start: $remote_fs
# Required-Stop: $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Example initscript
# Description: This file should be used to construct scripts to be
# placed in /etc/init.d.
### END INIT INFO
# Author: Dan MacKinlay <danielm@phm.gov.au>
# Based on instructions by Bertrand Mathieu
# http://zebert.blogspot.com/2009/05/installing-django-solr-varnish-and.html
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Description of the service"
NAME=supervisord
DAEMON=/usr/local/bin/supervisord
DAEMON_ARGS="-c /etc/supervisord.conf"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}
running_pid()
{
# Check if a given process pid's cmdline matches a given name
pid=$1
name=$2
[ -z "$pid" ] && return 1
[ ! -d /proc/$pid ] && return 1
(cat /proc/$pid/cmdline | tr "\000" "\n"|grep -q $name) || return 1
return 0
}
running()
{
# Check if the process is running looking at /proc
# (works for all users)
# No pidfile, probably no daemon present
[ ! -f "$PIDFILE" ] && return 1
# Obtain the pid and check it against the binary name
pid=`cat $PIDFILE`
running_pid $pid $DAEMON || return 1
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
echo -n "$NAME is "
if running ; then
echo "running"
else
echo "not running."
exit 1
fi
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
exit 3
;;
esac
:

View File

@ -1,25 +0,0 @@
build-essential:
pkg.installed:
- pkgs:
- build-essential
iptables:
pkg.installed:
- pkgs:
- iptables
system:
pkg.installed:
- pkgs:
- cmake
- curl
- exuberant-ctags
- git
- htop
- libpq-dev
- libxml2-dev
- libxslt1-dev
- mercurial
- python-dev
- tree
- openjdk-7-jdk

View File

@ -1,13 +0,0 @@
base:
'*':
- system
- iptables
- ssh
- users
- fish
- elasticsearch
- postgresql
- nginx
- supervisor
- application
- cron

View File

@ -1 +0,0 @@
ssh-dss AAAAB3NzaC1kc3MAAACBAKzhHc1iq/4P/kFcqnMFy/oP7fFOwDQjaKrQPGmMC1X19vb3AUjzyAKVbf4WolBDsnc2U8p9memnM1xfZ/s7VM2RRQMbAwgp0la5D/fVAhNd5cubeHlQlowt/6TFAUVISJVAyIEVs+zdb5gYtm9Bowsf/+8bV+JYG/bniIcTPKwXAAAAFQChvjdSMM4rgZ3CVECrLHOVFdyYTQAAAIBzB0z/gOTBB/CQ9mfo05b5Doplkxd+HYIyaLjNErs0R1WVkbIlFInvxeBsUWKv/t8yuwKwP4UuWzFzE+RS+WYzakd3H2WJryTnVEhyfhQGqyFvSnixqrHylJPNu14RAC2lMZFgJMOwJ9Rsw5YNgNnptwCj50sc5u49uadjoAUKYgAAAIAB7IRBOI+/iKDgeDU1fs8TuNkXKd8piP3zuEac/sgF/GzxCrTXM89yWPlWtVF/b76i5DLkdORFS0jKOILGOCCGoGnxvGuUfnB4IcvQIBJ4GVpSTaiVzq+nYgO6IelUKo2Zh7R8jYjvoOZulPZP7EwpaaAfYlWEbwPddqvX7OfiHg== nick@nicksergeant.com

View File

@ -1,58 +0,0 @@
deploy-group:
group.present:
- name: deploy
wheel-group:
group.present:
- name: wheel
{% for user in pillar.users %}
{{ user.name }}:
user.present:
- name: {{ user.name }}
- home: /home/{{ user.name }}
- groups: {{ user.groups }}
- require:
{% for group in user.groups %}
- group: {{ group }}
{% endfor %}
- pkg: fish
- shell: /usr/bin/fish
ssh_auth.present:
- user: {{ user.name }}
{% if user.name != 'vagrant' and user.name != 'deploy' %}
- source: salt://users/{{ user.name }}.pub
{% endif %}
- makedirs: True
{% endfor %}
{% if pillar.env_name != 'vagrant' %}
deploy-authorized-keys:
file.managed:
- name: /home/deploy/.ssh/authorized_keys
- user: deploy
- group: deploy
- mode: 600
- source: salt://users/deploy.authorized_keys
- makedirs: True
- require:
- user: deploy
deploy-known-hosts:
file.managed:
- name: /home/deploy/.ssh/known_hosts
- user: deploy
- group: deploy
- mode: 700
- source: salt://users/known_hosts
- makedirs: True
{% endif %}
/etc/sudoers:
file.managed:
- source: salt://users/sudoers
- mode: 440

View File

@ -1 +0,0 @@
github.com,207.97.227.239 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==

View File

@ -1 +0,0 @@
ssh-dss AAAAB3NzaC1kc3MAAACBAKzhHc1iq/4P/kFcqnMFy/oP7fFOwDQjaKrQPGmMC1X19vb3AUjzyAKVbf4WolBDsnc2U8p9memnM1xfZ/s7VM2RRQMbAwgp0la5D/fVAhNd5cubeHlQlowt/6TFAUVISJVAyIEVs+zdb5gYtm9Bowsf/+8bV+JYG/bniIcTPKwXAAAAFQChvjdSMM4rgZ3CVECrLHOVFdyYTQAAAIBzB0z/gOTBB/CQ9mfo05b5Doplkxd+HYIyaLjNErs0R1WVkbIlFInvxeBsUWKv/t8yuwKwP4UuWzFzE+RS+WYzakd3H2WJryTnVEhyfhQGqyFvSnixqrHylJPNu14RAC2lMZFgJMOwJ9Rsw5YNgNnptwCj50sc5u49uadjoAUKYgAAAIAB7IRBOI+/iKDgeDU1fs8TuNkXKd8piP3zuEac/sgF/GzxCrTXM89yWPlWtVF/b76i5DLkdORFS0jKOILGOCCGoGnxvGuUfnB4IcvQIBJ4GVpSTaiVzq+nYgO6IelUKo2Zh7R8jYjvoOZulPZP7EwpaaAfYlWEbwPddqvX7OfiHg== nick@nicksergeant.com

View File

@ -1,32 +0,0 @@
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults env_reset
Defaults exempt_group=admin
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
# Host alias specification
# User alias specification
# Cmnd alias specification
# User privilege specification
root ALL=(ALL:ALL) ALL
# Members of the admin group may gain root privileges
%admin ALL=(ALL) NOPASSWD:ALL
# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) ALL
# See sudoers(5) for more information on "#include" directives:
#includedir /etc/sudoers.d
%wheel ALL=(ALL) NOPASSWD:ALL

View File

@ -11,10 +11,12 @@ if 'DATABASE_URL' in os.environ:
DATABASES = {'default': dj_database_url.config()}
if 'SEARCHBOX_SSL_URL' in os.environ:
es = urlparse(os.environ.get('SEARCHBOX_SSL_URL') or
'http://127.0.0.1:9200/')
port = es.port or 80
port = es.port or 443
HAYSTACK_CONNECTIONS = {
'default': {
@ -29,18 +31,28 @@ if 'DATABASE_URL' in os.environ:
"http_auth": es.username + ':' + es.password
}
if 'HAYSTACK_URL' in os.environ:
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
'URL': os.environ.get('HAYSTACK_URL'),
'INDEX_NAME': 'snipts',
},
}
ABSOLUTE_URL_OVERRIDES = {'auth.user': lambda u: "/%s/" % u.username}
ACCOUNT_ACTIVATION_DAYS = 14
ACCOUNT_ACTIVATION_DAYS = 0
ADMINS = (('Nick Sergeant', 'nick@snipt.net'),)
ALLOWED_HOSTS = ['*']
AUTH_PROFILE_MODULE = 'accounts.UserProfile'
AUTHENTICATION_BACKENDS = ('utils.backends.EmailOrUsernameModelBackend',)
BASE_PATH = os.path.dirname(__file__)
CSRF_COOKIE_SECURE = True if 'USE_SSL' in os.environ else False
DEBUG = True if 'DEBUG' in os.environ else False
DEFAULT_FROM_EMAIL = 'support@snipt.net'
DEFAULT_FROM_EMAIL = os.environ.get('POSTMARK_EMAIL', 'support@snipt.net')
EMAIL_BACKEND = 'postmark.django_backend.EmailBackend'
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
INTERCOM_SECRET_KEY = os.environ.get('INTERCOM_SECRET_KEY', '')
INTERNAL_IPS = ('127.0.0.1',)
LANGUAGE_CODE = 'en-us'
LOGIN_REDIRECT_URL = '/login-redirect/'
@ -61,20 +73,20 @@ PASSWORD_HASHERS = (
)
POSTMARK_API_KEY = os.environ.get('POSTMARK_API_KEY', '')
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
RAVEN_CONFIG = {'dsn': os.environ.get('RAVEN_CONFIG_DSN', '')}
REGISTRATION_EMAIL_HTML = False
ROOT_URLCONF = 'urls'
SECRET_KEY = os.environ.get('SECRET_KEY', 'changeme')
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True if 'USE_SSL' in os.environ else False
SEND_BROKEN_LINK_EMAILS = False
SERVER_EMAIL = 'support@snipt.net'
SERVER_EMAIL = os.environ.get('POSTMARK_EMAIL', 'support@snipt.net')
SESSION_COOKIE_AGE = 15801100
SESSION_COOKIE_SECURE = True if 'USE_SSL' in os.environ else False
SITE_ID = 1
STATICFILES_DIRS = (os.path.join(BASE_PATH, 'media'),)
STATICFILES_FINDERS = ('django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder')
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
STATIC_ROOT = os.path.join(BASE_PATH, 'static')
STATIC_URL = '/static/'
TASTYPIE_CANNED_ERROR = """There was an error with your request. The site
@ -121,7 +133,6 @@ INSTALLED_APPS = (
'markdown_deux',
'pagination',
'postmark',
'raven.contrib.django.raven_compat',
'registration',
'snipts',
'storages',
@ -143,6 +154,7 @@ LOGGING = {
'loggers': {}
}
MIDDLEWARE_CLASSES = (
'django.middleware.security.SecurityMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.common.CommonMiddleware',

View File

@ -1,11 +1,8 @@
CSRF_COOKIE_SECURE = False
DEBUG = True
INTERCOM_SECRET_KEY = ''
POSTMARK_API_KEY = ''
RAVEN_CONFIG = {'dsn': ''}
SECRET_KEY = 'changeme'
SESSION_COOKIE_SECURE = False
SSLIFY_DISABLE = False
STRIPE_SECRET_KEY = ''
USE_HTTPS = False

View File

View File

@ -0,0 +1,74 @@
#!/usr/bin/env python
from snipts.models import Snipt
from django.contrib.auth.models import User
from django.core.management.base import BaseCommand
import requests
def get_snipts(api_key, from_username, url=None, snipts=[]):
path = url or '/api/private/snipt/?limit=50&api_key={}&username={}&format=json'.format(api_key, from_username)
res = requests.get('https://snipt.net' + path)
json = res.json()
print(u"Fetched snipts {} through {} of {}".format(
json["meta"]["offset"],
json["meta"]["offset"] + json["meta"]["limit"],
json["meta"]["total_count"]
))
snipts.extend(json["objects"])
if json["meta"]["next"]:
return get_snipts(api_key, from_username, json["meta"]["next"], snipts)
else:
return snipts
class Command(BaseCommand):
help = u"Import snipts from snipt.net."
def add_arguments(self, parser):
parser.add_argument('api_key', nargs='+', type=str)
parser.add_argument('from_username', nargs='+', type=str)
parser.add_argument('to_username', nargs='+', type=str)
def handle(self, *args, **options):
api_key = options['api_key'][0]
from_username = options['from_username'][0]
to_username = options['to_username'][0]
to_user = User.objects.get(username=to_username)
print(u"Fetching snipts...")
items = get_snipts(api_key, from_username)
for snipt in items:
s = Snipt(
blog_post=snipt["blog_post"],
code=snipt["code"],
created=snipt["created"],
description=snipt["description"],
id=snipt["id"],
key=snipt["key"],
lexer=snipt["lexer"],
line_count=snipt["line_count"],
meta=snipt["meta"],
modified=snipt["modified"],
public=snipt["public"],
publish_date=snipt["publish_datetime"],
secure=snipt["secure"],
slug=snipt["slug"],
stylized=snipt["stylized"],
title=snipt["title"],
user=to_user,
views=snipt["views"]
)
for tag in snipt["tags"]:
s.tags.add(tag["name"])
s.save()
self.stdout.write(snipt["title"])

View File

@ -236,18 +236,12 @@ class Snipt(models.Model):
return u'https://{}.snipt.net/{}/'.format(
self.user.username, self.slug)
if settings.DEBUG:
root = 'http://local.snipt.net'
else:
root = 'https://snipt.net'
if self.public:
return u'{}/{}/{}/'.format(root, self.user.username, self.slug)
return u'/{}/{}/'.format(self.user.username, self.slug)
else:
return u'{}/{}/{}/?key={}'.format(root,
self.user.username,
self.slug,
self.key)
return u'/{}/{}/?key={}'.format(self.user.username,
self.slug,
self.key)
def get_download_url(self):
@ -264,12 +258,7 @@ class Snipt(models.Model):
else:
filename = u'{}.txt'.format(self.slug)
if settings.DEBUG:
root = 'http://local.snipt.net'
else:
root = 'https://snipt.net'
return u'{}/download/{}/{}'.format(root, self.key, filename)
return u'/download/{}/{}'.format(self.key, filename)
def get_embed_url(self):
@ -281,13 +270,7 @@ class Snipt(models.Model):
return '{}/embed/{}/'.format(root, self.key)
def get_raw_url(self):
if settings.DEBUG:
root = 'http://local.snipt.net'
else:
root = 'https://snipt.net'
return '{}/raw/{}/'.format(root, self.key)
return '/raw/{}/'.format(self.key)
@property
def sorted_tags(self):

View File

@ -77,29 +77,5 @@
</footer>
{% endfor %}
</div>
<div id="disqus_thread">
{% if snipt.public %}
<script type="text/javascript">
var disqus_shortname = 'snipt-net';
{% if debug %}
var disqus_developer = 1;
{% endif %}
var disqus_url = '{{ snipt.get_full_absolute_url }}';
var disqus_title = '{{ snipt.title }}';
var disqus_identifier = {{ snipt.id }};
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'https://' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
{% else %}
<p class="alert alert-info">
<strong>Disqus comments are disabled on private snipts.</strong><br /><br />
See <a href="https://github.com/nicksergeant/snipt/issues/53">https://github.com/nicksergeant/snipt/issues/53</a> for more information.
</p>
{% endif %}
</div>
</section>
{% endblock %}

View File

@ -21,7 +21,3 @@
</li>
{% endif %}
{% endblock %}
{% block aside-top %}
{% include "snipts/tags-public.html" %}
{% endblock %}

View File

@ -26,10 +26,10 @@
{% include "snipts/snipt-list.html" %}
{% empty %}
<div class="empty-snipts">
{% if request.user == user and not request.user.is_active %}
{% if request.user == user and not request.user.is_active and not public %}
Welcome! Please <a target="_self" href="/account/activate/">activate your account</a> to create your first snipt.
{% else %}
{% if request.user == user %}
{% if request.user == user and request.user.is_authenticated %}
Welcome! Create your first snipt by clicking "Add Snipt" above.
{% else %}
No snipts to show here. Sorry!
@ -43,10 +43,10 @@
{% include "snipts/snipt-list.html" %}
{% empty %}
<div class="empty-snipts">
{% if request.user == user and not request.user.is_active %}
{% if request.user == user and not request.user.is_active and not public %}
Welcome! Please <a target="_self" href="/account/activate/">activate your account</a> to create your first snipt.
{% else %}
{% if request.user == user %}
{% if request.user == user and request.user.is_authenticated %}
Welcome! Create your first snipt by clicking "Add Snipt" above.
{% else %}
No snipts to show here. Sorry!
@ -57,30 +57,4 @@
{% paginate %}
{% endif %}
</section>
<script type="text/javascript" id="disqus">
var disqus_shortname = 'snipt-net';
{% if debug %}
var disqus_developer = 1;
{% endif %}
(function () {
var s = document.createElement('script'); s.async = true;
s.type = 'text/javascript';
s.src = 'https://' + disqus_shortname + '.disqus.com/count.js';
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
}());
</script>
<script type="text/html" id="disqus-template">
var disqus_shortname = 'snipt-net';
{% if debug %}
var disqus_developer = 1;
{% endif %}
(function () {
var s = document.createElement('script'); s.async = true;
s.type = 'text/javascript';
s.src = 'https://' + disqus_shortname + '.disqus.com/count.js';
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
}());
</script>
{% endblock %}

View File

@ -112,18 +112,6 @@
{% endif %}
<div class="ruler top-x"></div>
<div class="ruler bottom-x"></div>
{% if detail and not request.user.is_authenticated %}
<div class="ruler ad-x"></div>
<div class="inline-ad">
<span class="block"></span>
<p>
Want to make sure your code is always working?
Try <a href="https://instrumentalapp.com/">custom application monitoring</a>
from Instrumental!
</p>
<span class="ad">Advertisement</span>
</div>
{% endif %}
</div>
{% block aside %}
<aside ng-show="!account || account.list_view == 'N'">
@ -214,9 +202,6 @@
{% else %}
<li class="created" title="{{ snipt.created|date:"Y-m-d\TH:i:s" }}">{{ snipt.created|naturaltime }}</li>
{% endif %}
{% if snipt.public and not detail %}
<li class="comments"><a href="{{ snipt.get_full_absolute_url }}#disqus_thread" data-disqus-identifier="{{ snipt.pk }}"></a></li>
{% endif %}
<li class="raw">
<a href="{{ snipt.get_raw_url }}">Raw</a> /
<a href="{{ snipt.get_raw_url }}?nice">Raw Nice</a>
@ -224,17 +209,6 @@
/ <a href="/api/public/snipt/{{ snipt.id }}/?format=json">API</a>
{% endif %}
</li>
{% if request.user.is_authenticated and snipt.user != request.user %}
{% if request.user.is_superuser %}
<li class="report-spam">
<a target="_blank" href="/admin/auth/user/{{ snipt.user.id }}/delete/">Delete User</a>
</li>
{% else %}
<li class="report-spam">
<a target="_blank" href="/report-spam/{{ snipt.id }}/">Report Spam</a>
</li>
{% endif %}
{% endif %}
{% if detail and snipt.public %}
<li class="tweet">
<a href="https://twitter.com/share" class="twitter-share-button" data-dnt="true" data-count="none" data-url="{{ snipt.get_full_absolute_url }}" data-text="&ldquo;{{ snipt.title }}&rdquo; on @Snipt">Tweet</a>

View File

@ -1,63 +0,0 @@
<section class="tags">
<h1>Popular public tags</h1>
<ul>
<li>
<a href="/public/tag/bash/" {% if tag.name == 'bash' %}class="active"{% endif %}><span>bash</span></a>
</li>
<li>
<a href="/public/tag/c_2/" {% if tag.name == 'c++' %}class="active"{% endif %}><span>c++</span></a>
</li>
<li>
<a href="/public/tag/css/" {% if tag.name == 'css' %}class="active"{% endif %}><span>css</span></a>
</li>
<li>
<a href="/public/tag/django/" {% if tag.name == 'django' %}class="active"{% endif %}><span>django</span></a>
</li>
<li>
<a href="/public/tag/drupal/" {% if tag.name == 'drupal' %}class="active"{% endif %}><span>drupal</span></a>
</li>
<li>
<a href="/public/tag/git/" {% if tag.name == 'git' %}class="active"{% endif %}><span>git</span></a>
</li>
<li>
<a href="/public/tag/html/" {% if tag.name == 'html' %}class="active"{% endif %}><span>html</span></a>
</li>
<li>
<a href="/public/tag/java/" {% if tag.name == 'java' %}class="active"{% endif %}><span>java</span></a>
</li>
<li>
<a href="/public/tag/javascript/" {% if tag.name == 'javascript' %}class="active"{% endif %}><span>javascript</span></a>
</li>
<li>
<a href="/public/tag/jquery/" {% if tag.name == 'jquery' %}class="active"{% endif %}><span>jquery</span></a>
</li>
<li>
<a href="/public/tag/js/" {% if tag.name == 'js' %}class="active"{% endif %}><span>js</span></a>
</li>
<li>
<a href="/public/tag/linux/" {% if tag.name == 'linux' %}class="active"{% endif %}><span>linux</span></a>
</li>
<li>
<a href="/public/tag/mysql/" {% if tag.name == 'mysql' %}class="active"{% endif %}><span>mysql</span></a>
</li>
<li>
<a href="/public/tag/php/" {% if tag.name == 'php' %}class="active"{% endif %}><span>php</span></a>
</li>
<li>
<a href="/public/tag/python/" {% if tag.name == 'python' %}class="active"{% endif %}><span>python</span></a>
</li>
<li>
<a href="/public/tag/rails/" {% if tag.name == 'rails' %}class="active"{% endif %}><span>rails</span></a>
</li>
<li>
<a href="/public/tag/ruby/" {% if tag.name == 'ruby' %}class="active"{% endif %}><span>ruby</span></a>
</li>
<li>
<a href="/public/tag/sql/" {% if tag.name == 'sql' %}class="active"{% endif %}><span>sql</span></a>
</li>
<li>
<a href="/public/tag/wordpress/" {% if tag.name == 'wordpress' %}class="active"{% endif %}><span>wordpress</span></a>
</li>
</ul>
<a href="/tags/" class="all-tags"><span>View all tags &raquo;</span></a>
</section>

View File

@ -1,4 +1,5 @@
import hashlib
import os
from django import template
from snipts.models import Favorite, Snipt
@ -42,6 +43,12 @@ def snipts_count_for_user(context):
return snipts
@tag(register, [Constant('as'), Variable()])
def signup_enabled(context, asvar):
context[asvar] = os.environ.get("DISABLE_SIGNUP") != "true"
return ''
@tag(register, [Constant('as'), Variable()])
def get_lexers(context, asvar):
context[asvar] = get_lexers_list()

View File

@ -29,9 +29,6 @@ urlpatterns = [
url(r'^raw/(?P<snipt_key>[^/]+)/(?P<lexer>[^\?]+)?$',
views.raw,
name='raw'),
url(r'^report-spam/(?P<snipt_id>[^/]+)/$',
views.report_spam,
name='report-spam'),
url(r'^(?P<username_or_custom_slug>[^/]+)/$',
views.list_user,
name='list-user'),

View File

@ -18,6 +18,9 @@ from snipts.models import Favorite, Snipt, SniptSecureView
from taggit.models import Tag
from teams.models import Team
import os
RESULTS_PER_PAGE = getattr(settings, 'HAYSTACK_SEARCH_RESULTS_PER_PAGE', 20)
@ -86,27 +89,6 @@ def embed(request, snipt_key):
content_type='application/javascript')
def report_spam(request, snipt_id):
if not request.user.is_authenticated():
return HttpResponseBadRequest()
snipt = get_object_or_404(Snipt, pk=snipt_id)
send_mail('[Snipt] Spam reported',
"""
Snipt: https://snipt.net/admin/snipts/snipt/{}/
User: https://snipt.net/admin/auth/user/{}/delete/
Reporter: https://snipt.net/{}/
""".format(snipt.id, snipt.user.id, request.user.username),
'support@snipt.net',
['nick@snipt.net'],
fail_silently=False)
return HttpResponse("""Thanks! Your report has been
submitted to the site admins.""")
@render_to('snipts/list-user.html')
def blog_posts(request, username):

View File

@ -1,11 +1,8 @@
import os
import uuid
from annoying.decorators import render_to
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.core.mail import send_mail
from django.http import Http404, HttpResponseRedirect, HttpResponseBadRequest
from django.shortcuts import get_object_or_404
from teams.models import Team
@ -37,15 +34,6 @@ def for_teams_complete(request):
team.user = user
team.save()
send_mail('[Snipt] New team signup: {}'.format(team.name),
"""
Team: https://snipt.net/{}
Email: {}
""".format(team.slug, team.email),
'support@snipt.net',
['nick@snipt.net'],
fail_silently=False)
return {
'team': team
}

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

@ -1,5 +1,7 @@
{% load snipt_tags static %}
{% signup_enabled as 'signup_is_enabled' %}
<!DOCTYPE html>
<html lang="en" class="{% block html-class %}{% endblock %}" ng-app="Snipt">
<head>
@ -41,15 +43,13 @@
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/highlightjs-themes/tomorrow.css" />
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/blog-themes/default/style.css" />
{% else %}
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/snipt.css?127" />
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/snipt.css?129" />
{% endif %}
{% if has_snipts and not detail %}
<link rel="alternate" type="application/rss+xml" title="RSS" href="{{ request.path }}?rss{% if not public %}&amp;api_key={{ request.user.api_key.key }}{% endif %}" />
{% endif %}
<link rel="author" href="/humans.txt" />
{% block css %}{% endblock %}
<!--[if IE]>
@ -68,25 +68,6 @@
</head>
<body class="{% block body-class %}{% endblock %} is-pro" ng-controller="AppController">
<!-- BuySellAds Ad Code -->
<script type="text/javascript">
(function(){
var bsa = document.createElement('script');
bsa.type = 'text/javascript';
bsa.async = true;
bsa.src = '//s3.buysellads.com/ac/bsa.js';
(document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(bsa);
})();
</script>
<!-- End BuySellAds Ad Code -->
<div class="closing">
<strong>Snipt.net is closing on December 31st, 2016</strong>
<p>
For more information, please visit <a href="https://blog.snipt.net/snipt-is-closing/">this blog post</a>.
</p>
</div>
{% block header %}
<header class="main">
<div class="inner">
@ -111,6 +92,11 @@
<li>
<a href="/login/?next={{ request.path }}" {% if '/login/' in request.path %} class="active"{% endif %}>Log in</a>
</li>
{% if signup_is_enabled %}
<li>
<a href="/signup/" {% if '/signup/' in request.path %} class="active"{% endif %}>Sign up</a>
</li>
{% endif %}
{% else %}
<li>
<a href="/{{ request.user.username }}/" {% if request.user.username in request.path %} class="active"{% endif %}>My snipts</a>
@ -184,12 +170,6 @@
Account
</a>
</li>
<li>
<a href="/for-teams/">
<i class="icon-star-empty icon-white"></i>
For Teams
</a>
</li>
{% if request.user.is_superuser %}
<li>
<a href="/admin/">
@ -229,49 +209,19 @@
<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">
<a href="/api/" {% if '/api/' in request.path %}class="active"{% endif %}><span>API</span></a>
</li>
<li class="twitter">
<a href="https://twitter.com/#!/snipt"><span>@snipt</span></a>
</li>
<li class="pro">
<a href="/for-teams/"><span>For Teams</span></a>
<a href="https://github.com/nicksergeant/snipt/wiki/API-Docs"><span>API Docs</span></a>
</li>
<li class="blog">
<a href="https://blog.snipt.net/"><span>Snipt Blog</span></a>
</li>
<li class="blog">
<a href="/apps/" {% if '/apps/' in request.path %}class="active"{% endif %}><span>Snipt Apps</span></a>
</li>
<li class="blog">
<a href="/blogging/" {% if '/blogging/' in request.path %}class="active"{% endif %}><span>Blogging on Snipt</span></a>
<a href="https://github.com/nicksergeant/snipt/wiki/Blogging-Docs"><span>Blogging Docs</span></a>
</li>
<li class="roadmap">
<a href="https://github.com/nicksergeant/snipt/"><span>Open source on GitHub</span></a>
</li>
<li class="roadmap">
<a href="https://github.com/nicksergeant/snipt/issues?state=open"><span>Bugs & feature requests</span></a>
</li>
<li class="roadmap">
<a href="http://getsentry.com/"><span>Shipped with confidence</span></a>
<a href="https://github.com/nicksergeant/snipt/"><span>GitHub Source</span></a>
</li>
</ul>
</nav>
<div class="linode">
<a href="https://www.linode.com/?utm_source=referral&utm_medium=website&utm_content=[Snipt.net]&utm_campaign=sponsorship" title="Sponsored by Linode" target="blank">
<span>Sponsored by</span>
</a>
</div>
</aside>
{% endblock %}
<div class="inner">
@ -437,13 +387,6 @@
</div>
{% endblock %}
<div class="dmca">
<strong>Copyrighted, illegal, or inappropriate content?</strong>
Email <a href="mailto:support@snipt.net">support@snipt.net</a>.
</div>
{% include 'analytics.html' %}
<script type="text/javascript">{% block analytics %}{% endblock %}</script>
{% block preload %}

View File

@ -1 +0,0 @@
<a class="go-pro" href="http://showroom.is/"></a>

View File

@ -57,58 +57,14 @@
<div class="container">
<div class="row">
<div class="span12">
<h4>{{ users_count|intcomma }} coders in over 120 countries have stored {{ snipts_count|intcomma }} snipts, in 145 languages.</h4>
<h4>This is a private instance of <a href="https://github.com/nicksergeant/snipt">Snipt</a>.</h4>
</div>
</div>
</div>
{% if request.user.is_authenticated %}
<a href="/{{ request.user.username }}/" class="button">My snipts</a>
{% else %}
<a href="/login/" class="button">Log in</a>
{% endif %}
<div class="faces group">
<div class="inner">
{% for coder in coders %}
<a href="/{{ coder.username }}/" title="{{ coder.username }}">
<img alt="{{ coder.username }}" title="{{ coder.username }}" src="https://secure.gravatar.com/avatar/{{ coder.email_md5 }}?s=50" />
</a>
{% endfor %}
</div>
</div>
</section>
<section class="features">
<div class="container">
<div class="row">
<header class="span4 offset4">
<h1>For teams or individuals</h1>
</header>
</div>
<div class="feature row share">
<div class="inner">
<h2>Team accounts</h2>
<p>
Create a <a href="/for-teams/">Team</a> account and allow your team members to create and
edit private and public code snippets. Search through all your team's snippets, and
view detailed diffs of changes to each snippet.
</p>
</div>
</div>
<div class="feature row blog">
<div class="inner">
<h2>Personal accounts</h2>
<p>
Individuals can post public and <code>private</code> snippets, making them perfect
for storing and organizing code you never want to forget.
</p>
</div>
</div>
<div class="feature row store">
<div class="inner">
<h2>Code-focused blogs</h2>
<p>
<a href="/blogging/">A full blog in seconds</a>: mark a snipt as "Blog Post", and it'll
appear on <code>{your-username}.snipt.net</code>. Markdown support built-in. Your domain, or ours.
</p>
</div>
</div>
</div>
</section>
{% endblock %}

View File

@ -1,13 +0,0 @@
/* TEAM */
Founder and Developer: Nick Sergeant
Contact: nick@snipt.net
Site: https://nicksergeant.com
Twitter: @nicksergeant
Location: Rochester, NY
/* SITE */
Standards: CSS3, HTML5
Components: Angular, Backbone.js, Twitter Bootstrap, jQuery, Underscore.js
Software: Django

View File

@ -1,11 +1 @@
Hey there,
Welcome to Snipt. If you ever have any thoughts or issues with the site whatsoever, please feel free to contact me directly.
Thanks!
Nick Sergeant
https://twitter.com/nicksergeant
https://twitter.com/snipt
nick@snipt.net
https://snipt.net
Welcome to Snipt!

View File

@ -7,7 +7,7 @@
{% block content %}
<div class="static-box">
<div class="alert alert-info alert-alone">
Signup complete! You're now logged in. Go <a href="/{{ request.user.username }}/">home</a>, perhaps?
Signup complete! You're now logged in. Go <a href="/login-redirect/">home</a>, perhaps?
</div>
</div>
{% endblock %}

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

@ -106,30 +106,4 @@
</div>
{% endif %}
{% endif %}
<script type="text/javascript" id="disqus">
var disqus_shortname = 'snipt-net';
{% if debug %}
var disqus_developer = 1;
{% endif %}
(function () {
var s = document.createElement('script'); s.async = true;
s.type = 'text/javascript';
s.src = 'https://' + disqus_shortname + '.disqus.com/count.js';
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
}());
</script>
<script type="text/html" id="disqus-template">
var disqus_shortname = 'snipt-net';
{% if debug %}
var disqus_developer = 1;
{% endif %}
(function () {
var s = document.createElement('script'); s.async = true;
s.type = 'text/javascript';
s.src = 'https://' + disqus_shortname + '.disqus.com/count.js';
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
}());
</script>
{% endblock %}

View File

@ -22,7 +22,3 @@
{% paginate %}
</div>
{% endblock %}
{% block aside-top %}
{% include "snipts/tags-public.html" %}
{% endblock %}

78
urls.py
View File

@ -4,16 +4,14 @@ from django.conf.urls import include, url
from django.contrib import admin
from django.contrib.auth.views import login
from django.http import HttpResponseRedirect
from django.views.generic import RedirectView, TemplateView
from django.views.generic import TemplateView
from django.views.static import serve
from forms import AuthenticationFormWithInactiveUsersOkay
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)
@ -28,47 +26,41 @@ private_api.register(PrivateUserResource())
private_api.register(PrivateFavoriteResource())
private_api.register(PrivateUserProfileResource())
urlpatterns = [
url(r'^$', homepage),
url(r'^login-redirect/$', login_redirect),
urlpatterns = []
url(r'^admin/', include(admin.site.urls)),
if os.environ.get("DISABLE_SIGNUP") == "true":
urlpatterns += [
url(r'^register/?$', lambda x: HttpResponseRedirect('/404/')),
url(r'^signup/?$', lambda x: HttpResponseRedirect('/404/')),
]
else:
urlpatterns += [
url(r'^signup/?$', lambda x: HttpResponseRedirect('/register/')),
]
url(r'^404/$', TemplateView.as_view(template_name='404.html')),
url(r'^500/$', TemplateView.as_view(template_name='500.html')),
url(r'^robots.txt$',
TemplateView.as_view(template_name='robots.txt')),
url(r'^humans.txt$',
TemplateView.as_view(template_name='humans.txt')),
url(r'^tags/$', tags),
url(r'^account/', include('accounts.urls')),
url(r'^api/public/lexer/$', lexers),
url(r'^api/private/key/$', user_api_key),
url(r'^api/', include(public_api.urls)),
url(r'^api/', include(private_api.urls)),
url(r'^search/$', search),
url(r'^activate/complete/$', RedirectView.as_view(
url='/login-redirect/')),
url(r'^login/?$', login, {
'authentication_form': AuthenticationFormWithInactiveUsersOkay
}, name='login'),
url(r'', include('registration.backends.default.urls')),
url(r'^', include('teams.urls')),
url(r'^', include('snipts.urls')),
url(r'^(?P<path>favicon\.ico)$', serve, {
'document_root': os.path.join(os.path.dirname(__file__),
'static/img')
}),
url(r'^static/(?P<path>.*)$', serve, {
'document_root': os.path.join(os.path.dirname(__file__),
'media')
})
urlpatterns += [
url(r'^$', homepage),
url(r'', include('registration.backends.simple.urls')),
url(r'^login/?$', login, name='login'),
url(r'^login-redirect/$', login_redirect),
url(r'^admin/', include(admin.site.urls)),
url(r'^404/$', TemplateView.as_view(template_name='404.html')),
url(r'^500/$', TemplateView.as_view(template_name='500.html')),
url(r'^robots.txt$', TemplateView.as_view(template_name='robots.txt')),
url(r'^tags/$', tags),
url(r'^account/', include('accounts.urls')),
url(r'^api/public/lexer/$', lexers),
url(r'^api/private/key/$', user_api_key),
url(r'^api/', include(public_api.urls)),
url(r'^api/', include(private_api.urls)),
url(r'^search/$', search),
url(r'^', include('teams.urls')),
url(r'^', include('snipts.urls')),
url(r'^(?P<path>favicon\.ico)$', serve, {
'document_root': os.path.join(os.path.dirname(__file__), 'static/img')
}),
url(r'^static/(?P<path>.*)$', serve, {
'document_root': os.path.join(os.path.dirname(__file__), 'media')
})
]

View File

@ -1,16 +0,0 @@
import hmac
import hashlib
import os
from django import template
from django.conf import settings
register = template.Library()
@register.filter
def intercom_sha_256(user_id):
return hmac.new(os.environ.get('INTERCOM_SECRET_KEY',
settings.INTERCOM_SECRET_KEY),
str(user_id),
digestmod=hashlib.sha256).hexdigest()

View File

@ -1,4 +1,4 @@
from registration.backends.default.views import RegistrationView
from registration.backends.simple.views import RegistrationView
from utils.forms import SniptRegistrationForm
@ -11,5 +11,5 @@ class SniptRegistrationView(RegistrationView):
def dispatch(self, request, *args, **kwargs):
return super(RegistrationView, self).dispatch(request, *args, **kwargs)
def get_success_url(self, request, user):
return '/account/activate/'
def get_success_url(self, request):
return '/login-redirect'

View File

@ -1,14 +1,7 @@
import hashlib
from accounts.models import UserProfile
from annoying.decorators import ajax_request, render_to
from blogs.views import blog_list
from django.contrib.auth.models import User
from django.db.models import Count
from django.http import HttpResponseRedirect, HttpResponseBadRequest
from django.shortcuts import render
from django.template import RequestContext
from snipts.models import Snipt
from snipts.utils import get_lexers_list
from taggit.models import Tag
@ -19,29 +12,7 @@ def homepage(request):
if request.blog_user:
return blog_list(request)
coders = []
users_with_gravatars = User.objects.filter(
userprofile__in=UserProfile.objects.filter(has_gravatar=True)
).order_by('?')
for user in users_with_gravatars:
public_snipts_count = Snipt.objects.filter(
user=user, public=True).values('pk').count()
if public_snipts_count:
user.email_md5 = hashlib.md5(user.email.lower().encode('utf-8')) \
.hexdigest()
coders.append(user)
if len(coders) == 35:
break
return {
'coders': coders,
'snipts_count': Snipt.objects.all().count(),
'users_count': User.objects.all().count(),
}
return {}
@ajax_request

18
wsgi.py
View File

@ -1,16 +1,10 @@
"""
WSGI config for what project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/
"""
from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
from django.core.wsgi import get_wsgi_application
from dj_static import Cling
application = Cling(get_wsgi_application())
application = get_wsgi_application()
application = DjangoWhiteNoise(application)