From aaa1415b57eaf03f9e8cc50f33153edfead975de Mon Sep 17 00:00:00 2001 From: Roy Hyunjin Han Date: Tue, 16 Nov 2010 16:29:17 -0500 Subject: [PATCH] Updated georegistry to latest pylons-authentication --- .gitignore | 6 +- default.cfg | 13 -- development.ini | 16 ++- ez_setup.py | 40 +----- georegistry/config/deployment.ini_tmpl | 47 +++++++ georegistry/config/environment.py | 31 +--- georegistry/config/routing.py | 3 + georegistry/controllers/__init__.py | 50 +++++++ georegistry/controllers/people.py | 164 ++++++++++------------ georegistry/lib/base.py | 6 +- georegistry/lib/helpers.py | 3 + georegistry/lib/store.py | 11 -- georegistry/model/__init__.py | 2 +- georegistry/templates/base.mako | 2 +- georegistry/templates/people/change.mako | 1 - georegistry/templates/people/confirm.mako | 2 +- georegistry/templates/people/login.mako | 2 +- georegistry/websetup.py | 12 +- production.ini | 53 ------- setup.cfg | 4 - 20 files changed, 219 insertions(+), 249 deletions(-) delete mode 100644 default.cfg create mode 100644 georegistry/config/deployment.ini_tmpl delete mode 100644 production.ini diff --git a/.gitignore b/.gitignore index 49c296a..d940607 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -.development.cfg -.production.cfg -*.pyc data +production.ini +*.pyc +*.swp diff --git a/default.cfg b/default.cfg deleted file mode 100644 index 26cf4ff..0000000 --- a/default.cfg +++ /dev/null @@ -1,13 +0,0 @@ -[mail support] -smtp = localhost -email = support@localhost -nickname = Support - -[recaptcha] -public = -private = - -[database] -name = -username = -password = diff --git a/development.ini b/development.ini index 38aaa2c..4c6503c 100644 --- a/development.ini +++ b/development.ini @@ -1,5 +1,16 @@ +# +# georegistry - Pylons development environment configuration +# +# The %(here)s variable will be replaced with the parent directory of this file +# [DEFAULT] debug = true +email_to = +error_email_from = support@example.com +smtp_server = localhost +# smtp_username = +# smtp_password = +# smtp_use_tls = True [server:main] use = egg:Paste#http @@ -13,8 +24,9 @@ static_files = true cache_dir = %(here)s/data beaker.session.key = georegistry beaker.session.secret = somesecret -sqlalchemy.url = postgresql://${username}:${password}@localhost/${name} -safe_path = %(here)s/.development.cfg +sqlalchemy.url = sqlite:///%(here)s/development.db +# recaptcha.public = +# recaptcha.private = [loggers] keys = root, routes, georegistry, sqlalchemy diff --git a/ez_setup.py b/ez_setup.py index df8991c..d6bc76c 100644 --- a/ez_setup.py +++ b/ez_setup.py @@ -17,6 +17,7 @@ DEFAULT_VERSION = "0.6c9" DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] + md5_data = { 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', @@ -54,10 +55,12 @@ 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a', } + import sys, os try: from hashlib import md5 except ImportError: from md5 import md5 + def _validate_md5(egg_name, data): if egg_name in md5_data: digest = md5(data).hexdigest() @@ -69,6 +72,7 @@ def _validate_md5(egg_name, data): sys.exit(2) return data + def use_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, download_delay=15 @@ -110,6 +114,7 @@ def do_download(): except pkg_resources.DistributionNotFound: return do_download() + def download_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, delay = 15 @@ -158,40 +163,6 @@ def download_setuptools( return os.path.realpath(saveto) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def main(argv, version=DEFAULT_VERSION): """Install or upgrade setuptools and EasyInstall""" try: @@ -233,6 +204,7 @@ def main(argv, version=DEFAULT_VERSION): print "Setuptools version",version,"or greater has been installed." print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' + def update_md5(filenames): """Update our built-in md5 registry""" diff --git a/georegistry/config/deployment.ini_tmpl b/georegistry/config/deployment.ini_tmpl new file mode 100644 index 0000000..a6a61be --- /dev/null +++ b/georegistry/config/deployment.ini_tmpl @@ -0,0 +1,47 @@ +# +# georegistry - Pylons configuration +# +# The %(here)s variable will be replaced with the parent directory of this file +# +[DEFAULT] +debug = false +email_to = +error_email_from = support@example.com +smtp_server = localhost +# smtp_username = +# smtp_password = +# smtp_use_tls = True + +[server:main] +use = egg:Paste#http +host = 0.0.0.0 +port = 5000 + +[app:main] +use = egg:georegistry +full_stack = true +static_files = true +cache_dir = %(here)s/data +app_instance_uuid = ${app_instance_uuid} +beaker.session.key = georegistry +beaker.session.secret = ${app_instance_secret} +sqlalchemy.url = sqlite:///production.db +# recaptcha.public = +# recaptcha.private = + +[loggers] +keys = root +[handlers] +keys = console +[formatters] +keys = generic +[logger_root] +level = WARN +handlers = console +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s diff --git a/georegistry/config/environment.py b/georegistry/config/environment.py index 5b98f10..5455a5c 100644 --- a/georegistry/config/environment.py +++ b/georegistry/config/environment.py @@ -5,10 +5,9 @@ from mako.lookup import TemplateLookup # Import system modules import os -import ConfigParser from sqlalchemy import engine_from_config # Import custom modules -from georegistry.lib import app_globals, helpers, store +from georegistry.lib import app_globals, helpers from georegistry.config.routing import make_map from georegistry.model import init_model @@ -38,36 +37,8 @@ def load_environment(global_conf, app_conf): module_directory=os.path.join(app_conf['cache_dir'], 'templates'), input_encoding='utf-8', default_filters=['escape'], imports=['from webhelpers.html import escape']) - # Load safe - config['safe'] = loadSafe(config['safe_path']) - config['sqlalchemy.url'] = patchSQLAlchemyURL(config['sqlalchemy.url'], config['safe']) # Setup the SQLAlchemy database engine engine = engine_from_config(config, 'sqlalchemy.') init_model(engine) # Return return config - - -def loadSafe(safePath): - 'Load information that we do not want to include in the repository' - # Validate - if not os.path.exists(safePath): - print 'Missing configuration: ' + safePath - safePath = store.expandBasePath('default.cfg') - # Initialize - valueByName = {} - # Load - configuration = ConfigParser.ConfigParser() - configuration.read(safePath) - for sectionName in configuration.sections(): - valueByName[sectionName] = dict(configuration.items(sectionName)) - # Return - return valueByName - - -def patchSQLAlchemyURL(sqlalchemyURL, safe): - 'Apply sensitive credentials' - # Define - getDBParameter = lambda x: safe['database'][x] - # Return - return sqlalchemyURL.replace('${username}', getDBParameter('username')).replace('${password}', getDBParameter('password')).replace('${name}', getDBParameter('name')) diff --git a/georegistry/config/routing.py b/georegistry/config/routing.py index ceb624c..9c73746 100644 --- a/georegistry/config/routing.py +++ b/georegistry/config/routing.py @@ -2,6 +2,7 @@ # Import pylons modules from routes import Mapper + def make_map(config): 'Create, configure and return the routes mapper' # Initialize map @@ -31,5 +32,7 @@ def make_map(config): map.connect('region_index', '/regions.:(responseFormat)', controller='regions', action='index') map.connect('region_show', '/regions/:(countryCode).:(responseFormat)', controller='regions', action='show') map.connect('region_show_plain', '/regions/:(countryCode)', controller='regions', action='show') + # Redirect index + map.redirect('/', '/regions') # Return return map diff --git a/georegistry/controllers/__init__.py b/georegistry/controllers/__init__.py index e69de29..ff3579a 100644 --- a/georegistry/controllers/__init__.py +++ b/georegistry/controllers/__init__.py @@ -0,0 +1,50 @@ +'General decorators' +# Import pylons modules +from pylons import request, url +from pylons.controllers.util import redirect +# Import system modules +from decorator import decorator +# Import custom modules +from georegistry.lib import helpers as h + + +# Authentication + +@decorator +def requireLogin(func, *args, **kwargs): + 'Redirect to login if the user is not logged in' + # If the user is not logged in, + if not h.isPerson(): + return redirect(url('person_login', targetURL=h.encodeURL(request.path))) + # Execute + return func(*args, **kwargs) + +@decorator +def requireLoginJSON(func, *args, **kwargs): + 'Give error message if the user is not logged in' + # If the user is not logged in, + if not h.isPerson(): + return dict(isOk=0, message='Login required') + # Execute + return func(*args, **kwargs) + + +# Authorization + +@decorator +def requireSuper(func, *args, **kwargs): + 'Redirect to homepage if the user is not a superuser' + # If the user is not a superuser, + if not h.isPersonSuper(): + return redirect(url('person_login', targetURL=h.encodeURL('/'))) + # Execute + return func(*args, **kwargs) + +@decorator +def requireSuperJSON(func, *args, **kwargs): + 'Give error message if the user is not a superuser' + # If the user is not a superuser, + if not h.isPersonSuper(): + return dict(isOk=0, message='Access denied') + # Execute + return func(*args, **kwargs) diff --git a/georegistry/controllers/people.py b/georegistry/controllers/people.py index f669995..5d35142 100644 --- a/georegistry/controllers/people.py +++ b/georegistry/controllers/people.py @@ -7,12 +7,13 @@ # Import system modules import recaptcha.client.captcha as captcha import cStringIO as StringIO +import sqlalchemy as sa import datetime # Import custom modules from georegistry import model from georegistry.model import Session from georegistry.config import parameter -from georegistry.lib import smtp, store, helpers as h +from georegistry.lib import helpers as h, store, smtp from georegistry.lib.base import BaseController, render @@ -32,7 +33,7 @@ def register(self): @jsonify def register_(self): 'Store proposed changes and send confirmation email' - return changeAccount(dict(request.POST), 'registration', '/people/confirm.mako') + return changePerson(dict(request.POST), 'registration', '/people/confirm.mako') def confirm(self, ticket): 'Confirm changes' @@ -76,13 +77,13 @@ def update_(self): # Prepare person = Session.query(model.Person).get(personID) # Return - return changeAccount(dict(request.POST), 'update', '/people/confirm.mako', person) + return changePerson(dict(request.POST), 'update', '/people/confirm.mako', person) def login(self, targetURL=h.encodeURL('/')): 'Show login form' c.messageCode = request.GET.get('messageCode') c.targetURL = h.decodeURL(targetURL) - c.publicKey = config['safe']['recaptcha']['public'] + c.recaptchaPublicKey = config.get('recaptcha.public', '') return render('/people/login.mako') @jsonify @@ -107,9 +108,9 @@ def login_(self): # Expect recaptcha response recaptchaChallenge = request.POST.get('recaptcha_challenge_field', '') recaptchaResponse = request.POST.get('recaptcha_response_field', '') - recaptchaKey = config['safe']['recaptcha']['private'] + recaptchaPrivateKey = config.get('recaptcha.private', '') # Validate - result = captcha.submit(recaptchaChallenge, recaptchaResponse, recaptchaKey, h.getRemoteIP()) + result = captcha.submit(recaptchaChallenge, recaptchaResponse, recaptchaPrivateKey, h.getRemoteIP()) # If the response is not valid, if not result.is_valid: return dict(isOk=0, rejection_count=person.rejection_count) @@ -119,6 +120,7 @@ def login_(self): session['minutesOffset'] = minutesOffset session['personID'] = person.id session['nickname'] = person.nickname + session['is_super'] = person.is_super session.save() # Save person person.minutes_offset = minutesOffset @@ -134,6 +136,7 @@ def logout(self, targetURL=h.encodeURL('/')): del session['minutesOffset'] del session['personID'] del session['nickname'] + del session['is_super'] session.save() # Redirect return redirect(url(h.decodeURL(targetURL))) @@ -150,13 +153,70 @@ def reset(self): return dict(isOk=0) # Reset account c.password = store.makeRandomAlphaNumericString(parameter.PASSWORD_LENGTH_AVERAGE) - return changeAccount(dict( - username=person.username, - password=c.password, - nickname=person.nickname, - email=person.email, - email_sms=person.email_sms, - ), 'reset', '/people/confirm.mako', person) + return changePerson(dict(username=person.username, password=c.password, nickname=person.nickname, email=person.email, email_sms=person.email_sms), 'reset', '/people/confirm.mako', person) + + +# Helpers + +def changePerson(valueByName, action, templatePath, person=None): + 'Validate values and send confirmation email if values are okay' + # Validate form + try: + form = PersonForm().to_python(valueByName, person) + except formencode.Invalid, error: + return dict(isOk=0, errorByID=error.unpack_errors()) + # Prepare candidate + candidate = model.PersonCandidate(form['username'], model.hashString(form['password']), form['nickname'], form['email'], form['email_sms']) + candidate.person_id = person.id if person else None + candidate.ticket = store.makeRandomUniqueTicket(parameter.TICKET_LENGTH, Session.query(model.PersonCandidate)) + candidate.when_expired = datetime.datetime.utcnow() + datetime.timedelta(days=parameter.TICKET_LIFESPAN_IN_DAYS) + Session.add(candidate) + Session.commit() + # Send confirmation + toByValue = dict(nickname=form['nickname'], email=form['email']) + subject = '[%s] Confirm %s' % (parameter.SITE_NAME, action) + c.candidate = candidate + c.username = form['username'] + c.action = action + body = render(templatePath) + try: + smtp.sendMessage(dict(email=config['error_email_from'], smtp=config['smtp_server'], username=config.get('smtp_username', ''), password=config.get('smtp_password', ''), nickname=parameter.SITE_NAME + ' Support'), toByValue, subject, body) + except smtp.SMTPError: + return dict(isOk=0, errorByID={'status': 'Unable to send confirmation; please try again later.'}) + # Return + return dict(isOk=1) + +def confirmPersonCandidate(ticket): + 'Move changes from the PersonCandidate table into the Person table' + # Initialize + matchedCandidateFilter = model.PersonCandidate.ticket==ticket + expiredCandidateFilter = model.PersonCandidate.when_expired < datetime.datetime.utcnow() + candidate = Session.query(model.PersonCandidate).filter(matchedCandidateFilter & sa.not_(expiredCandidateFilter)).first() + # If the ticket exists, + if candidate: + # Prepare + similarCandidateFilter = (model.PersonCandidate.username == candidate.username) | (model.PersonCandidate.nickname == candidate.nickname) | (model.PersonCandidate.email == candidate.email) + # Delete expired or similar candidates + Session.query(model.PersonCandidate).filter(expiredCandidateFilter | similarCandidateFilter).delete() + # If the person exists, + if candidate.person_id: + # Update + person = Session.query(model.Person).get(candidate.person_id) + person.username = candidate.username + person.password_hash = candidate.password_hash + person.nickname = candidate.nickname + person.email = candidate.email + person.email_sms = candidate.email_sms + # Reset + person.rejection_count = 0 + # If the person does not exist, + else: + # Add person + Session.add(model.Person(candidate.username, candidate.password_hash, candidate.nickname, candidate.email, candidate.email_sms)) + # Commit + Session.commit() + # Return + return candidate # Validators @@ -181,7 +241,6 @@ def _to_python(self, value, person): # Return return value - class SecurePassword(formencode.validators.FancyValidator): 'Validator to prevent weak passwords' @@ -191,9 +250,8 @@ def _to_python(self, value, person): raise formencode.Invalid('That password needs more variety', value, person) return value - class PersonForm(formencode.Schema): - 'Validate user credentials' + 'Validate person credentials' username = formencode.All( formencode.validators.String( @@ -221,76 +279,4 @@ class PersonForm(formencode.Schema): formencode.validators.Email(not_empty=True), Unique('email', 'That email is reserved for another account'), ) - email_sms = formencode.All( - formencode.validators.Email(), - Unique('email_sms', 'That SMS address is reserved for another account'), - ) - - -# Helpers - -def changeAccount(valueByName, action, templatePath, person=None): - 'Validate values and send confirmation email if values are okay' - try: - # Validate form - form = PersonForm().to_python(valueByName, person) - except formencode.Invalid, error: - return dict(isOk=0, errorByID=error.unpack_errors()) - else: - # Purge expired candidates - purgeExpiredPersonCandidates() - # Prepare candidate - candidate = model.PersonCandidate(form['username'], model.hashString(form['password']), form['nickname'], form['email'], form['email_sms']) - candidate.person_id = person.id if person else None - candidate.ticket = store.makeRandomUniqueTicket(parameter.TICKET_LENGTH, Session.query(model.PersonCandidate)) - candidate.when_expired = datetime.datetime.utcnow() + datetime.timedelta(days=parameter.TICKET_LIFESPAN_IN_DAYS) - Session.add(candidate) - Session.commit() - # Prepare recipient - toByValue = dict(nickname=form['nickname'], email=form['email']) - # Prepare subject - subject = '[%s] Confirm %s' % (parameter.SITE_NAME, action) - # Prepare body - c.candidate = candidate - c.username = form['username'] - c.action = action - body = render(templatePath) - # Send - try: - smtp.sendMessage(config['safe']['mail support'], toByValue, subject, body) - except smtp.SMTPError: - return dict(isOk=0, errorByID={'status': 'Unable to send confirmation; please try again later.'}) - # Return - return dict(isOk=1) - -def purgeExpiredPersonCandidates(): - 'Delete candidates that have expired' - Session.execute(model.person_candidates_table.delete().where(model.PersonCandidate.when_expired=datetime.datetime.utcnow()).first() - # If the ticket exists, - if candidate: - # If the person exists, - if candidate.person_id: - # Update person - person = Session.query(model.Person).get(candidate.person_id) - person.username = candidate.username - person.password_hash = candidate.password_hash - person.nickname = candidate.nickname - person.email = candidate.email - person.email_sms = candidate.email_sms - # Reset rejection_count - person.rejection_count = 0 - # If the person does not exist, - else: - # Add person - Session.add(model.Person(candidate.username, candidate.password_hash, candidate.nickname, candidate.email, candidate.email_sms)) - # Delete ticket - Session.delete(candidate) - # Commit - Session.commit() - # Return - return candidate + email_sms = formencode.validators.Email() diff --git a/georegistry/lib/base.py b/georegistry/lib/base.py index e7081ff..8cea8b6 100644 --- a/georegistry/lib/base.py +++ b/georegistry/lib/base.py @@ -1,13 +1,11 @@ -"""The base Controller API - -Provides the BaseController class for subclassing. -""" +'Base Controller API' # Import pylons modules from pylons.controllers import WSGIController from pylons.templating import render_mako as render # Import custom modules from georegistry.model.meta import Session + class BaseController(WSGIController): def __call__(self, environ, start_response): diff --git a/georegistry/lib/helpers.py b/georegistry/lib/helpers.py index a9544d2..b7d1c94 100644 --- a/georegistry/lib/helpers.py +++ b/georegistry/lib/helpers.py @@ -19,6 +19,9 @@ def decodeURL(x): def isPerson(): return 1 if 'personID' in session else 0 +def isPersonSuper(): + return 1 if session.get('is_super', False) else 0 + def getPersonID(): return session.get('personID', 0) diff --git a/georegistry/lib/store.py b/georegistry/lib/store.py index a2da8c1..2147bb1 100644 --- a/georegistry/lib/store.py +++ b/georegistry/lib/store.py @@ -2,8 +2,6 @@ # Import system modules import os import random -import cPickle as pickle -import cStringIO as StringIO # File @@ -85,12 +83,3 @@ def reduceSets(packs, itemName): return set() items = [x[itemName] for x in packs] return reduce(lambda x, y: x.union(y), items) - - -# Pickle - -def setPickle(x): - return pickle.dumps(x, protocol=2) - -def getPickle(pickled_x): - return pickle.load(StringIO.StringIO(pickled_x)) diff --git a/georegistry/model/__init__.py b/georegistry/model/__init__.py index ea1cdb7..15bafaa 100644 --- a/georegistry/model/__init__.py +++ b/georegistry/model/__init__.py @@ -33,7 +33,7 @@ def hashString(string): sa.Column('email_sms', sa.String(parameter.EMAIL_LENGTH_MAXIMUM)), sa.Column('minutes_offset', sa.Integer, default=0), sa.Column('rejection_count', sa.Integer, default=0), - sa.Column('pickled', sa.LargeBinary), + sa.Column('is_super', sa.Boolean, default=False), ) person_candidates_table = sa.Table('person_candidates', Base.metadata, sa.Column('id', sa.Integer, primary_key=True), diff --git a/georegistry/templates/base.mako b/georegistry/templates/base.mako index 194a251..bf123ec 100644 --- a/georegistry/templates/base.mako +++ b/georegistry/templates/base.mako @@ -20,8 +20,8 @@ $(document).ready(function() { function () {this.className = this.className.replace('OFF', 'ON');}, function () {this.className = this.className.replace('ON', 'OFF');} ); - function getID(obj) {return /\d+/.exec(obj.id)[0]} function getNumber(x) {return /\d+/.exec(x)[0]} + function getID(obj) {return getNumber(obj.id)} ${self.js()}\ }); diff --git a/georegistry/templates/people/change.mako b/georegistry/templates/people/change.mako index 0a4f41f..66e3490 100644 --- a/georegistry/templates/people/change.mako +++ b/georegistry/templates/people/change.mako @@ -71,7 +71,6 @@ $('#username').focus(); ${'Register for an account' if c.isNew else 'Update your account'} - diff --git a/georegistry/templates/people/confirm.mako b/georegistry/templates/people/confirm.mako index 38634cb..683e3b5 100644 --- a/georegistry/templates/people/confirm.mako +++ b/georegistry/templates/people/confirm.mako @@ -8,4 +8,4 @@ Password: ${c.password} Please click on the link below to complete your ${c.action}. ${request.relative_url(h.url('person_confirm', ticket=c.candidate.ticket), to_application=True)} -This ticket expires on ${c.candidate.when_expired.strftime('%A, %B %d, %Y at %H:%M%p')}. +This ticket expires on ${c.candidate.when_expired.strftime('%A, %B %d, %Y at %I:%M%p')}. diff --git a/georegistry/templates/people/login.mako b/georegistry/templates/people/login.mako index d6db98c..0702ceb 100644 --- a/georegistry/templates/people/login.mako +++ b/georegistry/templates/people/login.mako @@ -47,7 +47,7 @@ function ajax_login() { rejection_count = data.rejection_count ? data.rejection_count : rejection_count + 1; // If there have been too many rejections, if (rejection_count >= ${h.REJECTION_LIMIT}) { - Recaptcha.create("${c.publicKey}", 'recaptcha', { + Recaptcha.create("${c.recaptchaPublicKey}", 'recaptcha', { theme: 'red', callback: Recaptcha.focus_response_field }); diff --git a/georegistry/websetup.py b/georegistry/websetup.py index 648825c..98c351c 100644 --- a/georegistry/websetup.py +++ b/georegistry/websetup.py @@ -3,9 +3,11 @@ import pylons.test # Import system modules import logging; log = logging.getLogger(__name__) +import getpass # Import custom modules -from georegistry.config.environment import load_environment +from georegistry import model from georegistry.model.meta import Session, Base +from georegistry.config.environment import load_environment def setup_app(command, conf, vars): @@ -15,3 +17,11 @@ def setup_app(command, conf, vars): load_environment(conf.global_conf, conf.local_conf) # Create the tables if they don't already exist Base.metadata.create_all(bind=Session.bind) + # If users do not exist, + if not Session.query(model.Person).all(): + print 'Please create an administrator account.' + # Create admin + person = model.Person(raw_input('Username (admin): ') or 'admin', model.hashString(getpass.getpass('Password (admin): ') or 'admin'), raw_input('Nickname (Administrator): ') or u'Administrator', raw_input('Email (support@invisibleroads.com): ') or 'support@invisibleroads.com', raw_input('SMS: ')) + person.is_super = True + Session.add(person) + Session.commit() diff --git a/production.ini b/production.ini deleted file mode 100644 index 905c51c..0000000 --- a/production.ini +++ /dev/null @@ -1,53 +0,0 @@ -[DEFAULT] -debug = false -email_to = -error_email_from = -smtp_server = -smtp_username = -smtp_password = -smtp_use_tls = - -[server:main] -use = egg:Paste#http -host = 127.0.0.1 -port = 5000 - -[app:main] -use = egg:georegistry -full_stack = true -static_files = true -cache_dir = %(here)s/data -beaker.session.key = georegistry -beaker.session.secret = somesecret -sqlalchemy.url = postgresql://${username}:${password}@localhost/${name} -safe_path = %(here)s/.production.cfg - -[loggers] -keys = root, routes, georegistry, sqlalchemy -[handlers] -keys = console -[formatters] -keys = generic -[logger_root] -level = WARN -handlers = console -[logger_routes] -level = WARN -handlers = -qualname = routes.middleware -[logger_georegistry] -level = WARN -handlers = -qualname = georegistry -[logger_sqlalchemy] -level = WARN -handlers = -qualname = sqlalchemy.engine -[handler_console] -class = StreamHandler -args = (sys.stderr,) -level = NOTSET -formatter = generic -[formatter_generic] -format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s -datefmt = %H:%M:%S diff --git a/setup.cfg b/setup.cfg index 730057c..0353ac0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,3 @@ -[egg_info] -tag_build = dev -tag_svn_revision = true - [easy_install] find_links = http://www.pylonshq.com/download/