Merge branch 'master' into partials-update

Conflicts:
	realms/modules/wiki/views.py
This commit is contained in:
Chase Sterling 2016-09-05 13:30:27 -04:00
commit 7260c88571
42 changed files with 203 additions and 79 deletions

View File

@ -10,7 +10,8 @@
"keymaster": "madrobby/keymaster", "keymaster": "madrobby/keymaster",
"ace-builds": "~1.2.3", "ace-builds": "~1.2.3",
"parsleyjs": "~2.3.10", "parsleyjs": "~2.3.10",
"marked": "~0.3.2", "markdown-it": "~7.0.0",
"markdown-it-anchor": "https://wzrd.in/standalone/markdown-it-anchor@2.5.0",
"js-yaml": "~3.6.0", "js-yaml": "~3.6.0",
"store-js": "~1.3.16", "store-js": "~1.3.16",
"bootswatch-dist": "3.3.6-flatly", "bootswatch-dist": "3.3.6-flatly",

View File

@ -1,16 +1,19 @@
import functools from __future__ import absolute_import
import sys
import sys
# Set default encoding to UTF-8 # Set default encoding to UTF-8
reload(sys) reload(sys)
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
sys.setdefaultencoding('utf-8') sys.setdefaultencoding('utf-8')
import functools
import base64 import base64
import time import time
import json import json
import httplib
import traceback import traceback
import six.moves.http_client as httplib
from functools import update_wrapper
import click import click
from flask import Flask, request, render_template, url_for, redirect, g from flask import Flask, request, render_template, url_for, redirect, g
from flask_cache import Cache from flask_cache import Cache
@ -18,16 +21,15 @@ from flask_login import LoginManager, current_user
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_assets import Environment, Bundle from flask_assets import Environment, Bundle
from flask_ldap_login import LDAPLoginManager from flask_ldap_login import LDAPLoginManager
from functools import update_wrapper
from werkzeug.routing import BaseConverter from werkzeug.routing import BaseConverter
from werkzeug.exceptions import HTTPException from werkzeug.exceptions import HTTPException
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from .modules.search.models import Search from realms.modules.search.models import Search
from .lib.util import to_canonical, remove_ext, mkdir_safe, gravatar_url, to_dict from realms.lib.util import to_canonical, remove_ext, mkdir_safe, gravatar_url, to_dict
from .lib.hook import HookModelMeta, HookMixin from realms.lib.hook import HookModelMeta, HookMixin
from .lib.util import is_su, in_virtualenv from realms.lib.util import is_su, in_virtualenv
from .version import __version__ from realms.version import __version__
class Application(Flask): class Application(Flask):
@ -229,7 +231,8 @@ assets.register('main.js',
'vendor/components-bootstrap/js/bootstrap.js', 'vendor/components-bootstrap/js/bootstrap.js',
'vendor/handlebars/handlebars.js', 'vendor/handlebars/handlebars.js',
'vendor/js-yaml/dist/js-yaml.js', 'vendor/js-yaml/dist/js-yaml.js',
'vendor/marked/lib/marked.js', 'vendor/markdown-it/dist/markdown-it.js',
'vendor/markdown-it-anchor/index.0',
'js/html-sanitizer-minified.js', # don't minify? 'js/html-sanitizer-minified.js', # don't minify?
'vendor/highlightjs/highlight.pack.js', 'vendor/highlightjs/highlight.pack.js',
'vendor/parsleyjs/dist/parsley.js', 'vendor/parsleyjs/dist/parsley.js',

View File

@ -1,17 +1,23 @@
from realms import config, create_app, db, __version__, cli, cache from __future__ import absolute_import
from realms.lib.util import random_string, in_virtualenv, green, yellow, red
from subprocess import call, Popen
from multiprocessing import cpu_count
import click
import json import json
import sys import sys
import os import os
import pip
import time import time
import subprocess import subprocess
from subprocess import call, Popen
from multiprocessing import cpu_count
import click
import pip
from realms import config, create_app, db, __version__, cli, cache
from realms.lib.util import random_string, in_virtualenv, green, yellow, red
config = config.conf config = config.conf
# called to discover commands in modules # called to discover commands in modules
app = create_app() app = create_app()

View File

@ -1,7 +1,11 @@
from __future__ import absolute_import
import json import json
import os import os
import sys import sys
from urlparse import urlparse
# noinspection PyUnresolvedReferences
from six.moves.urllib.parse import urlparse
from realms.lib.util import in_vagrant from realms.lib.util import in_vagrant
@ -71,7 +75,7 @@ class Config(object):
CACHE_MEMCACHED_SERVERS = ['127.0.0.1:11211'] CACHE_MEMCACHED_SERVERS = ['127.0.0.1:11211']
# Valid options: simple, elasticsearch, woosh # Valid options: simple, elasticsearch, whoosh
SEARCH_TYPE = 'simple' SEARCH_TYPE = 'simple'
ELASTICSEARCH_URL = 'http://127.0.0.1:9200' ELASTICSEARCH_URL = 'http://127.0.0.1:9200'

View File

@ -0,0 +1,2 @@
from __future__ import absolute_import

View File

@ -1,7 +1,10 @@
from flask_sqlalchemy import DeclarativeMeta from __future__ import absolute_import
from functools import wraps from functools import wraps
from flask_sqlalchemy import DeclarativeMeta
def hook_func(name, fn): def hook_func(name, fn):
@wraps(fn) @wraps(fn)

View File

@ -1,6 +1,10 @@
from __future__ import absolute_import
import json import json
from sqlalchemy import not_, and_
from datetime import datetime from datetime import datetime
from sqlalchemy import not_, and_
from realms import db from realms import db

View File

@ -1,9 +1,13 @@
from __future__ import absolute_import
import os import os
import shutil import shutil
import tempfile import tempfile
from flask_testing import TestCase from flask_testing import TestCase
from realms.lib.util import random_string
from realms import create_app from realms import create_app
from realms.lib.util import random_string
class BaseTest(TestCase): class BaseTest(TestCase):

View File

@ -1,4 +1,5 @@
import click from __future__ import absolute_import
import re import re
import os import os
import hashlib import hashlib
@ -6,6 +7,8 @@ import json
import string import string
import random import random
import sys import sys
import click
from jinja2 import Template from jinja2 import Template

View File

@ -0,0 +1 @@
from __future__ import absolute_import

View File

@ -1,7 +1,10 @@
from realms import login_manager from __future__ import absolute_import
from flask import request, flash, redirect from flask import request, flash, redirect
from flask_login import login_url from flask_login import login_url
from realms import login_manager
modules = set() modules = set()
@login_manager.unauthorized_handler @login_manager.unauthorized_handler

View File

@ -1,3 +1,5 @@
from ..models import Auth from __future__ import absolute_import
from realms.modules.auth.models import Auth
Auth.register('ldap') Auth.register('ldap')

View File

@ -1,7 +1,9 @@
from __future__ import absolute_import
from flask_wtf import Form from flask_wtf import Form
from wtforms import StringField, PasswordField, validators from wtforms import StringField, PasswordField, validators
class LoginForm(Form): class LoginForm(Form):
login = StringField('Username', [validators.DataRequired()]) login = StringField('Username', [validators.DataRequired()])
password = PasswordField('Password', [validators.DataRequired()]) password = PasswordField('Password', [validators.DataRequired()])

View File

@ -1,8 +1,11 @@
from __future__ import absolute_import
from flask import render_template from flask import render_template
from flask_login import login_user from flask_login import login_user
from realms import ldap
from flask_ldap_login import LDAPLoginForm from flask_ldap_login import LDAPLoginForm
from ..models import BaseUser
from realms import ldap
from realms.modules.auth.models import BaseUser
users = {} users = {}

View File

@ -1,7 +1,11 @@
from flask import current_app, request, redirect, Blueprint, flash, url_for from __future__ import absolute_import
from ..ldap.models import User
from flask import current_app, request, redirect, Blueprint, flash, url_for, session
from flask_ldap_login import LDAPLoginForm from flask_ldap_login import LDAPLoginForm
from .models import User
blueprint = Blueprint('auth.ldap', __name__) blueprint = Blueprint('auth.ldap', __name__)
@ -14,6 +18,6 @@ def login():
return redirect(url_for('auth.login')) return redirect(url_for('auth.login'))
if User.auth(form.user, request.form['password']): if User.auth(form.user, request.form['password']):
return redirect(request.args.get("next") or url_for(current_app.config['ROOT_ENDPOINT'])) return redirect(session.get("next_url") or url_for(current_app.config['ROOT_ENDPOINT']))
else: else:
return redirect(url_for('auth.login')) return redirect(url_for('auth.login'))

View File

@ -1,3 +1,5 @@
from ..models import Auth from __future__ import absolute_import
from realms.modules.auth.models import Auth
Auth.register('local') Auth.register('local')

View File

@ -1,8 +1,11 @@
from __future__ import absolute_import
import click import click
from realms.lib.util import random_string
from realms.modules.auth.local.models import User
from realms.lib.util import green, red, yellow
from realms import cli_group from realms import cli_group
from realms.lib.util import random_string
from realms.lib.util import green, red, yellow
from .models import User
@cli_group(short_help="Auth Module") @cli_group(short_help="Auth Module")

View File

@ -1,3 +1,5 @@
from __future__ import absolute_import
from flask_wtf import Form from flask_wtf import Form
from wtforms import StringField, PasswordField, validators from wtforms import StringField, PasswordField, validators

View File

@ -1,5 +1,8 @@
from __future__ import absolute_import
from flask import current_app from flask import current_app
from flask_wtf import RecaptchaField from flask_wtf import RecaptchaField
from .forms import RegistrationForm from .forms import RegistrationForm

View File

@ -1,11 +1,15 @@
from __future__ import absolute_import
from hashlib import sha256
from flask import current_app, render_template from flask import current_app, render_template
from flask_login import logout_user, login_user from flask_login import logout_user, login_user
from itsdangerous import URLSafeSerializer, BadSignature
from realms import login_manager, db from realms import login_manager, db
from realms.lib.model import Model from realms.lib.model import Model
from ..models import BaseUser from realms.modules.auth.models import BaseUser
from .forms import LoginForm from .forms import LoginForm
from itsdangerous import URLSafeSerializer, BadSignature
from hashlib import sha256
@login_manager.token_loader @login_manager.token_loader

View File

@ -1,6 +1,10 @@
from flask import current_app, render_template, request, redirect, Blueprint, flash, url_for from __future__ import absolute_import
from realms.modules.auth.local.models import User
from realms.modules.auth.local.forms import LoginForm, RegistrationForm from flask import current_app, render_template, request, redirect, Blueprint, flash, url_for, session
from .models import User
from .forms import LoginForm, RegistrationForm
blueprint = Blueprint('auth.local', __name__) blueprint = Blueprint('auth.local', __name__)
@ -46,6 +50,6 @@ def register():
User.create(request.form['username'], request.form['email'], request.form['password']) User.create(request.form['username'], request.form['email'], request.form['password'])
User.auth(request.form['email'], request.form['password']) User.auth(request.form['email'], request.form['password'])
return redirect(request.args.get("next") or url_for(current_app.config['ROOT_ENDPOINT'])) return redirect(session.get("next_url") or url_for(current_app.config['ROOT_ENDPOINT']))
return render_template("auth/register.html", form=form) return render_template("auth/register.html", form=form)

View File

@ -1,12 +1,16 @@
from __future__ import absolute_import
import importlib
from hashlib import sha256
from flask import current_app from flask import current_app
from flask_login import UserMixin, logout_user, AnonymousUserMixin from flask_login import UserMixin, logout_user, AnonymousUserMixin
from itsdangerous import URLSafeSerializer, BadSignature
import bcrypt
from realms import login_manager from realms import login_manager
from realms.lib.util import gravatar_url from realms.lib.util import gravatar_url
from itsdangerous import URLSafeSerializer, BadSignature
from hashlib import sha256
from . import modules from . import modules
import bcrypt
import importlib
@login_manager.user_loader @login_manager.user_loader

View File

@ -1,3 +1,5 @@
from ..models import Auth from __future__ import absolute_import
from realms.modules.auth.models import Auth
Auth.register('oauth') Auth.register('oauth')

View File

@ -1,9 +1,11 @@
from __future__ import absolute_import
from flask import session from flask import session
from flask_login import login_user from flask_login import login_user
from flask_oauthlib.client import OAuth from flask_oauthlib.client import OAuth
from realms import config from realms import config
from ..models import BaseUser from realms.modules.auth.models import BaseUser
config = config.conf config = config.conf

View File

@ -1,3 +1,5 @@
from __future__ import absolute_import
from flask import Blueprint, url_for, request, flash, redirect, session, current_app from flask import Blueprint, url_for, request, flash, redirect, session, current_app
from .models import User from .models import User
@ -16,7 +18,7 @@ def login(provider):
@blueprint.route('/login/oauth/<provider>/callback') @blueprint.route('/login/oauth/<provider>/callback')
def callback(provider): def callback(provider):
next_url = request.args.get('next') or url_for(current_app.config['ROOT_ENDPOINT']) next_url = session.get('next_url') or url_for(current_app.config['ROOT_ENDPOINT'])
try: try:
remote_app = User.get_app(provider) remote_app = User.get_app(provider)
resp = remote_app.authorized_response() resp = remote_app.authorized_response()

View File

@ -0,0 +1 @@
from __future__ import absolute_import

View File

@ -1,12 +1,18 @@
from flask import current_app, render_template, request, redirect, Blueprint, flash, url_for from __future__ import absolute_import
from flask import current_app, render_template, request, redirect, Blueprint, flash, url_for, session
from flask_login import logout_user from flask_login import logout_user
from realms.modules.auth.models import Auth
from .models import Auth
blueprint = Blueprint('auth', __name__, template_folder='templates') blueprint = Blueprint('auth', __name__, template_folder='templates')
@blueprint.route("/login", methods=['GET', 'POST']) @blueprint.route("/login", methods=['GET', 'POST'])
def login(): def login():
next_url = request.args.get('next') or url_for(current_app.config['ROOT_ENDPOINT'])
session['next_url'] = next_url
return render_template("auth/login.html", forms=Auth.login_forms()) return render_template("auth/login.html", forms=Auth.login_forms())

View File

@ -0,0 +1 @@
from __future__ import absolute_import

View File

@ -1,5 +1,8 @@
from __future__ import absolute_import
import click import click
from flask import current_app from flask import current_app
from realms import search, cli_group from realms import search, cli_group
from realms.modules.wiki.models import Wiki from realms.modules.wiki.models import Wiki

View File

@ -1,5 +1,7 @@
from realms.modules.wiki.models import WikiPage from __future__ import absolute_import
from realms import search from realms import search
from realms.modules.wiki.models import WikiPage
@WikiPage.after('write') @WikiPage.after('write')

View File

@ -1,7 +1,10 @@
from __future__ import absolute_import
import re import re
import sys import sys
from flask import g, current_app from flask import g, current_app
from realms.lib.util import filename_to_cname from realms.lib.util import filename_to_cname

View File

@ -1,7 +1,11 @@
from __future__ import absolute_import
from flask import render_template, request, Blueprint, current_app from flask import render_template, request, Blueprint, current_app
from flask.ext.login import current_user from flask_login import current_user
from realms import search as search_engine from realms import search as search_engine
blueprint = Blueprint('search', __name__, template_folder='templates') blueprint = Blueprint('search', __name__, template_folder='templates')

View File

@ -1,6 +1,9 @@
from __future__ import absolute_import
import os import os
import sys import sys
from realms.modules.wiki.models import Wiki
from .models import Wiki
def init(app): def init(app):

View File

@ -1,3 +1,5 @@
from __future__ import absolute_import
from realms import assets from realms import assets
assets.register('editor.js', assets.register('editor.js',

View File

@ -1,4 +1,7 @@
from __future__ import absolute_import
from flask import g, current_app from flask import g, current_app
from .models import Wiki from .models import Wiki

View File

@ -1,13 +1,17 @@
from __future__ import absolute_import
import os import os
import posixpath import posixpath
import re import re
import ghdiff import ghdiff
import yaml import yaml
from dulwich.object_store import tree_lookup_path from dulwich.object_store import tree_lookup_path
from dulwich.repo import Repo, NotGitRepository from dulwich.repo import Repo, NotGitRepository
from realms.lib.util import cname_to_filename, filename_to_cname
from realms import cache from realms import cache
from realms.lib.hook import HookMixin from realms.lib.hook import HookMixin
from realms.lib.util import cname_to_filename, filename_to_cname
class PageNotFound(Exception): class PageNotFound(Exception):

View File

@ -1,6 +1,10 @@
from __future__ import absolute_import
import json import json
from nose.tools import * from nose.tools import *
from flask import url_for from flask import url_for
from realms.lib.util import cname_to_filename, filename_to_cname from realms.lib.util import cname_to_filename, filename_to_cname
from realms.lib.test import BaseTest from realms.lib.test import BaseTest

View File

@ -1,12 +1,17 @@
from __future__ import absolute_import
import collections import collections
import itertools import itertools
import sys import sys
from datetime import datetime from datetime import datetime
from flask import abort, g, render_template, request, redirect, Blueprint, flash, url_for, current_app from flask import abort, g, render_template, request, redirect, Blueprint, flash, url_for, current_app
from flask_login import login_required, current_user from flask_login import login_required, current_user
from realms.lib.util import to_canonical, remove_ext, gravatar_url from realms.lib.util import to_canonical, remove_ext, gravatar_url
from .models import PageNotFound from .models import PageNotFound
blueprint = Blueprint('wiki', __name__, template_folder='templates', blueprint = Blueprint('wiki', __name__, template_folder='templates',
static_folder='static', static_url_path='/static/wiki') static_folder='static', static_url_path='/static/wiki')

View File

@ -38,15 +38,28 @@ var metaMarked = function(src, opt, callback) {
} }
}; };
marked.setOptions({ var markdownit = window.markdownit({
renderer: new marked.Renderer(), html: true,
gfm: true, linkify: true,
tables: true, typographer: true,
breaks: false, highlight: function (str, lang) {
pedantic: false, if (lang && hljs.getLanguage(lang)) {
sanitize: false, try {
smartLists: true, return hljs.highlight(lang, str).value;
smartypants: false } catch (__) {
}
}
return ''; // use external default escaping
}
}).use(markdownItAnchor, {
level: 1,
// slugify: string => string,
permalink: false,
// renderPermalink: (slug, opts, state, permalink) => {},
permalinkClass: 'header-anchor',
permalinkSymbol: '¶',
permalinkBefore: false
}); });
// Markdown Renderer // Markdown Renderer
@ -54,9 +67,8 @@ var MDR = {
meta: null, meta: null,
md: null, md: null,
sanitize: true, // Override sanitize: true, // Override
renderer: new marked.Renderer(),
parse: function(md){ parse: function(md){
return marked(md, { renderer: this.renderer }); return markdownit.render(md);
}, },
convert: function(md, partials, sanitize) { convert: function(md, partials, sanitize) {
if (this.sanitize !== null) { if (this.sanitize !== null) {
@ -117,13 +129,8 @@ var MDR = {
} }
}; };
MDR.renderer.table = function(header, body) { // Add some custom classes to table tags
return '<table class="table table-bordered">\n' markdownit.renderer.rules.table_open = function (tokens, idx, options, env, self) {
+ '<thead>\n' tokens[idx].attrPush(['class', 'table table-bordered']);
+ header return self.renderToken(tokens, idx, options);
+ '</thead>\n' };
+ '<tbody>\n'
+ body
+ '</tbody>\n'
+ '</table>\n';
};

View File

@ -72,7 +72,7 @@
</ul> </ul>
</li> </li>
{% else %} {% else %}
<li><a href="{{ url_for('auth.login') }}"><i class="fa fa-user"></i> &nbsp;Login</a></li> <li><a href="{{ url_for('auth.login', next=request.path) }}"><i class="fa fa-user"></i> &nbsp;Login</a></li>
{% if config.REGISTRATION_ENABLED and 'auth.local' in config.MODULES %} {% if config.REGISTRATION_ENABLED and 'auth.local' in config.MODULES %}
<li><a href="{{ url_for('auth.local.register') }}"><i class="fa fa-users"></i> &nbsp;Register</a></li> <li><a href="{{ url_for('auth.local.register') }}"><i class="fa fa-users"></i> &nbsp;Register</a></li>
{% endif %} {% endif %}

View File

@ -1 +1,3 @@
from __future__ import absolute_import
__version__ = '0.8.1' __version__ = '0.8.1'

View File

@ -1,5 +1,5 @@
from setuptools import setup, find_packages
import os import os
from setuptools import setup, find_packages
if os.environ.get('USER', '') == 'vagrant': if os.environ.get('USER', '') == 'vagrant':
del os.link del os.link
@ -43,7 +43,8 @@ setup(name='realms-wiki',
'itsdangerous==0.24', 'itsdangerous==0.24',
'markdown2==2.3.1', 'markdown2==2.3.1',
'python-ldap==2.4.22', 'python-ldap==2.4.22',
'simplejson==3.6.3' 'simplejson==3.6.3',
'six==1.10.0'
], ],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [