use application factory, WIP

This commit is contained in:
Matthew Scragg 2014-10-21 16:06:27 -05:00
parent e6bc4928c9
commit 38e5ef85c0
17 changed files with 200 additions and 120 deletions

View file

@ -1,6 +1,7 @@
import click
from realms.lib.util import random_string
from realms.modules.auth.models import User
from realms.lib.util import green, red, yellow
@click.group()
@ -21,15 +22,15 @@ def create_user(username, email, password):
password = random_string(12)
if User.get_by_username(username):
click.secho("Username %s already exists" % username, fg='red')
red("Username %s already exists" % username)
return
if User.get_by_email(email):
click.secho("Email %s already exists" % email, fg='red')
red("Email %s already exists" % email)
return
User.create(username, email, password)
click.secho("User %s created" % username, fg='green')
green("User %s created" % username)
if show_pass:
click.secho("Password: %s" % password, fg='yellow')
yellow("Password: %s" % password)

View file

@ -1,6 +1,5 @@
from flask_wtf import Form, RecaptchaField
from flask_wtf import Form
from wtforms import StringField, PasswordField, validators
from realms import app
class RegistrationForm(Form):
@ -12,9 +11,6 @@ class RegistrationForm(Form):
])
confirm = PasswordField('Repeat Password')
if app.config['RECAPTCHA_ENABLE']:
setattr(RegistrationForm, 'recaptcha', RecaptchaField("You Human?"))
class LoginForm(Form):
email = StringField('Email', [validators.DataRequired()])

View file

@ -0,0 +1,8 @@
from flask import current_app
from flask_wtf import RecaptchaField
from .forms import RegistrationForm
def before_first_request():
if current_app.config['RECAPTCHA_ENABLE']:
setattr(RegistrationForm, 'recaptcha', RecaptchaField("You Human?"))

View file

@ -1,5 +1,6 @@
from flask import current_app
from flask.ext.login import UserMixin, logout_user, login_user, AnonymousUserMixin
from realms import config, login_manager, db
from realms import login_manager, db
from realms.lib.model import Model
from realms.lib.util import gravatar_url
from itsdangerous import URLSafeSerializer, BadSignature
@ -15,7 +16,7 @@ def load_user(user_id):
@login_manager.token_loader
def load_token(token):
# Load unsafe because payload is needed for sig
sig_okay, payload = URLSafeSerializer(config.SECRET_KEY).loads_unsafe(token)
sig_okay, payload = URLSafeSerializer(current_app.config['SECRET_KEY']).loads_unsafe(token)
if not payload:
return None
@ -81,7 +82,7 @@ class User(Model, UserMixin):
"""
Signed with app secret salted with sha256 of password hash of user (client secret)
"""
return URLSafeSerializer(config.SECRET_KEY + salt)
return URLSafeSerializer(current_app.config['SECRET_KEY'] + salt)
@staticmethod
def auth(email, password):

View file

@ -1,16 +1,15 @@
from flask import g, render_template, request, redirect, Blueprint, flash, url_for
from flask import current_app, render_template, request, redirect, Blueprint, flash, url_for
from realms.modules.auth.models import User
from realms.modules.auth.forms import LoginForm, RegistrationForm
from realms import app
blueprint = Blueprint('auth', __name__, url_prefix=app.config['RELATIVE_PATH'])
blueprint = Blueprint('auth', __name__)
@blueprint.route("/logout")
def logout_page():
User.logout()
flash("You are now logged out")
return redirect(url_for(app.config['ROOT_ENDPOINT']))
return redirect(url_for(current_app.config['ROOT_ENDPOINT']))
@blueprint.route("/login", methods=['GET', 'POST'])
@ -23,7 +22,7 @@ def login():
return redirect(url_for('auth.login'))
if User.auth(request.form['email'], request.form['password']):
return redirect(request.args.get("next") or url_for(app.config['ROOT_ENDPOINT']))
return redirect(request.args.get("next") or url_for(current_app.config['ROOT_ENDPOINT']))
else:
flash('Email or Password Incorrect', 'warning')
return redirect(url_for('auth.login'))
@ -34,9 +33,9 @@ def login():
@blueprint.route("/register", methods=['GET', 'POST'])
def register():
if not app.config['REGISTRATION_ENABLED']:
if not current_app.config['REGISTRATION_ENABLED']:
flash("Registration is disabled")
return redirect(url_for(app.config['ROOT_ENDPOINT']))
return redirect(url_for(current_app.config['ROOT_ENDPOINT']))
form = RegistrationForm()
@ -57,7 +56,7 @@ def register():
User.create(request.form['username'], request.form['email'], request.form['password'])
User.auth(request.form['email'], request.form['password'])
return redirect(request.args.get("next") or url_for(app.config['ROOT_ENDPOINT']))
return redirect(request.args.get("next") or url_for(current_app.config['ROOT_ENDPOINT']))
return render_template("auth/register.html", form=form)

