mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2024-12-26 03:14:19 +00:00
Compare commits
3 Commits
82d6f6003f
...
cdf6f9fcfd
Author | SHA1 | Date | |
---|---|---|---|
|
cdf6f9fcfd | ||
|
268da220d2 | ||
|
84e1755a57 |
@ -5,9 +5,8 @@
|
|||||||
!app
|
!app
|
||||||
!migrations
|
!migrations
|
||||||
!tests
|
!tests
|
||||||
!.flaskenv
|
|
||||||
!boot.sh
|
!boot.sh
|
||||||
!config.py
|
!config.py
|
||||||
!docker-nopaque-entrypoint.sh
|
!docker-nopaque-entrypoint.sh
|
||||||
!nopaque.py
|
|
||||||
!requirements.txt
|
!requirements.txt
|
||||||
|
!wsgi.py
|
||||||
|
@ -46,7 +46,7 @@ COPY docker-nopaque-entrypoint.sh /usr/local/bin/
|
|||||||
COPY --chown=nopaque:nopaque app app
|
COPY --chown=nopaque:nopaque app app
|
||||||
COPY --chown=nopaque:nopaque migrations migrations
|
COPY --chown=nopaque:nopaque migrations migrations
|
||||||
COPY --chown=nopaque:nopaque tests tests
|
COPY --chown=nopaque:nopaque tests tests
|
||||||
COPY --chown=nopaque:nopaque .flaskenv boot.sh config.py nopaque.py requirements.txt ./
|
COPY --chown=nopaque:nopaque boot.sh config.py wsgi.py requirements.txt ./
|
||||||
|
|
||||||
RUN mkdir logs
|
RUN mkdir logs
|
||||||
|
|
||||||
|
@ -33,6 +33,9 @@ scheduler = APScheduler()
|
|||||||
socketio = SocketIO()
|
socketio = SocketIO()
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Create export for lemmatized corpora
|
||||||
|
|
||||||
|
|
||||||
def create_app(config: Config = Config) -> Flask:
|
def create_app(config: Config = Config) -> Flask:
|
||||||
''' Creates an initialized Flask (WSGI Application) object. '''
|
''' Creates an initialized Flask (WSGI Application) object. '''
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from flask import abort, request
|
from flask import abort, request
|
||||||
from app import db
|
|
||||||
from app.decorators import content_negotiation
|
from app.decorators import content_negotiation
|
||||||
|
from app import db
|
||||||
from app.models import User
|
from app.models import User
|
||||||
from . import bp
|
from . import bp
|
||||||
|
|
||||||
|
@ -9,12 +9,12 @@ from app.users.settings.forms import (
|
|||||||
UpdateAccountInformationForm,
|
UpdateAccountInformationForm,
|
||||||
UpdateProfileInformationForm
|
UpdateProfileInformationForm
|
||||||
)
|
)
|
||||||
from . import bp
|
|
||||||
from .forms import UpdateUserForm
|
|
||||||
from app.users.utils import (
|
from app.users.utils import (
|
||||||
user_endpoint_arguments_constructor as user_eac,
|
user_endpoint_arguments_constructor as user_eac,
|
||||||
user_dynamic_list_constructor as user_dlc
|
user_dynamic_list_constructor as user_dlc
|
||||||
)
|
)
|
||||||
|
from . import bp
|
||||||
|
from .forms import UpdateUserForm
|
||||||
|
|
||||||
|
|
||||||
@bp.route('')
|
@bp.route('')
|
||||||
|
@ -5,8 +5,8 @@ from flask import abort, Blueprint
|
|||||||
from werkzeug.exceptions import InternalServerError
|
from werkzeug.exceptions import InternalServerError
|
||||||
from app import db, hashids
|
from app import db, hashids
|
||||||
from app.models import Job, JobInput, JobStatus, TesseractOCRPipelineModel
|
from app.models import Job, JobInput, JobStatus, TesseractOCRPipelineModel
|
||||||
from .schemas import EmptySchema, JobSchema, SpaCyNLPPipelineJobSchema, TesseractOCRPipelineJobSchema, TesseractOCRPipelineModelSchema
|
|
||||||
from .auth import auth_error_responses, token_auth
|
from .auth import auth_error_responses, token_auth
|
||||||
|
from .schemas import EmptySchema, JobSchema, SpaCyNLPPipelineJobSchema, TesseractOCRPipelineJobSchema, TesseractOCRPipelineModelSchema
|
||||||
|
|
||||||
|
|
||||||
bp = Blueprint('jobs', __name__)
|
bp = Blueprint('jobs', __name__)
|
||||||
|
@ -3,11 +3,11 @@ from apifairy import authenticate, body, response
|
|||||||
from apifairy.decorators import other_responses
|
from apifairy.decorators import other_responses
|
||||||
from flask import abort, Blueprint
|
from flask import abort, Blueprint
|
||||||
from werkzeug.exceptions import InternalServerError
|
from werkzeug.exceptions import InternalServerError
|
||||||
from app import db
|
|
||||||
from app.email import create_message, send
|
from app.email import create_message, send
|
||||||
|
from app import db
|
||||||
from app.models import User
|
from app.models import User
|
||||||
from .schemas import EmptySchema, UserSchema
|
|
||||||
from .auth import auth_error_responses, token_auth
|
from .auth import auth_error_responses, token_auth
|
||||||
|
from .schemas import EmptySchema, UserSchema
|
||||||
|
|
||||||
|
|
||||||
bp = Blueprint('users', __name__)
|
bp = Blueprint('users', __name__)
|
||||||
|
@ -4,7 +4,7 @@ from threading import Thread
|
|||||||
from app import db
|
from app import db
|
||||||
from app.decorators import content_negotiation, permission_required
|
from app.decorators import content_negotiation, permission_required
|
||||||
from app.models import SpaCyNLPPipelineModel
|
from app.models import SpaCyNLPPipelineModel
|
||||||
from .. import bp
|
from . import bp
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>', methods=['DELETE'])
|
@bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>', methods=['DELETE'])
|
||||||
|
@ -8,9 +8,7 @@ from .forms import (
|
|||||||
CreateSpaCyNLPPipelineModelForm,
|
CreateSpaCyNLPPipelineModelForm,
|
||||||
UpdateSpaCyNLPPipelineModelForm
|
UpdateSpaCyNLPPipelineModelForm
|
||||||
)
|
)
|
||||||
from .utils import (
|
from .utils import spacy_nlp_pipeline_model_dlc
|
||||||
spacy_nlp_pipeline_model_dlc as spacy_nlp_pipeline_model_dlc
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/spacy-nlp-pipeline-models')
|
@bp.route('/spacy-nlp-pipeline-models')
|
||||||
|
@ -8,9 +8,7 @@ from .forms import (
|
|||||||
CreateTesseractOCRPipelineModelForm,
|
CreateTesseractOCRPipelineModelForm,
|
||||||
UpdateTesseractOCRPipelineModelForm
|
UpdateTesseractOCRPipelineModelForm
|
||||||
)
|
)
|
||||||
from .utils import (
|
from .utils import tesseract_ocr_pipeline_model_dlc
|
||||||
tesseract_ocr_pipeline_model_dlc as tesseract_ocr_pipeline_model_dlc
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/tesseract-ocr-pipeline-models')
|
@bp.route('/tesseract-ocr-pipeline-models')
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
from flask import current_app
|
|
||||||
from app import db
|
|
||||||
from app.models import User, Corpus, CorpusFile
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from flask import current_app
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
|
from app import db
|
||||||
|
from app.models import User, Corpus, CorpusFile
|
||||||
|
|
||||||
|
|
||||||
class SandpaperConverter:
|
class SandpaperConverter:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from flask import abort, current_app
|
from flask import current_app
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from app import db
|
|
||||||
from app.decorators import content_negotiation
|
from app.decorators import content_negotiation
|
||||||
|
from app import db
|
||||||
from app.models import CorpusFile
|
from app.models import CorpusFile
|
||||||
from ..decorators import corpus_follower_permission_required
|
from ..decorators import corpus_follower_permission_required
|
||||||
from . import bp
|
from . import bp
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
from flask import request, url_for
|
from flask import request, url_for
|
||||||
from app.models import CorpusFile
|
from app.models import CorpusFile
|
||||||
from ..utils import corpus_endpoint_arguments_constructor as corpus_eac
|
|
||||||
|
|
||||||
|
|
||||||
def corpus_file_dynamic_list_constructor():
|
def corpus_file_dynamic_list_constructor():
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
from .container_column import ContainerColumn
|
|
||||||
from .int_enum_column import IntEnumColumn
|
|
@ -1,21 +0,0 @@
|
|||||||
import json
|
|
||||||
from app import db
|
|
||||||
|
|
||||||
|
|
||||||
class ContainerColumn(db.TypeDecorator):
|
|
||||||
impl = db.String
|
|
||||||
|
|
||||||
def __init__(self, container_type, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.container_type = container_type
|
|
||||||
|
|
||||||
def process_bind_param(self, value, dialect):
|
|
||||||
if isinstance(value, self.container_type):
|
|
||||||
return json.dumps(value)
|
|
||||||
elif isinstance(value, str) and isinstance(json.loads(value), self.container_type):
|
|
||||||
return value
|
|
||||||
else:
|
|
||||||
return TypeError()
|
|
||||||
|
|
||||||
def process_result_value(self, value, dialect):
|
|
||||||
return json.loads(value)
|
|
1
app/extensions/__init__.py
Normal file
1
app/extensions/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
2
app/extensions/sqlalchemy/__init__.py
Normal file
2
app/extensions/sqlalchemy/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from .types import ContainerColumn
|
||||||
|
from .types import IntEnumColumn
|
@ -1,6 +1,26 @@
|
|||||||
|
import json
|
||||||
from app import db
|
from app import db
|
||||||
|
|
||||||
|
|
||||||
|
class ContainerColumn(db.TypeDecorator):
|
||||||
|
impl = db.String
|
||||||
|
|
||||||
|
def __init__(self, container_type, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.container_type = container_type
|
||||||
|
|
||||||
|
def process_bind_param(self, value, dialect):
|
||||||
|
if isinstance(value, self.container_type):
|
||||||
|
return json.dumps(value)
|
||||||
|
elif isinstance(value, str) and isinstance(json.loads(value), self.container_type):
|
||||||
|
return value
|
||||||
|
else:
|
||||||
|
return TypeError()
|
||||||
|
|
||||||
|
def process_result_value(self, value, dialect):
|
||||||
|
return json.loads(value)
|
||||||
|
|
||||||
|
|
||||||
class IntEnumColumn(db.TypeDecorator):
|
class IntEnumColumn(db.TypeDecorator):
|
||||||
impl = db.Integer
|
impl = db.Integer
|
||||||
|
|
@ -9,7 +9,7 @@ import shutil
|
|||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
from app import db
|
from app import db
|
||||||
from app.converters.vrt import normalize_vrt_file
|
from app.converters.vrt import normalize_vrt_file
|
||||||
from app.ext.flask_sqlalchemy import IntEnumColumn
|
from app.extensions.sqlalchemy import IntEnumColumn
|
||||||
from .corpus_follower_association import CorpusFollowerAssociation
|
from .corpus_follower_association import CorpusFollowerAssociation
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ from typing import Union
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import shutil
|
import shutil
|
||||||
from app import db
|
from app import db
|
||||||
from app.ext.flask_sqlalchemy import ContainerColumn, IntEnumColumn
|
from app.extensions.sqlalchemy import ContainerColumn, IntEnumColumn
|
||||||
|
|
||||||
|
|
||||||
class JobStatus(IntEnum):
|
class JobStatus(IntEnum):
|
||||||
|
@ -5,7 +5,7 @@ from pathlib import Path
|
|||||||
import requests
|
import requests
|
||||||
import yaml
|
import yaml
|
||||||
from app import db
|
from app import db
|
||||||
from app.ext.flask_sqlalchemy import ContainerColumn
|
from app.extensions.sqlalchemy import ContainerColumn
|
||||||
from .file_mixin import FileMixin
|
from .file_mixin import FileMixin
|
||||||
from .user import User
|
from .user import User
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ from pathlib import Path
|
|||||||
import requests
|
import requests
|
||||||
import yaml
|
import yaml
|
||||||
from app import db
|
from app import db
|
||||||
from app.ext.flask_sqlalchemy import ContainerColumn
|
from app.extensions.sqlalchemy import ContainerColumn
|
||||||
from .file_mixin import FileMixin
|
from .file_mixin import FileMixin
|
||||||
from .user import User
|
from .user import User
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import re
|
|||||||
import secrets
|
import secrets
|
||||||
import shutil
|
import shutil
|
||||||
from app import db, hashids
|
from app import db, hashids
|
||||||
from app.ext.flask_sqlalchemy import IntEnumColumn
|
from app.extensions.sqlalchemy import IntEnumColumn
|
||||||
from .corpus import Corpus
|
from .corpus import Corpus
|
||||||
from .corpus_follower_association import CorpusFollowerAssociation
|
from .corpus_follower_association import CorpusFollowerAssociation
|
||||||
from .corpus_follower_role import CorpusFollowerRole
|
from .corpus_follower_role import CorpusFollowerRole
|
||||||
|
57
app/static/js/forms/base-form-new.js
Normal file
57
app/static/js/forms/base-form-new.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
export class BaseForm {
|
||||||
|
constructor(formElement) {
|
||||||
|
this.element = formElement;
|
||||||
|
|
||||||
|
this.element.addEventListener('submit', (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
this.submit();
|
||||||
|
});
|
||||||
|
console.log("UsernamePostFormInitialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
submit() {
|
||||||
|
let errorTextElements = this.element
|
||||||
|
.querySelectorAll('.supporting-text[data-supporting-text-type="error"]');
|
||||||
|
for (let errorTextElement of errorTextElements) {errorTextElement.remove();}
|
||||||
|
|
||||||
|
const body = new FormData(this.element);
|
||||||
|
const headers = {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
};
|
||||||
|
const method = this.element.method;
|
||||||
|
|
||||||
|
const fetchPromise = new Promise((resolve, reject) => {
|
||||||
|
fetch(this.element.action, {body: body, headers: headers, method: method})
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
console.log("reject", response);
|
||||||
|
reject(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("resolve", response);
|
||||||
|
resolve(response);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
fetchPromise
|
||||||
|
.then(
|
||||||
|
(response) => {console.log("Hello from resolve handler");return response.json();},
|
||||||
|
(response) => {
|
||||||
|
console.log("Hello from reject handler 1/2");
|
||||||
|
response.json()
|
||||||
|
.then((errors) => {
|
||||||
|
console.log("Hello from reject handler 2/2");
|
||||||
|
for (let [name, messages] of Object.entries(errors)) {
|
||||||
|
console.log(name, messages);
|
||||||
|
const inputFieldElement = this.element[name].closest('.input-field');
|
||||||
|
for (let message of messages) {
|
||||||
|
const messageHTML = `<span class="supporting-text" data-supporting-text-type="error">${message}</span>`;
|
||||||
|
inputFieldElement.insertAdjacentHTML('beforeend', messageHTML);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
@ -1,4 +1,3 @@
|
|||||||
from flask_login import current_user
|
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from flask_wtf.file import FileField, FileRequired
|
from flask_wtf.file import FileField, FileRequired
|
||||||
from wtforms import (
|
from wtforms import (
|
||||||
@ -17,7 +16,7 @@ from wtforms.validators import (
|
|||||||
Regexp
|
Regexp
|
||||||
)
|
)
|
||||||
from app.models import User, UserSettingJobStatusMailNotificationLevel
|
from app.models import User, UserSettingJobStatusMailNotificationLevel
|
||||||
from app.wtforms.validators import FileSize
|
from app.extensions.wtforms.validators import FileSize
|
||||||
|
|
||||||
|
|
||||||
class UpdateAccountInformationForm(FlaskForm):
|
class UpdateAccountInformationForm(FlaskForm):
|
||||||
|
2
boot.sh
2
boot.sh
@ -24,7 +24,7 @@ if [[ "${#}" == "0" ]]; then
|
|||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
python3 nopaque.py
|
python3 wsgi.py
|
||||||
elif [[ "${1}" == "flask" ]]; then
|
elif [[ "${1}" == "flask" ]]; then
|
||||||
flask ${@:2}
|
flask ${@:2}
|
||||||
elif [[ "${1}" == "--help" || "${1}" == "-h" ]]; then
|
elif [[ "${1}" == "--help" || "${1}" == "-h" ]]; then
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
version: "3.5"
|
|
||||||
|
|
||||||
# The docker-compose.yml file is not meant to be modified itself.
|
# The docker-compose.yml file is not meant to be modified itself.
|
||||||
# Instead use the following files for configurations:
|
# Instead use the following files for configurations:
|
||||||
# - .env: Environment variables for the docker-compose.yml file.
|
# - .env: Environment variables for the docker-compose.yml file.
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
version: "3.5"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
nopaque:
|
nopaque:
|
||||||
environment:
|
environment:
|
||||||
@ -13,6 +11,6 @@ services:
|
|||||||
- "./config.py:/home/nopaque/config.py"
|
- "./config.py:/home/nopaque/config.py"
|
||||||
- "./docker-entrypoint.sh:/usr/local/bin/docker-entrypoint.sh"
|
- "./docker-entrypoint.sh:/usr/local/bin/docker-entrypoint.sh"
|
||||||
- "./migrations:/home/nopaque/migrations"
|
- "./migrations:/home/nopaque/migrations"
|
||||||
- "./nopaque.py:/home/nopaque/nopaque.py"
|
|
||||||
- "./requirements.txt:/home/nopaque/requirements.txt"
|
- "./requirements.txt:/home/nopaque/requirements.txt"
|
||||||
- "./tests:/home/nopaque/tests"
|
- "./tests:/home/nopaque/tests"
|
||||||
|
- "./wsgi.py:/home/nopaque/wsgi.py"
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
version: "3.5"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
nopaque:
|
nopaque:
|
||||||
environment:
|
environment:
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
version: "3.5"
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
traefik:
|
traefik:
|
||||||
external: true
|
external: true
|
||||||
|
@ -15,7 +15,7 @@ Flask-Marshmallow==0.14.0
|
|||||||
Flask-Menu==0.7.2
|
Flask-Menu==0.7.2
|
||||||
Flask-Migrate
|
Flask-Migrate
|
||||||
Flask-Paranoid
|
Flask-Paranoid
|
||||||
Flask-SocketIO
|
Flask-SocketIO==5.3.6
|
||||||
Flask-SQLAlchemy==2.5.1
|
Flask-SQLAlchemy==2.5.1
|
||||||
Flask-WTF
|
Flask-WTF
|
||||||
hiredis
|
hiredis
|
||||||
|
Loading…
Reference in New Issue
Block a user