From cba28239a201c3baf6ce24730c561aff82faf785 Mon Sep 17 00:00:00 2001 From: Matthew Scragg Date: Thu, 3 Oct 2013 09:58:07 -0500 Subject: [PATCH] registration and other stuff --- reimagine/__init__.py | 75 ++++++++++++++++++----- reimagine/models.py | 65 +++++++++++++++++++- reimagine/static/css/style.css | 39 +++++++++++- reimagine/templates/account/index.html | 20 ++++++ reimagine/templates/account/login.html | 4 +- reimagine/templates/account/register.html | 2 + reimagine/templates/errors/404.html | 6 ++ reimagine/templates/layout.html | 48 ++++++++++++--- reimagine/templates/page/compare.html | 16 +++++ reimagine/templates/page/edit.html | 8 +-- reimagine/templates/page/history.html | 48 ++++++++++++++- reimagine/templates/page/page.html | 21 ++++--- reimagine/wiki.py | 24 ++++++-- 13 files changed, 326 insertions(+), 50 deletions(-) create mode 100644 reimagine/templates/account/index.html create mode 100644 reimagine/templates/page/compare.html diff --git a/reimagine/__init__.py b/reimagine/__init__.py index 394b320..7e706e7 100644 --- a/reimagine/__init__.py +++ b/reimagine/__init__.py @@ -4,11 +4,12 @@ import time import redis import rethinkdb as rdb -from flask import Flask, request, render_template, url_for, redirect +from flask import Flask, request, render_template, url_for, redirect, flash, session from flask.ext.bcrypt import Bcrypt -from flask.ext.login import LoginManager +from flask.ext.login import LoginManager, login_user, logout_user from flask.ext.assets import Environment from recaptcha.client import captcha +from werkzeug.routing import BaseConverter import config from session import RedisSessionInterface @@ -16,12 +17,18 @@ from wiki import Wiki from util import to_canonical, remove_ext +class RegexConverter(BaseConverter): + def __init__(self, url_map, *items): + super(RegexConverter, self).__init__(url_map) + self.regex = items[0] + app = Flask(__name__) app.config.update(config.flask) app.debug = (config.ENV is not 'PROD') app.secret_key = config.secret_key app.static_path = os.sep + 'static' app.session_interface = RedisSessionInterface() +app.url_map.converters['regex'] = RegexConverter bcrypt = Bcrypt(app) @@ -45,7 +52,13 @@ if not config.db['dbname'] in rdb.db_list().run(conn) and config.ENV is not 'PRO repo_dir = config.repo['dir'] -from models import Site +# This is down here because of dependencies above +from models import Site, User, CurrentUser + + +@login_manager.user_loader +def load_user(user_id): + return CurrentUser(user_id) w = Wiki(repo_dir) @@ -54,6 +67,14 @@ def redirect_url(): return request.args.get('next') or request.referrer or url_for('index') +def validate_captcha(): + response = captcha.submit( + request.form['recaptcha_challenge_field'], + request.form['recaptcha_response_field'], + app.config['RECAPTCHA_PRIVATE_KEY'], + request.remote_addr) + return response.is_valid + @app.template_filter('datetime') def _jinja2_filter_datetime(ts): return time.strftime('%b %d, %Y %I:%M %p', time.localtime(ts)) @@ -72,7 +93,18 @@ def page_error(e): @app.route("/") def root(): - return redirect('/home') + return render('home') + #return redirect('/home') + +@app.route("/account/") +def account(): + return render_template('account/index.html') + +@app.route("/logout/") +def logout(): + logout_user() + del session['user'] + return redirect(url_for('root')) @app.route("/commit//") def commit_sha(name, sha): @@ -85,18 +117,29 @@ def commit_sha(name, sha): return redirect('/create/'+cname) +@app.route("/compare//") +def compare(name, fsha, dots, lsha): + diff = w.compare(name, fsha, lsha) + return render_template('page/compare.html', name=name, diff=diff) + + @app.route("/register", methods=['GET', 'POST']) def register(): if request.method == 'POST': - response = captcha.submit( - request.form['recaptcha_challenge_field'], - request.form['recaptcha_response_field'], - app.config['RECAPTCHA_PRIVATE_KEY'], - request.remote_addr) - if not response.is_valid: - return redirect('/register?fail') - else: - return redirect("/") + user = User() + if user.get_by_email(request.form['email']): + flash('Email is already taken') + return redirect('/register') + if user.get_by_username(request.form['username']): + flash('Username is already taken') + return redirect('/register') + + # Create user and login + u = User.create(email=request.form['email'].lower(), + username=request.form['username'], + password=bcrypt.generate_password_hash(request.form['password'])) + login_user(u) + return redirect("/") else: return render_template('account/register.html') @@ -104,7 +147,11 @@ def register(): @app.route("/login", methods=['GET', 'POST']) def login(): if request.method == 'POST': - pass + if User.auth(request.form['email'], request.form['password']): + return redirect("/") + else: + flash("Email or Password invalid") + return redirect("/login") else: return render_template('account/login.html') diff --git a/reimagine/models.py b/reimagine/models.py index 020ce98..e832a8a 100644 --- a/reimagine/models.py +++ b/reimagine/models.py @@ -1,6 +1,18 @@ +import rethinkdb as rdb +from flask import session +from flask.ext.login import login_user from rethinkORM import RethinkModel +from reimagine import conn, bcrypt -from reimagine import conn + +def to_dict(cur, first=False): + ret = [] + for row in cur: + ret.append(row) + if ret and first: + return ret[0] + else: + return ret class BaseModel(RethinkModel): @@ -14,14 +26,63 @@ class BaseModel(RethinkModel): def create(cls, **kwargs): return super(BaseModel, cls).create(**kwargs) + def get_all(self, arg, index): + return rdb.table(self.table).get_all(arg, index=index).run(self._conn) + + def get_one(self, arg, index): + return rdb.table(self.table).get_all(arg, index=index).limit(1).run(self._conn) + class Site(BaseModel): table = 'sites' +class CurrentUser(): + id = None + + def __init__(self, id): + self.id = id + + def get_id(self): + return self.id + + def is_active(self): + return True + + def is_anonymous(self): + return False if self.id else True + + def is_authenticated(self): + return True if self.id else False + + class User(BaseModel): table = 'users' + def get_by_email(self, email): + return to_dict(self.get_one(email, 'email'), True) + + def get_by_username(self, username): + return to_dict(self.get_one(username, 'username'), True) def login(self, login, password): - pass \ No newline at end of file + pass + + @classmethod + def get(cls, id): + print id + return cls(id=id) + + @classmethod + def auth(cls, username, password): + u = User() + data = u.get_by_email(username) + if not data: + return False + + if bcrypt.check_password_hash(data['password'], password): + login_user(CurrentUser(data['id'])) + session['user'] = data + return True + else: + return False \ No newline at end of file diff --git a/reimagine/static/css/style.css b/reimagine/static/css/style.css index 8fb41dd..c8f9e6b 100644 --- a/reimagine/static/css/style.css +++ b/reimagine/static/css/style.css @@ -1,5 +1,15 @@ .navbar { - margin-bottom: 25px; + +} + +#main-body { + background-color: #fff; + padding: 20px; + margin: 0 -20px; + -webkit-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.15); + box-shadow: 0 1px 2px rgba(0,0,0,.15); } .checkbox-cell { @@ -26,7 +36,7 @@ left: 50%; bottom: 10px; right: 10px; - top: 60px; + top: 50px; overflow: auto; background: rgba(255,255,255,0.9); border: 1px solid #EEE; @@ -58,7 +68,7 @@ #editor { position: absolute; margin-right: 5px; - top: 60px; + top: 50px; left: 10px; bottom: 10px; right: 50%; @@ -85,4 +95,27 @@ -ms-box-flex: 1; -o-box-flex: 1; box-flex: 1; +} + +.user-avatar a img { + width: 32px; + height: 32px; + -webkit-box-shadow: 0 1px 3px #1e1e1e; + -moz-box-shadow: 0 1px 3px #1e1e1e; + box-shadow: 0 1px 3px #1e1e1e; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + -ms-border-radius: 2px; + -o-border-radius: 2px; + border-radius: 2px; +} + + +.navbar-nav .user-avatar a { + line-height: 30px; +} + +.navbar-nav>li.user-avatar a { + padding-top: 9px; + padding-bottom: 9px; } \ No newline at end of file diff --git a/reimagine/templates/account/index.html b/reimagine/templates/account/index.html new file mode 100644 index 0000000..91cd377 --- /dev/null +++ b/reimagine/templates/account/index.html @@ -0,0 +1,20 @@ +{% extends 'layout.html' %} +{% block body %} + +

