Merge fix

This commit is contained in:
Joshua McKenty 2013-06-30 16:39:36 -07:00
commit 7786681233
9 changed files with 385 additions and 9 deletions

2
.gitignore vendored
View File

@ -33,3 +33,5 @@ nosetests.xml
.mr.developer.cfg .mr.developer.cfg
.project .project
.pydevproject .pydevproject
*.db

1
Procfile Normal file
View File

@ -0,0 +1 @@
web: gunicorn refstack.web:app

50
alembic.ini Normal file
View File

@ -0,0 +1,50 @@
# A generic, single database configuration.
[alembic]
# path to migration scripts
script_location = alembic
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
sqlalchemy.url = driver://user:pass@localhost/dbname
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S

1
alembic/README Normal file
View File

@ -0,0 +1 @@
Generic single-database configuration.

79
alembic/env.py Normal file
View File

@ -0,0 +1,79 @@
from __future__ import with_statement
import os
import sys
sys.path.append("./")
from alembic import context
from sqlalchemy import engine_from_config, pool
from logging.config import fileConfig
from refstack.web import app
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
cur_db_uri = config.get_section_option('alembic', 'sqlalchemy.url')
my_db_uri = app.config.get('SQLALCHEMY_DATABASE_URI', cur_db_uri)
config.set_section_option('alembic', 'sqlalchemy.url', my_db_uri)
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
# target_metadata = None
from refstack.web import db
target_metadata = db.metadata
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(url=url)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
engine = engine_from_config(
config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool)
connection = engine.connect()
context.configure(
connection=connection,
target_metadata=target_metadata
)
try:
with context.begin_transaction():
context.run_migrations()
finally:
connection.close()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()

22
alembic/script.py.mako Normal file
View File

