add config option to disable registration
add command to create user
This commit is contained in:
parent
17eabddd70
commit
b8531a0347
43
manage.py
43
manage.py
|
@ -1,18 +1,43 @@
|
|||
from gevent import wsgi
|
||||
from realms import config, app, manager
|
||||
from flask.ext.script import Server
|
||||
|
||||
manager.add_command("runserver", Server(host="0.0.0.0", port=5000))
|
||||
from realms import config, app, cli, db
|
||||
from werkzeug.serving import run_with_reloader
|
||||
import click
|
||||
import os
|
||||
|
||||
|
||||
@manager.command
|
||||
@cli.command()
|
||||
@click.option('--port', default=5000)
|
||||
def runserver(port):
|
||||
""" Run development server
|
||||
"""
|
||||
click.secho("Starting development server", fg='green')
|
||||
app.run(host="0.0.0.0",
|
||||
port=port,
|
||||
debug=True)
|
||||
|
||||
|
||||
@cli.command()
|
||||
def run():
|
||||
""" Run production server
|
||||
"""
|
||||
Run production ready server
|
||||
"""
|
||||
print "Server started. Env: %s Port: %s" % (config.ENV, config.PORT)
|
||||
click.echo("Server started. Env: %s Port: %s" % (config.ENV, config.PORT))
|
||||
wsgi.WSGIServer(('', int(config.PORT)), app).serve_forever()
|
||||
|
||||
|
||||
@cli.command()
|
||||
def create_db():
|
||||
""" Creates DB tables
|
||||
"""
|
||||
click.echo("Creating all tables")
|
||||
db.create_all()
|
||||
|
||||
|
||||
@cli.command()
|
||||
def drop_db():
|
||||
""" Drops DB tables
|
||||
"""
|
||||
click.echo("Dropping all tables")
|
||||
db.drop_all()
|
||||
|
||||
if __name__ == '__main__':
|
||||
manager.run()
|
||||
cli()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Monkey patch stdlib.
|
||||
import gevent.monkey
|
||||
gevent.monkey.patch_all(aggressive=False)
|
||||
gevent.monkey.patch_all(aggressive=False, subprocess=True)
|
||||
|
||||
# Set default encoding to UTF-8
|
||||
import sys
|
||||
|
@ -14,9 +14,9 @@ import sys
|
|||
import json
|
||||
import httplib
|
||||
import traceback
|
||||
import click
|
||||
from flask import Flask, request, render_template, url_for, redirect, g
|
||||
from flask.ext.cache import Cache
|
||||
from flask.ext.script import Manager
|
||||
from flask.ext.login import LoginManager, current_user
|
||||
from flask.ext.sqlalchemy import SQLAlchemy
|
||||
from flask.ext.assets import Environment, Bundle
|
||||
|
@ -67,9 +67,9 @@ class Application(Flask):
|
|||
if hasattr(sources, 'views'):
|
||||
self.register_blueprint(sources.views.blueprint)
|
||||
|
||||
# Flask-Script
|
||||
# Click
|
||||
if hasattr(sources, 'commands'):
|
||||
manager.add_command(module_name, sources.commands.manager)
|
||||
cli.add_command(sources.commands.cli, name=module_name)
|
||||
|
||||
print >> sys.stderr, ' * Ready in %.2fms' % (1000.0 * (time.time() - start_time))
|
||||
|
||||
|
@ -142,40 +142,39 @@ def error_handler(e):
|
|||
return response, status_code
|
||||
|
||||
|
||||
def create_app():
|
||||
app = Application(__name__)
|
||||
app.config.from_object('realms.config')
|
||||
app.url_map.converters['regex'] = RegexConverter
|
||||
app.url_map.strict_slashes = False
|
||||
|
||||
for status_code in httplib.responses:
|
||||
if status_code >= 400:
|
||||
app.register_error_handler(status_code, error_handler)
|
||||
app = Application(__name__)
|
||||
app.config.from_object('realms.config')
|
||||
app.url_map.converters['regex'] = RegexConverter
|
||||
app.url_map.strict_slashes = False
|
||||
|
||||
@app.before_request
|
||||
def init_g():
|
||||
g.assets = dict(css=['main.css'], js=['main.js'])
|
||||
for status_code in httplib.responses:
|
||||
if status_code >= 400:
|
||||
app.register_error_handler(status_code, error_handler)
|
||||
|
||||
@app.template_filter('datetime')
|
||||
def _jinja2_filter_datetime(ts):
|
||||
return time.strftime('%b %d, %Y %I:%M %p', time.localtime(ts))
|
||||
@app.before_request
|
||||
def init_g():
|
||||
g.assets = dict(css=['main.css'], js=['main.js'])
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
return render_template('errors/404.html'), 404
|
||||
@app.template_filter('datetime')
|
||||
def _jinja2_filter_datetime(ts):
|
||||
return time.strftime('%b %d, %Y %I:%M %p', time.localtime(ts))
|
||||
|
||||
if config.RELATIVE_PATH:
|
||||
@app.route("/")
|
||||
def root():
|
||||
return redirect(url_for(config.ROOT_ENDPOINT))
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
return render_template('errors/404.html'), 404
|
||||
|
||||
return app
|
||||
if config.RELATIVE_PATH:
|
||||
@app.route("/")
|
||||
def root():
|
||||
return redirect(url_for(config.ROOT_ENDPOINT))
|
||||
|
||||
app = create_app()
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
pass
|
||||
|
||||
# Init plugins here if possible
|
||||
manager = Manager(app)
|
||||
|
||||
login_manager = LoginManager(app)
|
||||
login_manager.login_view = 'auth.login'
|
||||
|
||||
|
@ -204,7 +203,7 @@ assets.register('main.css',
|
|||
|
||||
app.discover()
|
||||
|
||||
# Should be called explicitly during install?
|
||||
# This will be removed at some point
|
||||
db.create_all()
|
||||
|
||||
|
||||
|
|
|
@ -37,19 +37,31 @@ RECAPTCHA_OPTIONS = {}
|
|||
|
||||
SECRET_KEY = 'K3dRq1q9eN72GJDkgvyshFVwlqHHCyPI'
|
||||
|
||||
# Path on file system where wiki data will reside
|
||||
WIKI_PATH = os.path.join(APP_PATH, 'wiki')
|
||||
|
||||
# Name of page that will act as home
|
||||
WIKI_HOME = 'home'
|
||||
|
||||
ALLOW_ANON = True
|
||||
REGISTRATION_ENABLED = True
|
||||
|
||||
# Used by Flask-Login
|
||||
LOGIN_DISABLED = ALLOW_ANON
|
||||
|
||||
# Page names that can't be modified
|
||||
LOCKED = []
|
||||
WIKI_LOCKED_PAGES = []
|
||||
# Depreciated variable name
|
||||
LOCKED = WIKI_LOCKED_PAGES
|
||||
|
||||
ROOT_ENDPOINT = 'wiki.page'
|
||||
|
||||
try:
|
||||
with open(os.path.join(APP_PATH, 'config.json')) as f:
|
||||
__settings = json.load(f)
|
||||
for k in ['APP_PATH', 'USER_HOME']:
|
||||
if k in __settings:
|
||||
del __settings[k]
|
||||
globals().update(__settings)
|
||||
except IOError:
|
||||
pass
|
||||
|
|
|
@ -2,6 +2,8 @@ import re
|
|||
import os
|
||||
import hashlib
|
||||
import json
|
||||
import string
|
||||
import random
|
||||
|
||||
|
||||
class AttrDict(dict):
|
||||
|
@ -10,6 +12,10 @@ class AttrDict(dict):
|
|||
self.__dict__ = self
|
||||
|
||||
|
||||
def random_string(size=6, chars=string.ascii_lowercase + string.ascii_uppercase + string.digits):
|
||||
return ''.join(random.choice(chars) for _ in range(size))
|
||||
|
||||
|
||||
def to_json(data):
|
||||
return json.dumps(to_dict(data), separators=(',', ':'))
|
||||
|
||||
|
|
35
realms/modules/auth/commands.py
Normal file
35
realms/modules/auth/commands.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
import click
|
||||
from realms.lib.util import random_string
|
||||
from realms.modules.auth.models import User
|
||||
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
pass
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.argument('username')
|
||||
@click.argument('email')
|
||||
@click.option('--password', help='Leave blank for random password')
|
||||
def create_user(username, email, password):
|
||||
""" Create a new user
|
||||
"""
|
||||
show_pass = not password
|
||||
|
||||
if not password:
|
||||
password = random_string(12)
|
||||
|
||||
if User.get_by_username(username):
|
||||
click.secho("Username %s already exists" % username, fg='red')
|
||||
return
|
||||
|
||||
if User.get_by_email(email):
|
||||
click.secho("Email %s already exists" % email, fg='red')
|
||||
return
|
||||
|
||||
User.create(username, email, password)
|
||||
click.secho("User %s created" % username, fg='green')
|
||||
|
||||
if show_pass:
|
||||
click.secho("Password: %s" % password, fg='yellow')
|
|
@ -2,6 +2,7 @@ from flask_wtf import Form, RecaptchaField
|
|||
from wtforms import StringField, PasswordField, validators
|
||||
from realms import config
|
||||
|
||||
|
||||
class RegistrationForm(Form):
|
||||
username = StringField('Username', [validators.Length(min=4, max=25)])
|
||||
email = StringField('Email Address', [validators.Length(min=6, max=35)])
|
||||
|
|
|
@ -33,6 +33,11 @@ def login():
|
|||
|
||||
@blueprint.route("/register", methods=['GET', 'POST'])
|
||||
def register():
|
||||
|
||||
if not config.REGISTRATION_ENABLED:
|
||||
flash("Registration is disabled")
|
||||
return redirect(url_for(config.ROOT_ENDPOINT))
|
||||
|
||||
form = RegistrationForm()
|
||||
|
||||
if request.method == "POST":
|
||||
|
@ -61,6 +66,7 @@ def register():
|
|||
def settings():
|
||||
return render_template("auth/settings.html")
|
||||
|
||||
|
||||
@blueprint.route("/logout")
|
||||
def logout():
|
||||
User.logout()
|
||||
|
|
|
@ -33,7 +33,7 @@ def revert():
|
|||
commit = request.form.get('commit')
|
||||
cname = to_canonical(name)
|
||||
|
||||
if cname in config.LOCKED:
|
||||
if cname in config.WIKI_LOCKED_PAGES:
|
||||
flash("Page is locked")
|
||||
return redirect(url_for(config.ROOT_ENDPOINT))
|
||||
|
||||
|
@ -56,7 +56,7 @@ def edit(name):
|
|||
if request.method == 'POST':
|
||||
edit_cname = to_canonical(request.form['name'])
|
||||
|
||||
if edit_cname in config.LOCKED:
|
||||
if edit_cname in config.WIKI_LOCKED_PAGES:
|
||||
return redirect(url_for(config.ROOT_ENDPOINT))
|
||||
|
||||
if edit_cname.lower() != cname.lower():
|
||||
|
@ -91,7 +91,7 @@ def create(name):
|
|||
if request.method == 'POST':
|
||||
cname = to_canonical(request.form['name'])
|
||||
|
||||
if cname in config.LOCKED:
|
||||
if cname in config.WIKI_LOCKED_PAGES:
|
||||
return redirect(url_for("wiki.create"))
|
||||
|
||||
if not cname:
|
||||
|
|
|
@ -59,8 +59,10 @@
|
|||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
<li><a href="{{ url_for('auth.login') }}"><i class="icon-user"></i> Login</a></li>
|
||||
<li><a href="{{ url_for('auth.login') }}"><i class="icon-user"></i> Login</a></li>
|
||||
{% if config.REGISTRATION_ENABLED %}
|
||||
<li><a href="{{ url_for('auth.register') }}"><i class="icon-pencil"></i> Register</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
|
|
|
@ -3,7 +3,6 @@ Flask
|
|||
Flask-Assets
|
||||
Flask-Cache
|
||||
Flask-Login
|
||||
Flask-Script
|
||||
Flask-SQLAlchemy
|
||||
Flask-WTF
|
||||
beautifulsoup4
|
||||
|
@ -15,3 +14,4 @@ lxml
|
|||
markdown2
|
||||
simplejson
|
||||
PyYAML
|
||||
click
|
||||
|
|
Loading…
Reference in a new issue