Account

+ +
+
+ +
+ +
+
+ +
+
+ +
+
+
+{% endblock %} \ No newline at end of file diff --git a/reimagine/templates/account/login.html b/reimagine/templates/account/login.html index 73c3139..9d3edb9 100644 --- a/reimagine/templates/account/login.html +++ b/reimagine/templates/account/login.html @@ -5,8 +5,8 @@
- - + +
diff --git a/reimagine/templates/account/register.html b/reimagine/templates/account/register.html index ae7e943..91eee19 100644 --- a/reimagine/templates/account/register.html +++ b/reimagine/templates/account/register.html @@ -27,4 +27,6 @@ + Already registered? Login here. + {% endblock %} \ No newline at end of file diff --git a/reimagine/templates/errors/404.html b/reimagine/templates/errors/404.html index e69de29..686ef75 100644 --- a/reimagine/templates/errors/404.html +++ b/reimagine/templates/errors/404.html @@ -0,0 +1,6 @@ +{% extends 'layout.html' %} +{% block body %} + +

Page Not Found

+ +{% endblock %} \ No newline at end of file diff --git a/reimagine/templates/layout.html b/reimagine/templates/layout.html index 9d7c9f4..3048c01 100644 --- a/reimagine/templates/layout.html +++ b/reimagine/templates/layout.html @@ -6,7 +6,7 @@ - ReImagine + Realms @@ -27,7 +27,7 @@ -