@ -0,0 +1,22 @@
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision}
Create Date: ${create_date}
"""
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}

View File

@ -0,0 +1,33 @@
"""First step
Revision ID: 2e26571834ea
Revises: None
Create Date: 2013-06-30 15:07:31.746984
"""
# revision identifiers, used by Alembic.
revision = '2e26571834ea'
down_revision = None
from alembic import op
import sqlalchemy as sa
def upgrade():
### commands auto generated by Alembic - please adjust! ###
op.create_table('vendor',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('vendor_name', sa.String(length=80), nullable=True),
sa.Column('contact_email', sa.String(length=120), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('contact_email'),
sa.UniqueConstraint('vendor_name')
)
### end Alembic commands ###
def downgrade():
### commands auto generated by Alembic - please adjust! ###
op.drop_table('vendor')
### end Alembic commands ###

152
refstack/static/toast.css Normal file
View File

@ -0,0 +1,152 @@
/*-----------------------------------*\
Toast
A Simple CSS Framework
=================================
Values you may want to change:
- .container { max-width:; }
- p { margin-bottom:; }
- html { font:; }
Remember: no framework will be as
good as a custom built, per-
project one. Toast and other
frameworks are best used for
rapid prototyping.
\*-----------------------------------*/
/*-----------------------------------*\
$RESET
\*-----------------------------------*/
* {
margin: 0;
padding: 0;
position: relative;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/*-----------------------------------*\
$GRID
\*-----------------------------------*/
.container {
/* Whatever you want. Theyre your oats. */
max-width: 960px;
margin: 0 auto;
padding: 0 30px;
padding: 0 1.5rem;
}
.grid {
margin-left: -3%;
max-width: 105%;
}
.unit {
display: inline-block;
*display: inline;
*zoom: 1;
vertical-align: top;
margin-left: 3%;
margin-right: -.25em;
/* Clearfix */
overflow: hidden;
*overflow: visible;
}
.unit.demo {
background-color: #fff8eb;
height: 48px;
height: 3rem;
margin-bottom: 24px;
margin-bottom: 1.5rem;
}
.span-grid {
width: 97%;
}
.one-of-two { width: 47%; }
.one-of-three { width: 30.36%; }
.two-of-three { width: 63.666666666%; }
.one-of-four { width: 22.05%; }
.three-of-four { width: 72%; }
.one-of-five { width: 17.07%; }
.two-of-five { width: 37%; }
.three-of-five { width: 57%; }
.four-of-five { width: 77%; }
@media screen and (max-width: 650px) {
.grid {
margin-left: 0;
max-width: none;
}
.unit {
width: auto;
margin-left: 0;
display: block;
}
}
/*-----------------------------------*\
$TYPE
Works off the assumption of a 1.5
line height @ 20px. Again, change
as necessary.
\*-----------------------------------*/
p, .p, ul, ol, hr, table, form, pre,
h1, .alpha, h2, .beta {
margin-bottom: 30px;
margin-bottom: 1.5rem;
}
h1, .alpha {
font-size: 60px;
font-size: 3rem;
font-weight: 700;
line-height: 1;
}
h2, .beta {
font-size: 30px;
font-size: 1.5rem;
font-weight: 400;
line-height: 2;
}
h3, .gamma {
font-size: 20px;
font-size: 1rem;
font-weight: 700;
}
hr {
border: none;
border-bottom: 1px solid rgba(0,0,0,.1);
margin-top: -1px;
}
/*-----------------------------------*\
$MAIN
\*-----------------------------------*/
html {
font: 125%/1.5 Helvetica Neue, Helvetica, Arial, sans-serif;
}
@media screen and (max-width: 650px) {
html {
font-size: 100%;
}
}

View File

@ -7,25 +7,51 @@ import os
import random import random
import sqlite3 import sqlite3
import sys import sys
from flask import Flask, request, render_template, g, jsonify from flask import Flask, flash, request, redirect, url_for, render_template, g, session
from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.sqlalchemy import SQLAlchemy
from contextlib import closing from flask.ext.admin import Admin, BaseView, expose
from flask.ext.admin.contrib.sqlamodel import ModelView
from sqlalchemy.exc import IntegrityError
from flask.ext.security import Security, SQLAlchemyUserDatastore, \
UserMixin, RoleMixin, login_required
from wtforms import Form, BooleanField, TextField, PasswordField, validators
from flask_mail import Mail
import requests
app = Flask(__name__) app = Flask(__name__)
app.debug = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////var/www/refstack/database.db' app.config['MAILGUN_KEY'] = 'key-7o9l9dupikfpsdvqi0ewot-se8g1hz64'
app.config['MAILGUN_DOMAIN'] = 'hastwoparents.com'
app.config['SECRET_KEY'] = 'GIANT_UGLY-SECRET-GOES-H3r3'
db_path = os.path.abspath(os.path.join(os.path.basename(__file__), "../"))
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', 'sqlite:///%s/refstack.db' % (db_path))
app.config['DEBUG'] = True
app.config['SECURITY_PASSWORD_HASH'] = 'sha512_crypt'
app.config['SECURITY_PASSWORD_SALT'] = app.config['SECRET_KEY']
app.config['SECURITY_POST_LOGIN_VIEW'] = 'dashboard'
app.config['SECURITY_RECOVERABLE'] = True
app.config['SECURITY_REGISTERABLE'] = True
app.config['SECURITY_EMAIL_SENDER'] = "admin@hastwoparents.com"
app.config['MAIL_SERVER'] = 'smtp.mailgun.org'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = 'postmaster@hastwoparents.com'
app.config['MAIL_PASSWORD'] = '0sx00qlvqbo3'
mail = Mail(app)
db = SQLAlchemy(app) db = SQLAlchemy(app)
class Vendor(db.Model): class Vendor(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
vendor_name = db.Column(db.String(80), unique=True) vendor_name = db.Column(db.String(80), unique=True)
contact_email = db.Column(db.String(120), unique=True) contact_email = db.Column(db.String(120), unique=True)
def __init__(self, vendor_name, contact_email):
self.vendor_name = vendor_name
self.contact_email = contact_email
def __repr__(self): def __repr__(self):
return '<Vendor %r>' % self.vendor_name return '<Vendor %r>' % self.vendor_name
@ -51,7 +77,17 @@ class Cloud(db.Model):
return '<Cloud %r>' % self.endpoint return '<Cloud %r>' % self.endpoint
admin = Admin(app)
admin.add_view(ModelView(Vendor, db.session))
@app.route('/', methods=['POST','GET']) @app.route('/', methods=['POST','GET'])
def index(): def index():
vendors = Vendor.query.all() vendors = Vendor.query.all()
return render_template('index.html', vendors = vendors) return render_template('index.html', vendors = vendors)
if __name__ == '__main__':
app.logger.setLevel('DEBUG')
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port, debug=True)