Merge branch 'master' into markdown-it
This commit is contained in:
commit
2bf11e6604
|
@ -6,7 +6,7 @@ RUN apt-get install -y software-properties-common python-software-properties
|
||||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||||
|
|
||||||
RUN ln -s /usr/bin/nodejs /usr/bin/node && \
|
RUN ln -s /usr/bin/nodejs /usr/bin/node && \
|
||||||
npm install -g bower
|
npm install -g bower clean-css
|
||||||
|
|
||||||
RUN useradd -ms /bin/bash wiki
|
RUN useradd -ms /bin/bash wiki
|
||||||
|
|
||||||
|
@ -44,4 +44,3 @@ CMD . .venv/bin/activate && \
|
||||||
--bind 0.0.0.0:5000 \
|
--bind 0.0.0.0:5000 \
|
||||||
--chdir /home/wiki/realms-wiki \
|
--chdir /home/wiki/realms-wiki \
|
||||||
'realms:create_app()'
|
'realms:create_app()'
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,10 @@ import httplib
|
||||||
import traceback
|
import traceback
|
||||||
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.ext.cache import Cache
|
from flask_cache import Cache
|
||||||
from flask.ext.login import LoginManager, current_user
|
from flask_login import LoginManager, current_user
|
||||||
from flask.ext.sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
from flask.ext.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 functools import update_wrapper
|
||||||
from werkzeug.routing import BaseConverter
|
from werkzeug.routing import BaseConverter
|
||||||
|
@ -180,9 +180,7 @@ def create_app(config=None):
|
||||||
|
|
||||||
db.Model = declarative_base(metaclass=HookModelMeta, cls=HookMixin)
|
db.Model = declarative_base(metaclass=HookModelMeta, cls=HookMixin)
|
||||||
|
|
||||||
for status_code in httplib.responses:
|
app.register_error_handler(HTTPException, error_handler)
|
||||||
if status_code >= 400:
|
|
||||||
app.register_error_handler(status_code, error_handler)
|
|
||||||
|
|
||||||
@app.before_request
|
@app.before_request
|
||||||
def init_g():
|
def init_g():
|
||||||
|
|
|
@ -425,7 +425,7 @@ def clear_cache():
|
||||||
def test():
|
def test():
|
||||||
""" Run tests
|
""" Run tests
|
||||||
"""
|
"""
|
||||||
for mod in [('flask.ext.testing', 'Flask-Testing'), ('nose', 'nose'), ('blinker', 'blinker')]:
|
for mod in [('flask_testing', 'Flask-Testing'), ('nose', 'nose'), ('blinker', 'blinker')]:
|
||||||
if not module_exists(mod[0]):
|
if not module_exists(mod[0]):
|
||||||
pip.main(['install', mod[1]])
|
pip.main(['install', mod[1]])
|
||||||
|
|
||||||
|
|
|
@ -139,6 +139,7 @@ class Config(object):
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
ASSETS_DEBUG = False
|
ASSETS_DEBUG = False
|
||||||
SQLALCHEMY_ECHO = False
|
SQLALCHEMY_ECHO = False
|
||||||
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
|
|
||||||
MODULES = ['wiki', 'search', 'auth']
|
MODULES = ['wiki', 'search', 'auth']
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from flask.ext.sqlalchemy import DeclarativeMeta
|
from flask_sqlalchemy import DeclarativeMeta
|
||||||
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
from flask.ext.testing import TestCase
|
from flask_testing import TestCase
|
||||||
from realms.lib.util import random_string
|
from realms.lib.util import random_string
|
||||||
from realms import create_app
|
from realms import create_app
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from realms import login_manager
|
from realms import login_manager
|
||||||
from flask import request, flash, redirect
|
from flask import request, flash, redirect
|
||||||
from flask.ext.login import login_url
|
from flask_login import login_url
|
||||||
|
|
||||||
modules = set()
|
modules = set()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from flask import render_template
|
from flask import render_template
|
||||||
from flask.ext.login import login_user
|
from flask_login import login_user
|
||||||
from realms import ldap
|
from realms import ldap
|
||||||
from flask_ldap_login import LDAPLoginForm
|
from flask_ldap_login import LDAPLoginForm
|
||||||
from ..models import BaseUser
|
from ..models import BaseUser
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from flask import current_app, request, redirect, Blueprint, flash, url_for
|
from flask import current_app, request, redirect, Blueprint, flash, url_for, session
|
||||||
from ..ldap.models import User
|
from ..ldap.models import User
|
||||||
from flask_ldap_login import LDAPLoginForm
|
from flask_ldap_login import LDAPLoginForm
|
||||||
|
|
||||||
|
@ -14,6 +14,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'))
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from flask import current_app, render_template
|
from flask import current_app, render_template
|
||||||
from flask.ext.login import logout_user, login_user
|
from flask_login import logout_user, login_user
|
||||||
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 ..models import BaseUser
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from flask import current_app, render_template, request, redirect, Blueprint, flash, url_for
|
from flask import current_app, render_template, request, redirect, Blueprint, flash, url_for, session
|
||||||
from realms.modules.auth.local.models import User
|
from realms.modules.auth.local.models import User
|
||||||
from realms.modules.auth.local.forms import LoginForm, RegistrationForm
|
from realms.modules.auth.local.forms import LoginForm, RegistrationForm
|
||||||
|
|
||||||
|
@ -46,6 +46,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)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from flask.ext.login import UserMixin, logout_user, AnonymousUserMixin
|
from flask_login import UserMixin, logout_user, AnonymousUserMixin
|
||||||
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 itsdangerous import URLSafeSerializer, BadSignature
|
||||||
|
|
|
@ -16,7 +16,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()
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
from flask import current_app, render_template, request, redirect, Blueprint, flash, url_for
|
from flask import current_app, render_template, request, redirect, Blueprint, flash, url_for, session
|
||||||
from flask.ext.login import logout_user
|
from flask_login import logout_user
|
||||||
from realms.modules.auth.models import Auth
|
from realms.modules.auth.models import Auth
|
||||||
|
|
||||||
blueprint = Blueprint('auth', __name__)
|
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())
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ def whoosh(app):
|
||||||
|
|
||||||
|
|
||||||
def elasticsearch(app):
|
def elasticsearch(app):
|
||||||
from flask.ext.elastic import Elastic
|
from flask_elastic import Elastic
|
||||||
fields = app.config.get('ELASTICSEARCH_FIELDS')
|
fields = app.config.get('ELASTICSEARCH_FIELDS')
|
||||||
return ElasticSearch(Elastic(app), fields)
|
return ElasticSearch(Elastic(app), fields)
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
from flask import render_template, request, Blueprint
|
from flask import render_template, request, Blueprint, current_app
|
||||||
|
from flask.ext.login import current_user
|
||||||
from realms import search as search_engine
|
from realms import search as search_engine
|
||||||
|
|
||||||
blueprint = Blueprint('search', __name__)
|
blueprint = Blueprint('search', __name__, template_folder='templates')
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route('/_search')
|
@blueprint.route('/_search')
|
||||||
def search():
|
def search():
|
||||||
|
if current_app.config.get('PRIVATE_WIKI') and current_user.is_anonymous():
|
||||||
|
return current_app.login_manager.unauthorized()
|
||||||
|
|
||||||
results = search_engine.wiki(request.args.get('q'))
|
results = search_engine.wiki(request.args.get('q'))
|
||||||
return render_template('search/search.html', results=results)
|
return render_template('search/search.html', results=results)
|
||||||
|
|
|
@ -7,4 +7,4 @@ assets.register('editor.js',
|
||||||
'vendor/ace-builds/src/mode-markdown.js',
|
'vendor/ace-builds/src/mode-markdown.js',
|
||||||
'vendor/ace-builds/src/ext-keybinding_menu.js',
|
'vendor/ace-builds/src/ext-keybinding_menu.js',
|
||||||
'vendor/keymaster/keymaster.js',
|
'vendor/keymaster/keymaster.js',
|
||||||
'js/aced.js')
|
'wiki/js/aced.js')
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
var PAGE_NAME = '{{ name }}';
|
var PAGE_NAME = '{{ name }}';
|
||||||
</script>
|
</script>
|
||||||
<script src="{{ url_for('static', filename='js/editor.js') }}"></script>
|
<script src="{{ url_for('wiki.static', filename='js/editor.js') }}"></script>
|
||||||
|
|
||||||
{% if partials %}
|
{% if partials %}
|
||||||
<script>
|
<script>
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if config.get('COLLABORATION') %}
|
{% if config.get('COLLABORATION') %}
|
||||||
<script src="{{ url_for('static', filename='js/collaboration/main.js') }}"></script>
|
<script src="{{ url_for('wiki.static', filename='js/collaboration/main.js') }}"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if config.get('COLLABORATION') == 'firepad' %}
|
{% if config.get('COLLABORATION') == 'firepad' %}
|
||||||
|
@ -34,11 +34,11 @@
|
||||||
</script>
|
</script>
|
||||||
<script src="https://cdn.firebase.com/js/client/1.0.17/firebase.js"></script>
|
<script src="https://cdn.firebase.com/js/client/1.0.17/firebase.js"></script>
|
||||||
<script src="https://cdn.firebase.com/libs/firepad/1.0.0/firepad.min.js"></script>
|
<script src="https://cdn.firebase.com/libs/firepad/1.0.0/firepad.min.js"></script>
|
||||||
<script src="{{ url_for('static', filename='js/collaboration/firepad.js') }}"></script>
|
<script src="{{ url_for('wiki.static', filename='js/collaboration/firepad.js') }}"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if config.get('COLLABORATION') == 'togetherjs' %}
|
{% if config.get('COLLABORATION') == 'togetherjs' %}
|
||||||
<script src="{{ url_for('static', filename='js/collaboration/togetherjs.js') }}"></script>
|
<script src="{{ url_for('wiki.static', filename='js/collaboration/togetherjs.js') }}"></script>
|
||||||
<script src="https://togetherjs.com/togetherjs-min.js"></script>
|
<script src="https://togetherjs.com/togetherjs-min.js"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -2,16 +2,17 @@ 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.ext.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__)
|
blueprint = Blueprint('wiki', __name__, template_folder='templates',
|
||||||
|
static_folder='static', static_url_path='/static/wiki')
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/_commit/<sha>/<path:name>")
|
@blueprint.route("/_commit/<sha>/<path:name>")
|
||||||
def commit(name, sha):
|
def commit(name, sha):
|
||||||
if current_app.config.get('PRIVATE_WIKI') and current_user.is_anonymous():
|
if current_app.config.get('PRIVATE_WIKI') and current_user.is_anonymous:
|
||||||
return current_app.login_manager.unauthorized()
|
return current_app.login_manager.unauthorized()
|
||||||
|
|
||||||
cname = to_canonical(name)
|
cname = to_canonical(name)
|
||||||
|
@ -26,7 +27,7 @@ def commit(name, sha):
|
||||||
|
|
||||||
@blueprint.route(r"/_compare/<path:name>/<regex('\w+'):fsha><regex('\.{2,3}'):dots><regex('\w+'):lsha>")
|
@blueprint.route(r"/_compare/<path:name>/<regex('\w+'):fsha><regex('\.{2,3}'):dots><regex('\w+'):lsha>")
|
||||||
def compare(name, fsha, dots, lsha):
|
def compare(name, fsha, dots, lsha):
|
||||||
if current_app.config.get('PRIVATE_WIKI') and current_user.is_anonymous():
|
if current_app.config.get('PRIVATE_WIKI') and current_user.is_anonymous:
|
||||||
return current_app.login_manager.unauthorized()
|
return current_app.login_manager.unauthorized()
|
||||||
|
|
||||||
diff = g.current_wiki.get_page(name, sha=lsha).compare(fsha)
|
diff = g.current_wiki.get_page(name, sha=lsha).compare(fsha)
|
||||||
|
@ -41,7 +42,7 @@ def revert():
|
||||||
commit = request.form.get('commit')
|
commit = request.form.get('commit')
|
||||||
message = request.form.get('message', "Reverting %s" % cname)
|
message = request.form.get('message', "Reverting %s" % cname)
|
||||||
|
|
||||||
if not current_app.config.get('ALLOW_ANON') and current_user.is_anonymous():
|
if not current_app.config.get('ALLOW_ANON') and current_user.is_anonymous:
|
||||||
return dict(error=True, message="Anonymous posting not allowed"), 403
|
return dict(error=True, message="Anonymous posting not allowed"), 403
|
||||||
|
|
||||||
if cname in current_app.config.get('WIKI_LOCKED_PAGES'):
|
if cname in current_app.config.get('WIKI_LOCKED_PAGES'):
|
||||||
|
@ -63,7 +64,7 @@ def revert():
|
||||||
|
|
||||||
@blueprint.route("/_history/<path:name>")
|
@blueprint.route("/_history/<path:name>")
|
||||||
def history(name):
|
def history(name):
|
||||||
if current_app.config.get('PRIVATE_WIKI') and current_user.is_anonymous():
|
if current_app.config.get('PRIVATE_WIKI') and current_user.is_anonymous:
|
||||||
return current_app.login_manager.unauthorized()
|
return current_app.login_manager.unauthorized()
|
||||||
return render_template('wiki/history.html', name=name)
|
return render_template('wiki/history.html', name=name)
|
||||||
|
|
||||||
|
@ -165,7 +166,7 @@ def _tree_index(items, path=""):
|
||||||
@blueprint.route("/_index", defaults={"path": ""})
|
@blueprint.route("/_index", defaults={"path": ""})
|
||||||
@blueprint.route("/_index/<path:path>")
|
@blueprint.route("/_index/<path:path>")
|
||||||
def index(path):
|
def index(path):
|
||||||
if current_app.config.get('PRIVATE_WIKI') and current_user.is_anonymous():
|
if current_app.config.get('PRIVATE_WIKI') and current_user.is_anonymous:
|
||||||
return current_app.login_manager.unauthorized()
|
return current_app.login_manager.unauthorized()
|
||||||
|
|
||||||
items = g.current_wiki.get_index()
|
items = g.current_wiki.get_index()
|
||||||
|
@ -186,7 +187,7 @@ def page_write(name):
|
||||||
if not cname:
|
if not cname:
|
||||||
return dict(error=True, message="Invalid name")
|
return dict(error=True, message="Invalid name")
|
||||||
|
|
||||||
if not current_app.config.get('ALLOW_ANON') and current_user.is_anonymous():
|
if not current_app.config.get('ALLOW_ANON') and current_user.is_anonymous:
|
||||||
return dict(error=True, message="Anonymous posting not allowed"), 403
|
return dict(error=True, message="Anonymous posting not allowed"), 403
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
@ -229,7 +230,7 @@ def page_write(name):
|
||||||
@blueprint.route("/", defaults={'name': 'home'})
|
@blueprint.route("/", defaults={'name': 'home'})
|
||||||
@blueprint.route("/<path:name>")
|
@blueprint.route("/<path:name>")
|
||||||
def page(name):
|
def page(name):
|
||||||
if current_app.config.get('PRIVATE_WIKI') and current_user.is_anonymous():
|
if current_app.config.get('PRIVATE_WIKI') and current_user.is_anonymous:
|
||||||
return current_app.login_manager.unauthorized()
|
return current_app.login_manager.unauthorized()
|
||||||
|
|
||||||
cname = to_canonical(name)
|
cname = to_canonical(name)
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
{% if current_user.is_authenticated() %}
|
{% if current_user.is_authenticated %}
|
||||||
<li class="dropdown user-avatar">
|
<li class="dropdown user-avatar">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||||
<span>
|
<span>
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li><a href="{{ url_for('auth.login') }}"><i class="fa fa-user"></i> Login</a></li>
|
<li><a href="{{ url_for('auth.login', next=request.path) }}"><i class="fa fa-user"></i> 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> Register</a></li>
|
<li><a href="{{ url_for('auth.local.register') }}"><i class="fa fa-users"></i> Register</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -109,7 +109,7 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
var User = {};
|
var User = {};
|
||||||
User.is_authenticated = {{ current_user.is_authenticated()|tojson }};
|
User.is_authenticated = {{ current_user.is_authenticated|tojson }};
|
||||||
{% for attr in ['username', 'email'] %}
|
{% for attr in ['username', 'email'] %}
|
||||||
User.{{ attr }} = {{ current_user[attr]|tojson }};
|
User.{{ attr }} = {{ current_user[attr]|tojson }};
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
12
setup.py
12
setup.py
|
@ -23,14 +23,14 @@ setup(name='realms-wiki',
|
||||||
version=__version__,
|
version=__version__,
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'Flask==0.10.1',
|
'Flask==0.11.1',
|
||||||
'Flask-Assets==0.10',
|
'Flask-Assets==0.11',
|
||||||
'Flask-Cache==0.13.1',
|
'Flask-Cache==0.13.1',
|
||||||
'Flask-Elastic==0.2',
|
'Flask-Elastic==0.2',
|
||||||
'Flask-Login==0.2.11',
|
'Flask-Login==0.3.2',
|
||||||
'Flask-OAuthlib==0.9.1',
|
'Flask-OAuthlib==0.9.3',
|
||||||
'Flask-SQLAlchemy==2.0',
|
'Flask-SQLAlchemy==2.1',
|
||||||
'Flask-WTF==0.10.2',
|
'Flask-WTF==0.12',
|
||||||
'PyYAML==3.11',
|
'PyYAML==3.11',
|
||||||
'bcrypt==1.0.2',
|
'bcrypt==1.0.2',
|
||||||
'beautifulsoup4==4.3.2',
|
'beautifulsoup4==4.3.2',
|
||||||
|
|
Loading…
Reference in a new issue