diff --git a/bower.json b/bower.json index 5cc6524..6eaa945 100644 --- a/bower.json +++ b/bower.json @@ -10,7 +10,8 @@ "keymaster": "madrobby/keymaster", "ace-builds": "~1.2.3", "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", "store-js": "~1.3.16", "bootswatch-dist": "3.3.6-flatly", diff --git a/realms/__init__.py b/realms/__init__.py index 27c63dc..273e277 100644 --- a/realms/__init__.py +++ b/realms/__init__.py @@ -1,16 +1,19 @@ -import functools -import sys +from __future__ import absolute_import +import sys # Set default encoding to UTF-8 reload(sys) # noinspection PyUnresolvedReferences sys.setdefaultencoding('utf-8') +import functools import base64 import time import json -import httplib import traceback +import six.moves.http_client as httplib +from functools import update_wrapper + import click from flask import Flask, request, render_template, url_for, redirect, g from flask_cache import Cache @@ -18,16 +21,15 @@ from flask_login import LoginManager, current_user from flask_sqlalchemy import SQLAlchemy from flask_assets import Environment, Bundle from flask_ldap_login import LDAPLoginManager -from functools import update_wrapper from werkzeug.routing import BaseConverter from werkzeug.exceptions import HTTPException from sqlalchemy.ext.declarative import declarative_base -from .modules.search.models import Search -from .lib.util import to_canonical, remove_ext, mkdir_safe, gravatar_url, to_dict -from .lib.hook import HookModelMeta, HookMixin -from .lib.util import is_su, in_virtualenv -from .version import __version__ +from realms.modules.search.models import Search +from realms.lib.util import to_canonical, remove_ext, mkdir_safe, gravatar_url, to_dict +from realms.lib.hook import HookModelMeta, HookMixin +from realms.lib.util import is_su, in_virtualenv +from realms.version import __version__ class Application(Flask): @@ -229,7 +231,8 @@ assets.register('main.js', 'vendor/components-bootstrap/js/bootstrap.js', 'vendor/handlebars/handlebars.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? 'vendor/highlightjs/highlight.pack.js', 'vendor/parsleyjs/dist/parsley.js', diff --git a/realms/commands.py b/realms/commands.py index c7ca43c..1440872 100644 --- a/realms/commands.py +++ b/realms/commands.py @@ -1,17 +1,23 @@ -from realms import config, create_app, db, __version__, cli, cache -from realms.lib.util import random_string, in_virtualenv, green, yellow, red -from subprocess import call, Popen -from multiprocessing import cpu_count -import click +from __future__ import absolute_import + import json import sys import os -import pip import time 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 + # called to discover commands in modules app = create_app() diff --git a/realms/config/__init__.py b/realms/config/__init__.py index 32172f3..8bc8e17 100644 --- a/realms/config/__init__.py +++ b/realms/config/__init__.py @@ -1,7 +1,11 @@ +from __future__ import absolute_import + import json import os import sys -from urlparse import urlparse + +# noinspection PyUnresolvedReferences +from six.moves.urllib.parse import urlparse from realms.lib.util import in_vagrant @@ -71,7 +75,7 @@ class Config(object): CACHE_MEMCACHED_SERVERS = ['127.0.0.1:11211'] - # Valid options: simple, elasticsearch, woosh + # Valid options: simple, elasticsearch, whoosh SEARCH_TYPE = 'simple' ELASTICSEARCH_URL = 'http://127.0.0.1:9200' diff --git a/realms/lib/__init__.py b/realms/lib/__init__.py index e69de29..66b6508 100644 --- a/realms/lib/__init__.py +++ b/realms/lib/__init__.py @@ -0,0 +1,2 @@ +from __future__ import absolute_import + diff --git a/realms/lib/hook.py b/realms/lib/hook.py index a607b54..a46c6de 100644 --- a/realms/lib/hook.py +++ b/realms/lib/hook.py @@ -1,7 +1,10 @@ -from flask_sqlalchemy import DeclarativeMeta +from __future__ import absolute_import from functools import wraps +from flask_sqlalchemy import DeclarativeMeta + + def hook_func(name, fn): @wraps(fn) diff --git a/realms/lib/model.py b/realms/lib/model.py index bd84bbb..86d7839 100644 --- a/realms/lib/model.py +++ b/realms/lib/model.py @@ -1,6 +1,10 @@ +from __future__ import absolute_import + import json -from sqlalchemy import not_, and_ from datetime import datetime + +from sqlalchemy import not_, and_ + from realms import db diff --git a/realms/lib/test.py b/realms/lib/test.py index 465b6f4..e416e24 100644 --- a/realms/lib/test.py +++ b/realms/lib/test.py @@ -1,9 +1,13 @@ +from __future__ import absolute_import + import os import shutil import tempfile + from flask_testing import TestCase -from realms.lib.util import random_string + from realms import create_app +from realms.lib.util import random_string class BaseTest(TestCase): diff --git a/realms/lib/util.py b/realms/lib/util.py index b8c6da0..7ed3167 100644 --- a/realms/lib/util.py +++ b/realms/lib/util.py @@ -1,4 +1,5 @@ -import click +from __future__ import absolute_import + import re import os import hashlib @@ -6,6 +7,8 @@ import json import string import random import sys + +import click from jinja2 import Template diff --git a/realms/modules/__init__.py b/realms/modules/__init__.py index e69de29..c396168 100644 --- a/realms/modules/__init__.py +++ b/realms/modules/__init__.py @@ -0,0 +1 @@ +from __future__ import absolute_import diff --git a/realms/modules/auth/__init__.py b/realms/modules/auth/__init__.py index b8421e7..1908ef5 100644 --- a/realms/modules/auth/__init__.py +++ b/realms/modules/auth/__init__.py @@ -1,7 +1,10 @@ -from realms import login_manager +from __future__ import absolute_import + from flask import request, flash, redirect from flask_login import login_url +from realms import login_manager + modules = set() @login_manager.unauthorized_handler diff --git a/realms/modules/auth/ldap/__init__.py b/realms/modules/auth/ldap/__init__.py index f3d364d..7ec6f86 100644 --- a/realms/modules/auth/ldap/__init__.py +++ b/realms/modules/auth/ldap/__init__.py @@ -1,3 +1,5 @@ -from ..models import Auth +from __future__ import absolute_import + +from realms.modules.auth.models import Auth Auth.register('ldap') diff --git a/realms/modules/auth/ldap/forms.py b/realms/modules/auth/ldap/forms.py index 71dd215..e876af0 100644 --- a/realms/modules/auth/ldap/forms.py +++ b/realms/modules/auth/ldap/forms.py @@ -1,7 +1,9 @@ +from __future__ import absolute_import + from flask_wtf import Form from wtforms import StringField, PasswordField, validators class LoginForm(Form): login = StringField('Username', [validators.DataRequired()]) - password = PasswordField('Password', [validators.DataRequired()]) \ No newline at end of file + password = PasswordField('Password', [validators.DataRequired()]) diff --git a/realms/modules/auth/ldap/models.py b/realms/modules/auth/ldap/models.py index 1574eb8..f9a7931 100644 --- a/realms/modules/auth/ldap/models.py +++ b/realms/modules/auth/ldap/models.py @@ -1,8 +1,11 @@ +from __future__ import absolute_import + from flask import render_template from flask_login import login_user -from realms import ldap from flask_ldap_login import LDAPLoginForm -from ..models import BaseUser + +from realms import ldap +from realms.modules.auth.models import BaseUser users = {} diff --git a/realms/modules/auth/ldap/views.py b/realms/modules/auth/ldap/views.py index 7ab82f4..d491aa8 100644 --- a/realms/modules/auth/ldap/views.py +++ b/realms/modules/auth/ldap/views.py @@ -1,7 +1,11 @@ -from flask import current_app, request, redirect, Blueprint, flash, url_for -from ..ldap.models import User +from __future__ import absolute_import + +from flask import current_app, request, redirect, Blueprint, flash, url_for, session from flask_ldap_login import LDAPLoginForm +from .models import User + + blueprint = Blueprint('auth.ldap', __name__) @@ -14,6 +18,6 @@ def login(): return redirect(url_for('auth.login')) 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: return redirect(url_for('auth.login')) diff --git a/realms/modules/auth/local/__init__.py b/realms/modules/auth/local/__init__.py index 8c939c1..6dbfd63 100644 --- a/realms/modules/auth/local/__init__.py +++ b/realms/modules/auth/local/__init__.py @@ -1,3 +1,5 @@ -from ..models import Auth +from __future__ import absolute_import + +from realms.modules.auth.models import Auth Auth.register('local') diff --git a/realms/modules/auth/local/commands.py b/realms/modules/auth/local/commands.py index ae4a7e9..65b12fc 100644 --- a/realms/modules/auth/local/commands.py +++ b/realms/modules/auth/local/commands.py @@ -1,8 +1,11 @@ +from __future__ import absolute_import + import click + +from realms import cli_group 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 .models import User @cli_group(short_help="Auth Module") diff --git a/realms/modules/auth/local/forms.py b/realms/modules/auth/local/forms.py index e1cbee5..d18a0e7 100644 --- a/realms/modules/auth/local/forms.py +++ b/realms/modules/auth/local/forms.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from flask_wtf import Form from wtforms import StringField, PasswordField, validators diff --git a/realms/modules/auth/local/hooks.py b/realms/modules/auth/local/hooks.py index cbe1762..1599162 100644 --- a/realms/modules/auth/local/hooks.py +++ b/realms/modules/auth/local/hooks.py @@ -1,5 +1,8 @@ +from __future__ import absolute_import + from flask import current_app from flask_wtf import RecaptchaField + from .forms import RegistrationForm diff --git a/realms/modules/auth/local/models.py b/realms/modules/auth/local/models.py index 9e14ec8..228f196 100644 --- a/realms/modules/auth/local/models.py +++ b/realms/modules/auth/local/models.py @@ -1,11 +1,15 @@ +from __future__ import absolute_import + +from hashlib import sha256 + from flask import current_app, render_template from flask_login import logout_user, login_user +from itsdangerous import URLSafeSerializer, BadSignature + from realms import login_manager, db from realms.lib.model import Model -from ..models import BaseUser +from realms.modules.auth.models import BaseUser from .forms import LoginForm -from itsdangerous import URLSafeSerializer, BadSignature -from hashlib import sha256 @login_manager.token_loader diff --git a/realms/modules/auth/local/views.py b/realms/modules/auth/local/views.py index c863d0e..64ea2b9 100644 --- a/realms/modules/auth/local/views.py +++ b/realms/modules/auth/local/views.py @@ -1,6 +1,10 @@ -from flask import current_app, render_template, request, redirect, Blueprint, flash, url_for -from realms.modules.auth.local.models import User -from realms.modules.auth.local.forms import LoginForm, RegistrationForm +from __future__ import absolute_import + +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__) @@ -46,6 +50,6 @@ 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(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) diff --git a/realms/modules/auth/models.py b/realms/modules/auth/models.py index f5a0ec7..94a67eb 100644 --- a/realms/modules/auth/models.py +++ b/realms/modules/auth/models.py @@ -1,12 +1,16 @@ +from __future__ import absolute_import + +import importlib +from hashlib import sha256 + from flask import current_app from flask_login import UserMixin, logout_user, AnonymousUserMixin +from itsdangerous import URLSafeSerializer, BadSignature +import bcrypt + from realms import login_manager from realms.lib.util import gravatar_url -from itsdangerous import URLSafeSerializer, BadSignature -from hashlib import sha256 from . import modules -import bcrypt -import importlib @login_manager.user_loader diff --git a/realms/modules/auth/oauth/__init__.py b/realms/modules/auth/oauth/__init__.py index 7a84b08..4cf7d35 100644 --- a/realms/modules/auth/oauth/__init__.py +++ b/realms/modules/auth/oauth/__init__.py @@ -1,3 +1,5 @@ -from ..models import Auth +from __future__ import absolute_import + +from realms.modules.auth.models import Auth Auth.register('oauth') diff --git a/realms/modules/auth/oauth/models.py b/realms/modules/auth/oauth/models.py index d7f7680..40cb5b4 100644 --- a/realms/modules/auth/oauth/models.py +++ b/realms/modules/auth/oauth/models.py @@ -1,9 +1,11 @@ +from __future__ import absolute_import + from flask import session from flask_login import login_user from flask_oauthlib.client import OAuth from realms import config -from ..models import BaseUser +from realms.modules.auth.models import BaseUser config = config.conf diff --git a/realms/modules/auth/oauth/views.py b/realms/modules/auth/oauth/views.py index 3eb99e4..e0cebb3 100644 --- a/realms/modules/auth/oauth/views.py +++ b/realms/modules/auth/oauth/views.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from flask import Blueprint, url_for, request, flash, redirect, session, current_app from .models import User @@ -16,7 +18,7 @@ def login(provider): @blueprint.route('/login/oauth//callback') 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: remote_app = User.get_app(provider) resp = remote_app.authorized_response() diff --git a/realms/modules/auth/tests.py b/realms/modules/auth/tests.py index e69de29..c396168 100644 --- a/realms/modules/auth/tests.py +++ b/realms/modules/auth/tests.py @@ -0,0 +1 @@ +from __future__ import absolute_import diff --git a/realms/modules/auth/views.py b/realms/modules/auth/views.py index 40f5e47..f11eee5 100644 --- a/realms/modules/auth/views.py +++ b/realms/modules/auth/views.py @@ -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 realms.modules.auth.models import Auth + +from .models import Auth + blueprint = Blueprint('auth', __name__, template_folder='templates') @blueprint.route("/login", methods=['GET', 'POST']) 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()) diff --git a/realms/modules/search/__init__.py b/realms/modules/search/__init__.py index e69de29..c396168 100644 --- a/realms/modules/search/__init__.py +++ b/realms/modules/search/__init__.py @@ -0,0 +1 @@ +from __future__ import absolute_import diff --git a/realms/modules/search/commands.py b/realms/modules/search/commands.py index eab1556..a30758a 100644 --- a/realms/modules/search/commands.py +++ b/realms/modules/search/commands.py @@ -1,5 +1,8 @@ +from __future__ import absolute_import + import click from flask import current_app + from realms import search, cli_group from realms.modules.wiki.models import Wiki diff --git a/realms/modules/search/hooks.py b/realms/modules/search/hooks.py index abf7346..a18b87d 100644 --- a/realms/modules/search/hooks.py +++ b/realms/modules/search/hooks.py @@ -1,5 +1,7 @@ -from realms.modules.wiki.models import WikiPage +from __future__ import absolute_import + from realms import search +from realms.modules.wiki.models import WikiPage @WikiPage.after('write') diff --git a/realms/modules/search/models.py b/realms/modules/search/models.py index 2935db7..2dac20b 100644 --- a/realms/modules/search/models.py +++ b/realms/modules/search/models.py @@ -1,7 +1,10 @@ +from __future__ import absolute_import + import re import sys from flask import g, current_app + from realms.lib.util import filename_to_cname diff --git a/realms/modules/search/views.py b/realms/modules/search/views.py index 4172039..7d74e20 100644 --- a/realms/modules/search/views.py +++ b/realms/modules/search/views.py @@ -1,7 +1,11 @@ +from __future__ import absolute_import + 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 + blueprint = Blueprint('search', __name__, template_folder='templates') diff --git a/realms/modules/wiki/__init__.py b/realms/modules/wiki/__init__.py index c9ec232..9f70e89 100644 --- a/realms/modules/wiki/__init__.py +++ b/realms/modules/wiki/__init__.py @@ -1,6 +1,9 @@ +from __future__ import absolute_import + import os import sys -from realms.modules.wiki.models import Wiki + +from .models import Wiki def init(app): diff --git a/realms/modules/wiki/assets.py b/realms/modules/wiki/assets.py index 8f20b42..9b87083 100644 --- a/realms/modules/wiki/assets.py +++ b/realms/modules/wiki/assets.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from realms import assets assets.register('editor.js', diff --git a/realms/modules/wiki/hooks.py b/realms/modules/wiki/hooks.py index 03c9ae9..dbb9af0 100644 --- a/realms/modules/wiki/hooks.py +++ b/realms/modules/wiki/hooks.py @@ -1,4 +1,7 @@ +from __future__ import absolute_import + from flask import g, current_app + from .models import Wiki diff --git a/realms/modules/wiki/models.py b/realms/modules/wiki/models.py index e5b3ca2..3387da4 100644 --- a/realms/modules/wiki/models.py +++ b/realms/modules/wiki/models.py @@ -1,13 +1,17 @@ +from __future__ import absolute_import + import os import posixpath import re + import ghdiff import yaml from dulwich.object_store import tree_lookup_path from dulwich.repo import Repo, NotGitRepository -from realms.lib.util import cname_to_filename, filename_to_cname + from realms import cache from realms.lib.hook import HookMixin +from realms.lib.util import cname_to_filename, filename_to_cname class PageNotFound(Exception): diff --git a/realms/modules/wiki/tests.py b/realms/modules/wiki/tests.py index 565f4f1..a3e2435 100644 --- a/realms/modules/wiki/tests.py +++ b/realms/modules/wiki/tests.py @@ -1,6 +1,10 @@ +from __future__ import absolute_import + import json + from nose.tools import * from flask import url_for + from realms.lib.util import cname_to_filename, filename_to_cname from realms.lib.test import BaseTest diff --git a/realms/modules/wiki/views.py b/realms/modules/wiki/views.py index 480775b..528e29a 100644 --- a/realms/modules/wiki/views.py +++ b/realms/modules/wiki/views.py @@ -1,12 +1,17 @@ +from __future__ import absolute_import + import collections import itertools import sys from datetime import datetime + from flask import abort, g, render_template, request, redirect, Blueprint, flash, url_for, current_app from flask_login import login_required, current_user + from realms.lib.util import to_canonical, remove_ext, gravatar_url from .models import PageNotFound + blueprint = Blueprint('wiki', __name__, template_folder='templates', static_folder='static', static_url_path='/static/wiki') diff --git a/realms/static/js/mdr.js b/realms/static/js/mdr.js index 0f077b3..6522973 100644 --- a/realms/static/js/mdr.js +++ b/realms/static/js/mdr.js @@ -38,15 +38,28 @@ var metaMarked = function(src, opt, callback) { } }; -marked.setOptions({ - renderer: new marked.Renderer(), - gfm: true, - tables: true, - breaks: false, - pedantic: false, - sanitize: false, - smartLists: true, - smartypants: false +var markdownit = window.markdownit({ + html: true, + linkify: true, + typographer: true, + highlight: function (str, lang) { + if (lang && hljs.getLanguage(lang)) { + try { + return hljs.highlight(lang, str).value; + } 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 @@ -54,9 +67,8 @@ var MDR = { meta: null, md: null, sanitize: true, // Override - renderer: new marked.Renderer(), parse: function(md){ - return marked(md, { renderer: this.renderer }); + return markdownit.render(md); }, convert: function(md, partials, sanitize) { if (this.sanitize !== null) { @@ -117,13 +129,8 @@ var MDR = { } }; -MDR.renderer.table = function(header, body) { - return '\n' - + '\n' - + header - + '\n' - + '\n' - + body - + '\n' - + '
\n'; -}; \ No newline at end of file +// Add some custom classes to table tags +markdownit.renderer.rules.table_open = function (tokens, idx, options, env, self) { + tokens[idx].attrPush(['class', 'table table-bordered']); + return self.renderToken(tokens, idx, options); +}; diff --git a/realms/templates/layout.html b/realms/templates/layout.html index a8ee14c..fbe097f 100644 --- a/realms/templates/layout.html +++ b/realms/templates/layout.html @@ -72,7 +72,7 @@ {% else %} -
  •  Login
  • +
  •  Login
  • {% if config.REGISTRATION_ENABLED and 'auth.local' in config.MODULES %}
  •  Register
  • {% endif %} diff --git a/realms/version.py b/realms/version.py index ef72cc0..91a872e 100644 --- a/realms/version.py +++ b/realms/version.py @@ -1 +1,3 @@ +from __future__ import absolute_import + __version__ = '0.8.1' diff --git a/setup.py b/setup.py index 3b8ab06..b1b7b95 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ -from setuptools import setup, find_packages import os +from setuptools import setup, find_packages if os.environ.get('USER', '') == 'vagrant': del os.link @@ -43,7 +43,8 @@ setup(name='realms-wiki', 'itsdangerous==0.24', 'markdown2==2.3.1', 'python-ldap==2.4.22', - 'simplejson==3.6.3' + 'simplejson==3.6.3', + 'six==1.10.0' ], entry_points={ 'console_scripts': [