View file

@ -1,13 +1,14 @@
import os
import sys
from realms import app
from realms.modules.wiki.models import Wiki
# Init Wiki
Wiki(app.config['WIKI_PATH'])
# Check paths
for mode in [os.W_OK, os.R_OK]:
for dir_ in [app.config['WIKI_PATH'], os.path.join(app.config['WIKI_PATH'], '.git')]:
if not os.access(dir_, mode):
sys.exit('Read and write access to WIKI_PATH is required (%s)' % dir_)
def init(app):
# Init Wiki
Wiki(app.config['WIKI_PATH'])
# Check paths
for mode in [os.W_OK, os.R_OK]:
for dir_ in [app.config['WIKI_PATH'], os.path.join(app.config['WIKI_PATH'], '.git')]:
if not os.access(dir_, mode):
sys.exit('Read and write access to WIKI_PATH is required (%s)' % dir_)

View file

@ -0,0 +1,6 @@
from flask import g, current_app
from .models import Wiki
def before_request():
g.current_wiki = Wiki(current_app.config['WIKI_PATH'])

View file

@ -62,6 +62,15 @@ class Wiki(HookMixin):
def __repr__(self):
return "Wiki: %s" % self.path
def _get_user(self, username, email):
if not username:
username = self.default_committer_name
if not email:
email = self.default_committer_email
return username, email
def revert_page(self, name, commit_sha, message, username):
"""Revert page to passed commit sha1
@ -108,11 +117,7 @@ class Wiki(HookMixin):
if not message:
message = "Updated %s" % name
if not username:
username = self.default_committer_name
if not email:
email = self.default_committer_email
username, email = self._get_user(username, email)
ret = self.gittle.commit(name=username,
email=email,
@ -168,12 +173,13 @@ class Wiki(HookMixin):
content = re.sub(r"```(.*?)```", unescape_repl, content, flags=re.DOTALL)
return content
def rename_page(self, old_name, new_name, user=None):
def rename_page(self, old_name, new_name, username=None, email=None, message=None):
"""Rename page.
:param old_name: Page that will be renamed.
:param new_name: New name of page.
:param user: User object if any.
:param username: Committer name
:param email: Committer email
:return: str -- Commit sha1
"""
@ -186,32 +192,45 @@ class Wiki(HookMixin):
# file is being overwritten, but that is ok, it's git!
pass
username, email = self._get_user(username, email)
if not message:
message = "Moved %s to %s" % (old_name, new_name)
os.rename(os.path.join(self.path, old_filename), os.path.join(self.path, new_filename))
self.gittle.add(new_filename)
self.gittle.rm(old_filename)
commit = self.gittle.commit(name=getattr(user, 'username', self.default_committer_name),
email=getattr(user, 'email', self.default_committer_email),
message="Moved %s to %s" % (old_name, new_name),
commit = self.gittle.commit(name=username,
email=email,
message=message,
files=[old_filename, new_filename])
cache.delete_many(old_filename, new_filename)
cache.delete_many(old_name, new_name)
return commit
def delete_page(self, name, user=None):
def delete_page(self, name, username=None, email=None, message=None):
"""Delete page.
:param name: Page that will be deleted
:param user: User object if any
:param username: Committer name
:param email: Committer email
:return: str -- Commit sha1
"""
self.gittle.rm(name)
commit = self.gittle.commit(name=getattr(user, 'username', self.default_committer_name),
email=getattr(user, 'email', self.default_committer_email),
message="Deleted %s" % name,
files=[name])
username, email = self._get_user(username, email)
if not message:
message = "Deleted %s" % name
filename = cname_to_filename(name)
self.gittle.rm(filename)
commit = self.gittle.commit(name=username,
email=email,
message=message,
files=[str(filename)])
cache.delete_many(name)
return commit

View file

@ -1,15 +1,10 @@
from nose.tools import *
from flask import url_for
from realms import app, g
from realms.modules.wiki.models import Wiki, cname_to_filename, filename_to_cname
from flask.ext.testing import TestCase
from realms.lib.test import BaseTest
class WikiTest(TestCase):
def create_app(self):
app.config['TESTING'] = True
return app
class WikiTest(BaseTest):
def test_wiki_routes(self):
@ -22,7 +17,17 @@ class WikiTest(TestCase):
"""
def test_write_page(self):
pass
self.assert_200(
self.client.post(url_for('wiki.page_write', name='test'), data=dict(
content='testing',
message='test message'
)))
self.assert_200(self.client.get(url_for('wiki.page', name='test')))
def test_delete_page(self):
self.assert_200(self.client.delete(url_for('wiki.page_write', name='test')))
self.assert_status(self.client.get(url_for('wiki.page', name='test')), 302)
def test_revert(self):
pass

View file

@ -1,15 +1,9 @@
from flask import abort, g, render_template, request, redirect, Blueprint, flash, url_for, current_app
from flask.ext.login import login_required
from flask.ext.login import login_required, current_user
from realms.lib.util import to_canonical, remove_ext
from realms.modules.wiki.models import Wiki
from realms import current_user, app
blueprint = Blueprint('wiki', __name__, url_prefix=app.config['RELATIVE_PATH'])
@app.before_request
def init_wiki():
g.current_wiki = Wiki(app.config['WIKI_PATH'])
blueprint = Blueprint('wiki', __name__)
@blueprint.route("/_commit/<sha>/<name>")
@ -27,7 +21,8 @@ def commit(name, sha):
@blueprint.route("/_compare/<name>/<regex('[^.]+'):fsha><regex('\.{2,3}'):dots><regex('.+'):lsha>")
def compare(name, fsha, dots, lsha):
diff = g.current_wiki.compare(name, fsha, lsha)
return render_template('wiki/compare.html', name=name, diff=diff, old=fsha, new=lsha)
return render_template('wiki/compare.html',
name=name, diff=diff, old=fsha, new=lsha)
@blueprint.route("/_revert", methods=['POST'])
@ -38,11 +33,14 @@ def revert():
cname = to_canonical(name)
message = request.form.get('message', "Reverting %s" % cname)
if cname in app.config.get('WIKI_LOCKED_PAGES'):
if cname in current_app.config.get('WIKI_LOCKED_PAGES'):
return dict(error=True, message="Page is locked")
sha = g.current_wiki.revert_page(name, commit, message=message,
username=current_user.username)
sha = g.current_wiki.revert_page(name,
commit,
message=message,
username=current_user.username,
email=current_user.email)
if sha:
flash("Page reverted")
@ -101,23 +99,24 @@ def page_write(name):
cname = to_canonical(name)
if not cname:
return dict(error=True, message="Invalid name")
return dict(error=True, message="Invalid name")
if request.method == 'POST':
# Create
if cname in app.config.get('WIKI_LOCKED_PAGES'):
if cname in current_app.config.get('WIKI_LOCKED_PAGES'):
return dict(error=True, message="Page is locked")
sha = g.current_wiki.write_page(cname,
request.form['content'],
message=request.form['message'],
create=True,
username=current_user.username)
username=current_user.username,
email=current_user.email)
elif request.method == 'PUT':
edit_cname = to_canonical(request.form['name'])
if edit_cname in app.config.get('WIKI_LOCKED_PAGES'):
if edit_cname in current_app.config.get('WIKI_LOCKED_PAGES'):
return dict(error=True, message="Page is locked")
if edit_cname != cname.lower():
@ -126,13 +125,16 @@ def page_write(name):
sha = g.current_wiki.write_page(edit_cname,
request.form['content'],
message=request.form['message'],
username=current_user.username)
username=current_user.username,
email=current_user.email)
return dict(sha=sha)
else:
# DELETE
sha = g.current_wiki.delete_page(name, user=current_user)
sha = g.current_wiki.delete_page(name,
username=current_user.username,
email=current_user.email)
return dict(sha=sha)