mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2024-12-25 19:04:18 +00:00
Compare commits
5 Commits
a03b5918d9
...
4a29a52f2a
Author | SHA1 | Date | |
---|---|---|---|
|
4a29a52f2a | ||
|
991810cff5 | ||
|
6025a4a606 | ||
|
e1cfd394fa | ||
|
882987ba68 |
@ -1,4 +1,4 @@
|
||||
# from apifairy import APIFairy
|
||||
from apifairy import APIFairy
|
||||
from config import Config
|
||||
from docker import DockerClient
|
||||
from flask import Flask
|
||||
@ -6,7 +6,7 @@ from flask_apscheduler import APScheduler
|
||||
from flask_assets import Environment
|
||||
from flask_login import LoginManager
|
||||
from flask_mail import Mail
|
||||
# from flask_marshmallow import Marshmallow
|
||||
from flask_marshmallow import Marshmallow
|
||||
from flask_migrate import Migrate
|
||||
from flask_paranoid import Paranoid
|
||||
from flask_socketio import SocketIO
|
||||
@ -14,7 +14,7 @@ from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_hashids import Hashids
|
||||
|
||||
|
||||
# apifairy = APIFairy()
|
||||
apifairy = APIFairy()
|
||||
assets = Environment()
|
||||
db = SQLAlchemy()
|
||||
docker_client = DockerClient()
|
||||
@ -22,7 +22,7 @@ hashids = Hashids()
|
||||
login = LoginManager()
|
||||
login.login_view = 'auth.login'
|
||||
login.login_message = 'Please log in to access this page.'
|
||||
# ma = Marshmallow()
|
||||
ma = Marshmallow()
|
||||
mail = Mail()
|
||||
migrate = Migrate(compare_type=True)
|
||||
paranoid = Paranoid()
|
||||
@ -45,12 +45,12 @@ def create_app(config: Config = Config) -> Flask:
|
||||
registry=app.config['NOPAQUE_DOCKER_REGISTRY']
|
||||
)
|
||||
|
||||
# apifairy.init_app(app)
|
||||
apifairy.init_app(app)
|
||||
assets.init_app(app)
|
||||
db.init_app(app)
|
||||
hashids.init_app(app)
|
||||
login.init_app(app)
|
||||
# ma.init_app(app)
|
||||
ma.init_app(app)
|
||||
mail.init_app(app)
|
||||
migrate.init_app(app, db)
|
||||
paranoid.init_app(app)
|
||||
@ -63,8 +63,8 @@ def create_app(config: Config = Config) -> Flask:
|
||||
from .admin import bp as admin_blueprint
|
||||
app.register_blueprint(admin_blueprint, url_prefix='/admin')
|
||||
|
||||
# from .api import bp as api_blueprint
|
||||
# app.register_blueprint(api_blueprint, url_prefix='/api')
|
||||
from .api import bp as api_blueprint
|
||||
app.register_blueprint(api_blueprint, url_prefix='/api')
|
||||
|
||||
from .auth import bp as auth_blueprint
|
||||
app.register_blueprint(auth_blueprint)
|
||||
|
@ -1,7 +1,7 @@
|
||||
from flask_login import current_user
|
||||
from flask_socketio import disconnect, Namespace
|
||||
from app import db, hashids
|
||||
from app.extensions.flask_socketio_extras import admin_required
|
||||
from app.decorators import socketio_admin_required
|
||||
from app.models import User
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ class AdminNamespace(Namespace):
|
||||
disconnect()
|
||||
|
||||
|
||||
@admin_required
|
||||
@socketio_admin_required
|
||||
def on_set_user_confirmed(self, user_hashid: str, confirmed_value: bool):
|
||||
# Decode the user hashid
|
||||
user_id = hashids.decode(user_hashid)
|
||||
|
@ -9,7 +9,7 @@ from inspect import signature
|
||||
from threading import Lock
|
||||
from typing import Callable, Dict, List, Optional
|
||||
from app import db, docker_client, hashids, socketio
|
||||
from app.extensions.flask_socketio_extras import login_required
|
||||
from app.decorators import socketio_login_required
|
||||
from app.models import Corpus, CorpusStatus
|
||||
from . import extensions
|
||||
|
||||
@ -87,11 +87,11 @@ CQI_API_FUNCTION_NAMES: List[str] = [
|
||||
|
||||
|
||||
class CQiNamespace(Namespace):
|
||||
@login_required
|
||||
@socketio_login_required
|
||||
def on_connect(self):
|
||||
pass
|
||||
|
||||
@login_required
|
||||
@socketio_login_required
|
||||
def on_init(self, db_corpus_hashid: str):
|
||||
db_corpus_id: int = hashids.decode(db_corpus_hashid)
|
||||
db_corpus: Optional[Corpus] = Corpus.query.get(db_corpus_id)
|
||||
@ -134,7 +134,7 @@ class CQiNamespace(Namespace):
|
||||
}
|
||||
return {'code': 200, 'msg': 'OK'}
|
||||
|
||||
@login_required
|
||||
@socketio_login_required
|
||||
def on_exec(self, fn_name: str, fn_args: Dict = {}):
|
||||
try:
|
||||
cqi_client: CQiClient = session['cqi_over_sio']['cqi_client']
|
||||
|
@ -1,12 +1,12 @@
|
||||
from flask_login import current_user
|
||||
from flask_socketio import join_room
|
||||
from app import hashids, socketio
|
||||
from app.extensions.flask_socketio_extras import login_required
|
||||
from app.decorators import socketio_login_required
|
||||
from app.models import Corpus
|
||||
|
||||
|
||||
@socketio.on('GET /corpora/<corpus_id>')
|
||||
@login_required
|
||||
@socketio_login_required
|
||||
def get_corpus(corpus_hashid):
|
||||
corpus_id = hashids.decode(corpus_hashid)
|
||||
corpus = Corpus.query.get(corpus_id)
|
||||
@ -29,7 +29,7 @@ def get_corpus(corpus_hashid):
|
||||
|
||||
|
||||
@socketio.on('SUBSCRIBE /corpora/<corpus_id>')
|
||||
@login_required
|
||||
@socketio_login_required
|
||||
def subscribe_corpus(corpus_hashid):
|
||||
corpus_id = hashids.decode(corpus_hashid)
|
||||
corpus = Corpus.query.get(corpus_id)
|
||||
|
@ -1,7 +1,6 @@
|
||||
from flask import abort, current_app, request
|
||||
from flask import abort, request
|
||||
from flask_login import current_user
|
||||
from functools import wraps
|
||||
from threading import Thread
|
||||
from typing import List, Union
|
||||
from werkzeug.exceptions import NotAcceptable
|
||||
from app.models import Permission
|
||||
@ -22,22 +21,28 @@ def admin_required(f):
|
||||
return permission_required(Permission.ADMINISTRATE)(f)
|
||||
|
||||
|
||||
def background(f):
|
||||
'''
|
||||
' This decorator executes a function in a Thread.
|
||||
' Decorated functions need to be executed within a code block where an
|
||||
' app context exists.
|
||||
'
|
||||
' NOTE: An app object is passed as a keyword argument to the decorated
|
||||
' function.
|
||||
'''
|
||||
def socketio_login_required(f):
|
||||
@wraps(f)
|
||||
def wrapped(*args, **kwargs):
|
||||
kwargs['app'] = current_app._get_current_object()
|
||||
thread = Thread(target=f, args=args, kwargs=kwargs)
|
||||
thread.start()
|
||||
return thread
|
||||
return wrapped
|
||||
def wrapper(*args, **kwargs):
|
||||
if current_user.is_authenticated:
|
||||
return f(*args, **kwargs)
|
||||
return {'code': 401, 'body': 'Unauthorized'}
|
||||
return wrapper
|
||||
|
||||
|
||||
def socketio_permission_required(permission):
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def wrapper(*args, **kwargs):
|
||||
if not current_user.can(permission):
|
||||
return {'code': 403, 'body': 'Forbidden'}
|
||||
return f(*args, **kwargs)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
def socketio_admin_required(f):
|
||||
return socketio_permission_required(Permission.ADMINISTRATE)(f)
|
||||
|
||||
|
||||
def content_negotiation(
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -1,3 +0,0 @@
|
||||
from .decorators import login_required
|
||||
from .decorators import permission_required
|
||||
from .decorators import admin_required
|
@ -1,27 +0,0 @@
|
||||
from flask_login import current_user
|
||||
from functools import wraps
|
||||
from app.models import Permission as UserPermission
|
||||
|
||||
|
||||
def login_required(f):
|
||||
@wraps(f)
|
||||
def wrapper(*args, **kwargs):
|
||||
if current_user.is_authenticated:
|
||||
return f(*args, **kwargs)
|
||||
return {'code': 401, 'body': 'Unauthorized'}
|
||||
return wrapper
|
||||
|
||||
|
||||
def permission_required(permission):
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def wrapper(*args, **kwargs):
|
||||
if not current_user.can(permission):
|
||||
return {'code': 403, 'body': 'Forbidden'}
|
||||
return f(*args, **kwargs)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
def admin_required(f):
|
||||
return permission_required(UserPermission.ADMINISTRATE)(f)
|
@ -1,14 +0,0 @@
|
||||
from wtforms.validators import ValidationError
|
||||
|
||||
|
||||
def FileSize(max_size_mb):
|
||||
max_size_b = max_size_mb * 1024 * 1024
|
||||
|
||||
def file_length_check(form, field):
|
||||
if len(field.data.read()) >= max_size_b:
|
||||
raise ValidationError(
|
||||
f'File size must be less or equal than {max_size_mb} MB'
|
||||
)
|
||||
field.data.seek(0)
|
||||
|
||||
return file_length_check
|
@ -1,4 +1,4 @@
|
||||
<h3 class="manual-chapter-title">Services</h5>
|
||||
<h3 class="manual-chapter-title">Services</h3>
|
||||
<div class="row">
|
||||
<div class="col s12 m4">
|
||||
<img alt="Services" class="materialboxed responsive-img" src="{{ url_for('static', filename='images/manual/services.png') }}">
|
||||
|
2
app/templates/_base/metas.html.j2
Normal file
2
app/templates/_base/metas.html.j2
Normal file
@ -0,0 +1,2 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
@ -1,35 +1,39 @@
|
||||
<div class="navbar-fixed">
|
||||
<nav>
|
||||
<div class="nav-wrapper primary-color">
|
||||
{# menu icon #}
|
||||
{# shown for small/medium devices #}
|
||||
{% if current_user.is_authenticated %}
|
||||
<!-- menu icon -->
|
||||
<!-- small/medium devices -->
|
||||
<a href="#!" class="sidenav-trigger" data-target="sidenav"><i class="material-icons">menu</i></a>
|
||||
{% endif %}
|
||||
|
||||
{# nopaque logo+wordmark #}
|
||||
<a href="{{ url_for('main.index') }}" class="brand-logo center" style="height: 100%;">
|
||||
<!-- nopaque logo+wordmark -->
|
||||
<!-- small/medium devices -->
|
||||
<a href="{{ url_for('main.index') }}" class="brand-logo center hide-on-large-only" style="height: 100%;">
|
||||
<img src="{{ url_for('static', filename='images/nopaque_-_logo+wordmark.png') }}" alt="" class="py-3" style="height: 100%;">
|
||||
</a>
|
||||
<!-- large devices -->
|
||||
<a href="{{ url_for('main.index') }}" class="brand-logo hide-on-med-and-down" style="height: 100%;">
|
||||
<img src="{{ url_for('static', filename='images/nopaque_-_logo+wordmark.png') }}" alt="" class="p-3" style="height: 100%;">
|
||||
</a>
|
||||
|
||||
{# right items #}
|
||||
{# shown on large devices #}
|
||||
<!-- right aligned navigation links -->
|
||||
<!-- large devices -->
|
||||
<ul class="right hide-on-med-and-down" style="height: 100%;">
|
||||
{% if current_user.is_authenticated %}
|
||||
{# avatar, username and email #}
|
||||
{# shown for authenticated users #}
|
||||
<!-- avatar, username and email -->
|
||||
<li style="height: 100%;">
|
||||
<a href="#!" class="dropdown-trigger no-autoinit" data-target="nav-account-dropdown-content" id="nav-account-dropdown-trigger" style="height: 100%;">
|
||||
<img src="{{ url_for('users.user_avatar', user_id=current_user.id) }}" alt="" class="left circle py-3 mr-1" style="height: 100%;">
|
||||
{{ current_user.username }} ({{ current_user.email }})
|
||||
<img src="{{ url_for('users.user_avatar', user_id=current_user.id) }}" alt="" class="left circle py-3" style="height: 100%;">
|
||||
<span class="ml-1">{{ current_user.username }} ({{ current_user.email }})</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
{# log in and register items #}
|
||||
{# shown for unauthenticated users on all devices #}
|
||||
<!-- log in -->
|
||||
<li {% if request.path == url_for('auth.login') %}class="active"{% endif %}>
|
||||
<a href="{{ url_for('auth.login') }}"><i class="material-icons left">login</i>Log in</a>
|
||||
</li>
|
||||
<!-- register -->
|
||||
<li {% if request.path == url_for('auth.register') %}class="active"{% endif %}>
|
||||
<a href="{{ url_for('auth.register') }}"><i class="material-icons left">assignment</i>Register</a>
|
||||
</li>
|
||||
|
@ -1,20 +1,20 @@
|
||||
<script src="{{ url_for('static', filename='external/materialize/js/materialize.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='external/JSON-Patch/js/fast-json-patch.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='external/list.js/js/list.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='external/pako/js/pako_inflate.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='external/plotly.js/js/plotly.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='external/socket.io/js/socket.io.min.js') }}"></script>
|
||||
|
||||
{%- assets
|
||||
{% assets
|
||||
filters='rjsmin',
|
||||
output='gen/app.%(version)s.js',
|
||||
'js/index.js',
|
||||
'js/app.js',
|
||||
'js/utils.js'
|
||||
%}
|
||||
-%}
|
||||
<script src="{{ ASSET_URL }}"></script>
|
||||
{%- endassets %}
|
||||
{% endassets -%}
|
||||
|
||||
{%- assets
|
||||
{% assets
|
||||
filters='rjsmin',
|
||||
output='gen/Forms.%(version)s.js',
|
||||
'js/forms/index.js',
|
||||
@ -22,22 +22,22 @@
|
||||
'js/forms/create-contribution-form.js',
|
||||
'js/forms/create-corpus-file-form.js',
|
||||
'js/forms/create-job-form.js'
|
||||
%}
|
||||
-%}
|
||||
<script src="{{ ASSET_URL }}"></script>
|
||||
{%- endassets %}
|
||||
{% endassets -%}
|
||||
|
||||
{%- assets
|
||||
{% assets
|
||||
filters='rjsmin',
|
||||
output='gen/resource-displays.%(version)s.js',
|
||||
'js/resource-displays/index.js',
|
||||
'js/resource-displays/resource-display.js',
|
||||
'js/resource-displays/corpus-display.js',
|
||||
'js/resource-displays/job-display.js'
|
||||
%}
|
||||
-%}
|
||||
<script src="{{ ASSET_URL }}"></script>
|
||||
{%- endassets %}
|
||||
{% endassets -%}
|
||||
|
||||
{%- assets
|
||||
{% assets
|
||||
filters='rjsmin',
|
||||
output='gen/resource-lists.%(version)s.js',
|
||||
'js/resource-lists/index.js',
|
||||
@ -56,11 +56,11 @@
|
||||
'js/resource-lists/public-user-list.js',
|
||||
'js/resource-lists/spacy-nlp-pipeline-model-list.js',
|
||||
'js/resource-lists/tesseract-ocr-pipeline-model-list.js'
|
||||
%}
|
||||
-%}
|
||||
<script src="{{ ASSET_URL }}"></script>
|
||||
{%- endassets %}
|
||||
{% endassets -%}
|
||||
|
||||
{%- assets
|
||||
{% assets
|
||||
filters='rjsmin',
|
||||
output='gen/requests.%(version)s.js',
|
||||
'js/requests/index.js',
|
||||
@ -69,11 +69,11 @@
|
||||
'js/requests/corpora.js',
|
||||
'js/requests/jobs.js',
|
||||
'js/requests/users.js'
|
||||
%}
|
||||
-%}
|
||||
<script src="{{ ASSET_URL }}"></script>
|
||||
{%- endassets %}
|
||||
{% endassets -%}
|
||||
|
||||
{%- assets
|
||||
{% assets
|
||||
filters='rjsmin',
|
||||
output='gen/corpus-analysis.%(version)s.js',
|
||||
'js/corpus-analysis/index.js',
|
||||
@ -98,17 +98,16 @@
|
||||
'js/corpus-analysis/concordance-extension.js',
|
||||
'js/corpus-analysis/reader-extension.js',
|
||||
'js/corpus-analysis/static-visualization-extension.js'
|
||||
%}
|
||||
-%}
|
||||
<script src="{{ ASSET_URL }}"></script>
|
||||
{%- endassets %}
|
||||
{% endassets -%}
|
||||
|
||||
<script>
|
||||
// TODO: Implement an app.run method and use this for all of the following
|
||||
const app = new nopaque.App();
|
||||
app.init();
|
||||
|
||||
// Check if the current user is authenticated
|
||||
{%- if current_user.is_authenticated %}
|
||||
{% if current_user.is_authenticated -%}
|
||||
// TODO: Set this as a property of the app object
|
||||
const currentUserId = {{ current_user.hashid|tojson }};
|
||||
|
||||
@ -120,11 +119,10 @@
|
||||
app.getUser(currentUserId, true, true)
|
||||
.catch((error) => {throw JSON.stringify(error);});
|
||||
|
||||
// Check if the current user hasn't accepted the terms of use yet
|
||||
{%- if not current_user.terms_of_use_accepted %}
|
||||
{% if not current_user.terms_of_use_accepted -%}
|
||||
M.Modal.getInstance(document.querySelector('#terms-of-use-modal')).open();
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{% endif -%}
|
||||
{% endif -%}
|
||||
|
||||
// Display flashed messages
|
||||
for (let [category, message] of {{ get_flashed_messages(with_categories=True)|tojson }}) {
|
||||
|
@ -11,11 +11,11 @@
|
||||
</li>
|
||||
|
||||
{# general items #}
|
||||
{# {% if current_user.can('USE_API') %}
|
||||
{% if current_user.can('USE_API') %}
|
||||
<li>
|
||||
<a class="waves-effect" href="{{ url_for('apifairy.docs') }}"><i class="material-icons">api</i>API</a>
|
||||
</li>
|
||||
{% endif %} #}
|
||||
{% endif %}
|
||||
<li>
|
||||
<a class="waves-effect modal-trigger" href="#manual-modal"><i class="material-icons">school</i>Manual</a>
|
||||
</li>
|
||||
|
@ -1,16 +1,18 @@
|
||||
{% if current_user.is_authenticated %}
|
||||
<link href="{{ url_for('static', filename='external/material-design-icons/css/material-icons.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='external/materialize/css/materialize.min.css') }}" rel="stylesheet">
|
||||
{% if current_user.is_authenticated -%}
|
||||
<link href="{{ url_for('static', filename='materialize/css/sidenav-fixed.css') }}" rel="stylesheet">
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
<link href="{{ url_for('static', filename='materialize/css/sticky-footer.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='materialize/css/fixes.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='nopaque-icons/css/nopaque-icons.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/queryBuilder.css') }}" rel="stylesheet">
|
||||
{%- assets
|
||||
{% assets
|
||||
filters='pyscss',
|
||||
output='gen/app.%(version)s.css',
|
||||
'css/colors.scss',
|
||||
'css/helpers.scss',
|
||||
'css/style.css'
|
||||
%}
|
||||
-%}
|
||||
<link href="{{ ASSET_URL }}" rel="stylesheet">
|
||||
{%- endassets %}
|
||||
{% endassets -%}
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="container">
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
|
||||
{% block page_content %}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
|
||||
{% block page_content %}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="container">
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="container">
|
||||
|
@ -1,60 +1,72 @@
|
||||
{% extends "materialize/base.html.j2" %}
|
||||
|
||||
{% if title is not defined %}
|
||||
{% set title = 'nopaque' %}
|
||||
{% endif %}
|
||||
|
||||
{% block html_attribs %}lang="en"{% endblock html_attribs %}
|
||||
{% block doc %}
|
||||
<!DOCTYPE html>
|
||||
<html {% block html_attribs %}lang="en"{% endblock html_attribs %}>
|
||||
{% block html %}
|
||||
<head>
|
||||
{% block head %}
|
||||
{% block metas %}
|
||||
{% include "_base/metas.html.j2" %}
|
||||
{% endblock metas %}
|
||||
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<link href="{{ url_for('static', filename='images/nopaque_-_favicon.png') }}" rel="icon">
|
||||
{% endblock head %}
|
||||
<title {% block title_attribs %}{% endblock title_attribs %}>
|
||||
{%- block title %}{{ title }}{% endblock title -%}
|
||||
</title>
|
||||
|
||||
{% block metas %}
|
||||
<meta charset="UTF-8">
|
||||
{{ super() }}
|
||||
{% endblock metas %}
|
||||
<link href="{{ url_for('static', filename='images/nopaque_-_favicon.png') }}" rel="icon">
|
||||
|
||||
{% block title %}{{ title }}{% endblock title %}
|
||||
{% block stylesheets %}
|
||||
{% include "_base/stylesheets.html.j2" %}
|
||||
{% endblock stylesheets %}
|
||||
{% endblock head %}
|
||||
</head>
|
||||
<body {% block body_attribs %}{% endblock body_attribs %}>
|
||||
{% block body %}
|
||||
<header {% block header_attribs %}{% endblock header_attribs %}>
|
||||
{% block header %}
|
||||
{% block navbar %}
|
||||
{% include "_base/navbar.html.j2" %}
|
||||
{% endblock navbar %}
|
||||
{% block sidenav %}
|
||||
{% if current_user.is_authenticated %}
|
||||
{% include "_base/sidenav.html.j2" %}
|
||||
{% endif %}
|
||||
{% endblock sidenav %}
|
||||
{% endblock header %}
|
||||
</header>
|
||||
|
||||
{% block styles %}
|
||||
{{ super() }}
|
||||
{% include "_base/styles.html.j2" %}
|
||||
{% endblock styles %}
|
||||
<main {% block main_attribs %}class="background-color"{% endblock main_attribs %}>
|
||||
{% block main %}
|
||||
{% block page_content %}{% endblock page_content %}
|
||||
|
||||
{% block navbar %}
|
||||
{% include "_base/navbar.html.j2" %}
|
||||
{% endblock navbar %}
|
||||
<div id="dropdowns">
|
||||
{% block dropdowns %}
|
||||
{% include "_base/dropdowns.html.j2" %}
|
||||
{% endblock dropdowns %}
|
||||
</div>
|
||||
|
||||
{% block sidenav %}
|
||||
{% if current_user.is_authenticated %}
|
||||
{% include "_base/sidenav.html.j2" %}
|
||||
{% endif %}
|
||||
{% endblock sidenav %}
|
||||
<div id="modals">
|
||||
{% block modals %}
|
||||
{% include "_base/modals.html.j2" %}
|
||||
{% endblock modals %}
|
||||
</div>
|
||||
{% endblock main %}
|
||||
</main>
|
||||
|
||||
{% block main_attribs %} class="background-color"{% endblock main_attribs %}
|
||||
{% block main %}
|
||||
{% block page_content %}{% endblock page_content %}
|
||||
<div id="dropdowns">
|
||||
{% block dropdowns %}
|
||||
{% include "_base/dropdowns.html.j2" %}
|
||||
{% endblock dropdowns %}
|
||||
</div>
|
||||
<footer {% block footer_attribs %}class="page-footer primary-variant-color"{% endblock footer_attribs %}>
|
||||
{% block footer %}
|
||||
{% include "_base/footer.html.j2" %}
|
||||
{% endblock footer %}
|
||||
</footer>
|
||||
|
||||
<div id="modals">
|
||||
{% block modals %}
|
||||
{% include "_base/modals.html.j2" %}
|
||||
{% endblock modals %}
|
||||
</div>
|
||||
{% endblock main %}
|
||||
|
||||
{% block footer_attribs %} class="page-footer primary-variant-color"{% endblock footer_attribs %}
|
||||
{% block footer %}
|
||||
{% include "_base/footer.html.j2" %}
|
||||
{% endblock footer %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
{% include "_base/scripts.html.j2" %}
|
||||
{% endblock scripts %}
|
||||
{% block scripts %}
|
||||
{% include "_base/scripts.html.j2" %}
|
||||
{% endblock scripts %}
|
||||
{% endblock body %}
|
||||
</body>
|
||||
{% endblock html %}
|
||||
</html>
|
||||
{% endblock doc %}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="spacy-nlp-pipeline"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="spacy-nlp-pipeline"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="container">
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="tesseract-ocr-pipeline"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="tesseract-ocr-pipeline"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="container">
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
{% import 'corpora/_analysis/concordance.html.j2' as concordance_extension %}
|
||||
{% import 'corpora/_analysis/reader.html.j2' as reader_extension %}
|
||||
{% import 'corpora/_analysis/static_visualization.html.j2' as static_visualization_extension %}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="parallax-container" id="title">
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="social-area-color-lighten" {% endblock main_attribs %}
|
||||
|
||||
|
@ -1,49 +0,0 @@
|
||||
{% if title is not defined %}
|
||||
{% set title = 'Title' %}
|
||||
{% endif %}
|
||||
|
||||
{% block doc %}
|
||||
<!DOCTYPE html>
|
||||
<html {% block html_attribs %}{% endblock html_attribs %}>
|
||||
{% block html %}
|
||||
<head>
|
||||
{% block head %}
|
||||
<title>{% block title %}{{ title }}{% endblock title %}</title>
|
||||
|
||||
{% block metas %}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% endblock metas %}
|
||||
|
||||
{% block styles %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='external/material-design-icons/css/material-icons.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='external/materialize/css/materialize.min.css') }}">
|
||||
{% endblock styles %}
|
||||
{% endblock head %}
|
||||
</head>
|
||||
<body {% block body_attribs %}{% endblock body_attribs %}>
|
||||
{% block body %}
|
||||
<header {% block header_attribs %}{% endblock header_attribs %}>
|
||||
{% block header %}
|
||||
{% block navbar %}
|
||||
{% endblock navbar %}
|
||||
{% block sidenav %}
|
||||
{% endblock sidenav %}
|
||||
{% endblock header %}
|
||||
</header>
|
||||
|
||||
<main {% block main_attribs %}{% endblock main_attribs %}>
|
||||
{% block main %}{% endblock main %}
|
||||
</main>
|
||||
|
||||
<footer {% block footer_attribs %}{% endblock footer_attribs %}>
|
||||
{% block footer %}{% endblock footer %}
|
||||
</footer>
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='external/materialize/js/materialize.min.js') }}"></script>
|
||||
{% endblock scripts %}
|
||||
{% endblock body %}
|
||||
</body>
|
||||
{% endblock html %}
|
||||
</html>
|
||||
{% endblock doc %}
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="file-setup-pipeline"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="spacy-nlp-pipeline"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="tesseract-ocr-pipeline"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} class="service-scheme" data-service="transkribus-htr-pipeline"{% endblock main_attribs %}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="section container">
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
{% import "wtf.html.j2" as wtf %}
|
||||
|
||||
|
||||
{% block page_content %}
|
||||
|
@ -1,12 +1,12 @@
|
||||
from flask_login import current_user
|
||||
from flask_socketio import join_room, leave_room
|
||||
from app import hashids, socketio
|
||||
from app.extensions.flask_socketio_extras import login_required
|
||||
from app.decorators import socketio_login_required
|
||||
from app.models import User
|
||||
|
||||
|
||||
@socketio.on('GET /users/<user_id>')
|
||||
@login_required
|
||||
@socketio_login_required
|
||||
def get_user(user_hashid):
|
||||
user_id = hashids.decode(user_hashid)
|
||||
user = User.query.get(user_id)
|
||||
@ -22,7 +22,7 @@ def get_user(user_hashid):
|
||||
|
||||
|
||||
@socketio.on('SUBSCRIBE /users/<user_id>')
|
||||
@login_required
|
||||
@socketio_login_required
|
||||
def subscribe_user(user_hashid):
|
||||
user_id = hashids.decode(user_hashid)
|
||||
user = User.query.get(user_id)
|
||||
@ -35,7 +35,7 @@ def subscribe_user(user_hashid):
|
||||
|
||||
|
||||
@socketio.on('UNSUBSCRIBE /users/<user_id>')
|
||||
@login_required
|
||||
@socketio_login_required
|
||||
def unsubscribe_user(user_hashid):
|
||||
user_id = hashids.decode(user_hashid)
|
||||
user = User.query.get(user_id)
|
||||
|
@ -1,12 +1,12 @@
|
||||
from flask_login import current_user
|
||||
from flask_socketio import join_room
|
||||
from app import hashids, socketio
|
||||
from app.extensions.flask_socketio_extras import admin_required, login_required
|
||||
from app.decorators import socketio_admin_required, socketio_login_required
|
||||
from app.models import User
|
||||
|
||||
|
||||
@socketio.on('GET /users')
|
||||
@admin_required
|
||||
@socketio_admin_required
|
||||
def get_users():
|
||||
users = User.query.filter_by().all()
|
||||
return {
|
||||
@ -20,14 +20,14 @@ def get_users():
|
||||
|
||||
|
||||
@socketio.on('SUBSCRIBE /users')
|
||||
@admin_required
|
||||
@socketio_admin_required
|
||||
def subscribe_users():
|
||||
join_room('/users')
|
||||
return {'options': {'status': 200, 'statusText': 'OK'}}
|
||||
|
||||
|
||||
@socketio.on('GET /users/<user_id>')
|
||||
@login_required
|
||||
@socketio_login_required
|
||||
def get_user(user_hashid):
|
||||
user_id = hashids.decode(user_hashid)
|
||||
user = User.query.get(user_id)
|
||||
@ -46,7 +46,7 @@ def get_user(user_hashid):
|
||||
|
||||
|
||||
@socketio.on('SUBSCRIBE /users/<user_id>')
|
||||
@login_required
|
||||
@socketio_login_required
|
||||
def subscribe_user(user_hashid):
|
||||
user_id = hashids.decode(user_hashid)
|
||||
user = User.query.get(user_id)
|
||||
@ -59,7 +59,7 @@ def subscribe_user(user_hashid):
|
||||
|
||||
|
||||
@socketio.on('GET /public_users')
|
||||
@login_required
|
||||
@socketio_login_required
|
||||
def get_public_users():
|
||||
users = User.query.filter_by(is_public=True).all()
|
||||
return {
|
||||
@ -76,14 +76,14 @@ def get_public_users():
|
||||
|
||||
|
||||
@socketio.on('SUBSCRIBE /users')
|
||||
@admin_required
|
||||
@socketio_admin_required
|
||||
def subscribe_users():
|
||||
join_room('/public_users')
|
||||
return {'options': {'status': 200, 'statusText': 'OK'}}
|
||||
|
||||
|
||||
@socketio.on('GET /public_users/<user_id>')
|
||||
@login_required
|
||||
@socketio_login_required
|
||||
def get_user(user_hashid):
|
||||
user_id = hashids.decode(user_hashid)
|
||||
user = User.query.filter_by(id=user_id, is_public=True).first()
|
||||
@ -102,7 +102,7 @@ def get_user(user_hashid):
|
||||
|
||||
|
||||
@socketio.on('SUBSCRIBE /public_users/<user_id>')
|
||||
@login_required
|
||||
@socketio_login_required
|
||||
def subscribe_user(user_hashid):
|
||||
user_id = hashids.decode(user_hashid)
|
||||
user = User.query.filter_by(id=user_id, is_public=True).first()
|
||||
|
@ -1,5 +1,5 @@
|
||||
from flask_wtf import FlaskForm
|
||||
from flask_wtf.file import FileField, FileRequired
|
||||
from flask_wtf.file import FileField, FileRequired, FileSize
|
||||
from wtforms import (
|
||||
PasswordField,
|
||||
SelectField,
|
||||
@ -16,7 +16,6 @@ from wtforms.validators import (
|
||||
Regexp
|
||||
)
|
||||
from app.models import User, UserSettingJobStatusMailNotificationLevel
|
||||
from app.extensions.wtforms_extras.validators import FileSize
|
||||
|
||||
|
||||
class UpdateAccountInformationForm(FlaskForm):
|
||||
@ -99,7 +98,7 @@ class UpdateProfileInformationForm(FlaskForm):
|
||||
|
||||
|
||||
class UpdateAvatarForm(FlaskForm):
|
||||
avatar = FileField('File', validators=[FileRequired(), FileSize(2)])
|
||||
avatar = FileField('File', validators=[FileRequired(), FileSize(2_000_000)])
|
||||
submit = SubmitField()
|
||||
|
||||
def validate_avatar(self, field):
|
||||
|
@ -20,7 +20,7 @@ Flask-Hashids==1.0.3
|
||||
Flask-HTTPAuth==4.8.0
|
||||
Flask-Login==0.6.3
|
||||
Flask-Mail==0.9.1
|
||||
flask-marshmallow==1.2.1
|
||||
flask-marshmallow==0.14.0
|
||||
Flask-Migrate==4.0.7
|
||||
Flask-Paranoid==0.3.0
|
||||
Flask-SocketIO==5.3.6
|
||||
@ -36,6 +36,7 @@ joblib==1.4.0
|
||||
Mako==1.3.3
|
||||
MarkupSafe==2.1.5
|
||||
marshmallow==3.21.1
|
||||
marshmallow-sqlalchemy==1.0.0
|
||||
nltk==3.8.1
|
||||
packaging==24.0
|
||||
psycopg2==2.9.9
|
||||
@ -53,7 +54,7 @@ requests==2.31.0
|
||||
simple-websocket==1.0.0
|
||||
six==1.16.0
|
||||
SQLAlchemy==1.4.52
|
||||
tqdm==4.66.2
|
||||
tqdm==4.66.4
|
||||
typing_extensions==4.11.0
|
||||
tzlocal==5.2
|
||||
urllib3==2.2.1
|
||||
|
@ -7,16 +7,16 @@ Flask==2.3.3
|
||||
Flask-APScheduler
|
||||
Flask-Assets
|
||||
Flask-Hashids
|
||||
# Flask-HTTPAuth
|
||||
Flask-HTTPAuth
|
||||
Flask-Login
|
||||
Flask-Mail
|
||||
# flask-marshmallow
|
||||
flask-marshmallow==0.14.0
|
||||
Flask-Migrate
|
||||
Flask-Paranoid
|
||||
Flask-SocketIO
|
||||
Flask-SQLAlchemy==2.5.1
|
||||
Flask-WTF
|
||||
# marshmallow-sqlalchemy
|
||||
marshmallow-sqlalchemy
|
||||
nltk
|
||||
psycopg2
|
||||
PyJWT
|
||||
|
Loading…
Reference in New Issue
Block a user