tg-prepare 1.1.0__py3-none-any.whl → 2.1.0b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of tg-prepare might be problematic. Click here for more details.
- {tg_prepare-1.1.0.dist-info → tg_prepare-2.1.0b2.dist-info}/METADATA +3 -3
- tg_prepare-2.1.0b2.dist-info/RECORD +78 -0
- {tg_prepare-1.1.0.dist-info → tg_prepare-2.1.0b2.dist-info}/WHEEL +1 -1
- tg_prepare-2.1.0b2.dist-info/projects/.secret_key +1 -0
- tgp_backend/__init__.py +3 -4
- tgp_backend/config.py +31 -0
- tgp_backend/directories.py +6 -8
- tgp_backend/nextcloud.py +40 -19
- tgp_backend/project.py +172 -45
- tgp_backend/session_manager.py +47 -0
- tgp_backend/util.py +73 -25
- tgp_ui/app.py +43 -335
- tgp_ui/routes/__init__.py +0 -0
- tgp_ui/routes/collection.py +272 -0
- tgp_ui/routes/data.py +228 -0
- tgp_ui/routes/project.py +102 -0
- tgp_ui/routes/publication.py +129 -0
- tgp_ui/routes/tabs.py +34 -0
- tgp_ui/routes/views.py +62 -0
- tgp_ui/static/css/bootstrap.min.css.map +1 -0
- tgp_ui/static/css/navbar.css +92 -0
- tgp_ui/static/img/favicon.ico +0 -0
- tgp_ui/static/img/textgrid-logo.svg +1 -0
- tgp_ui/static/js/collectionManager.js +60 -0
- tgp_ui/static/js/fileManager.js +186 -0
- tgp_ui/static/js/main.js +32 -485
- tgp_ui/static/js/modalManager.js +105 -0
- tgp_ui/static/js/navbarManager.js +151 -0
- tgp_ui/static/js/projectManager.js +60 -0
- tgp_ui/static/js/require.js +5 -0
- tgp_ui/static/js/sidebarManager.js +32 -0
- tgp_ui/static/js/tabManager.js +79 -0
- tgp_ui/templates/details/empty_container.html +16 -0
- tgp_ui/templates/details/manage_collection.html +205 -0
- tgp_ui/templates/includes/set_session_id_form.html +16 -0
- tgp_ui/templates/includes/upload_form.html +131 -0
- tgp_ui/templates/layout.html +9 -48
- tgp_ui/templates/macros.html +79 -72
- tgp_ui/templates/modal/delete_project.html +25 -0
- tgp_ui/templates/modal/empty_container.html +9 -0
- tgp_ui/templates/modal/file_explorer_content.html +34 -0
- tgp_ui/templates/modal/file_explorer_main.html +22 -0
- tgp_ui/templates/modal/file_explorer_nextcloud.html +27 -0
- tgp_ui/templates/modal/github_modal.html +29 -0
- tgp_ui/templates/modal/nextcloud_login.html +48 -0
- tgp_ui/templates/modal/tei_explorer.html +58 -0
- tgp_ui/templates/modal/xpath_parser.html +52 -0
- tgp_ui/templates/project_main.html +36 -0
- tgp_ui/templates/project_navbar.html +81 -0
- tgp_ui/templates/{projects.html → projects_main.html} +13 -28
- tgp_ui/templates/tab_final_upload.html +29 -0
- tgp_ui/templates/tabs/check_result.html +90 -0
- tgp_ui/templates/tabs/edit_project.html +113 -0
- tgp_ui/templates/tabs/empty_container.html +12 -0
- tgp_ui/templates/tabs/import_data.html +138 -0
- tgp_ui/templates/tabs/manage_collections.html +88 -0
- tgp_ui/templates/tabs/select_directories.html +41 -0
- tgp_ui/templates/tabs/upload.html +42 -0
- tgp_ui/templates/tabs/validate_metadata.html +227 -0
- tg_prepare-1.1.0.dist-info/RECORD +0 -39
- tgp_ui/templates/collection.html +0 -194
- tgp_ui/templates/file_upload.html +0 -24
- tgp_ui/templates/nxc_file_tree.html +0 -33
- tgp_ui/templates/project.html +0 -26
- tgp_ui/templates/storage.html +0 -49
- tgp_ui/templates/tei_explorer.html +0 -48
- tgp_ui/templates/xpath_parser_modal_content.html +0 -37
- {tg_prepare-1.1.0.dist-info → tg_prepare-2.1.0b2.dist-info}/entry_points.txt +0 -0
- {tg_prepare-1.1.0.dist-info → tg_prepare-2.1.0b2.dist-info}/licenses/LICENSE +0 -0
- {tg_prepare-1.1.0.dist-info → tg_prepare-2.1.0b2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (C) 2023-2025 TU-Dresden (ZIH)
|
|
3
|
+
# ralf.klammer@tu-dresden.de
|
|
4
|
+
# moritz.wilhelm@tu-dresden.de
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
log = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SessionManager:
|
|
12
|
+
def __init__(self, session):
|
|
13
|
+
self.session = session
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SessionManagerNextcloud(SessionManager):
|
|
17
|
+
|
|
18
|
+
def save_credentials(self, form_data):
|
|
19
|
+
log.info("Saving credentials to session")
|
|
20
|
+
self.session["nextcloud"] = {
|
|
21
|
+
"username": form_data.get("nextcloud_user"),
|
|
22
|
+
"password": form_data.get("nextcloud_password"),
|
|
23
|
+
"url": form_data.get("nextcloud_url"),
|
|
24
|
+
"folder": form_data.get("nextcloud_folder", ""),
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
def get_credentials(self):
|
|
28
|
+
log.info("Retrieving credentials from session")
|
|
29
|
+
return self.session.get("nextcloud", {})
|
|
30
|
+
|
|
31
|
+
def delete_nextcloud_credentials(self):
|
|
32
|
+
log.info("Deleting credentials from session")
|
|
33
|
+
self.session.pop("nextcloud", None)
|
|
34
|
+
|
|
35
|
+
def request_has_valid_credentials(self, request):
|
|
36
|
+
"""
|
|
37
|
+
Check if the request contains valid Nextcloud credentials.
|
|
38
|
+
"""
|
|
39
|
+
relevant_form_keys = [
|
|
40
|
+
"nextcloud_url",
|
|
41
|
+
"nextcloud_user",
|
|
42
|
+
"nextcloud_password",
|
|
43
|
+
]
|
|
44
|
+
relevant_form_values = [
|
|
45
|
+
request.form.get(key) for key in relevant_form_keys
|
|
46
|
+
]
|
|
47
|
+
return all(relevant_form_values)
|
tgp_backend/util.py
CHANGED
|
@@ -6,27 +6,21 @@ import logging
|
|
|
6
6
|
import os
|
|
7
7
|
import re
|
|
8
8
|
|
|
9
|
-
from
|
|
9
|
+
from collections import defaultdict
|
|
10
|
+
|
|
11
|
+
from .config import get_config_value
|
|
10
12
|
|
|
11
13
|
log = logging.getLogger(__name__)
|
|
12
14
|
|
|
13
15
|
|
|
14
|
-
def config(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if not config_val:
|
|
23
|
-
log.info(
|
|
24
|
-
"Parameter: %s not in section: (%s) of *.ini -> using default: %s"
|
|
25
|
-
% (parameter, section, default)
|
|
26
|
-
)
|
|
27
|
-
return default
|
|
28
|
-
else:
|
|
29
|
-
return config_val
|
|
16
|
+
def config(*args, **kwargs):
|
|
17
|
+
log.warning(
|
|
18
|
+
"""
|
|
19
|
+
Using deprecated config function.
|
|
20
|
+
Please use tgp_backend.config.get_config_value instead.
|
|
21
|
+
"""
|
|
22
|
+
)
|
|
23
|
+
return get_config_value(*args, **kwargs)
|
|
30
24
|
|
|
31
25
|
|
|
32
26
|
def cli_startup(log_level=logging.INFO, log_file=None):
|
|
@@ -48,7 +42,9 @@ def get_file_extension(fname):
|
|
|
48
42
|
return ""
|
|
49
43
|
|
|
50
44
|
|
|
51
|
-
def list_files_and_folders(path):
|
|
45
|
+
def list_files_and_folders(path, get_selectable=False):
|
|
46
|
+
|
|
47
|
+
selectable_folders = []
|
|
52
48
|
|
|
53
49
|
def recursive_list(dir_path, depth=0):
|
|
54
50
|
items = []
|
|
@@ -58,22 +54,41 @@ def list_files_and_folders(path):
|
|
|
58
54
|
|
|
59
55
|
if entry.is_dir():
|
|
60
56
|
children = recursive_list(entry.path, depth=depth + 1)
|
|
57
|
+
contains_xml = any(
|
|
58
|
+
f.get("name", "").endswith(".xml") for f in children
|
|
59
|
+
)
|
|
60
|
+
item = {
|
|
61
|
+
"type": "folder",
|
|
62
|
+
"name": entry.name,
|
|
63
|
+
"depth": depth,
|
|
64
|
+
"path": entry.path,
|
|
65
|
+
"contains_xml": contains_xml,
|
|
66
|
+
"children": {"count": len(children), "list": children},
|
|
67
|
+
}
|
|
68
|
+
items.append(item)
|
|
69
|
+
if contains_xml:
|
|
70
|
+
selectable_folders.append(item)
|
|
71
|
+
else:
|
|
61
72
|
items.append(
|
|
62
73
|
{
|
|
63
|
-
"type": "
|
|
74
|
+
"type": "file",
|
|
64
75
|
"name": entry.name,
|
|
65
76
|
"depth": depth,
|
|
66
77
|
"path": entry.path,
|
|
67
|
-
"children": {"count": len(children), "list": children},
|
|
68
78
|
}
|
|
69
79
|
)
|
|
70
|
-
else:
|
|
71
|
-
items.append(
|
|
72
|
-
{"type": "file", "name": entry.name, "depth": depth}
|
|
73
|
-
)
|
|
74
80
|
return items
|
|
75
81
|
|
|
76
|
-
|
|
82
|
+
result = recursive_list(path)
|
|
83
|
+
if get_selectable:
|
|
84
|
+
return selectable_folders
|
|
85
|
+
else:
|
|
86
|
+
return result
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def get_selectable_folders(path):
|
|
90
|
+
|
|
91
|
+
return list_files_and_folders(path, get_selectable=True)
|
|
77
92
|
|
|
78
93
|
|
|
79
94
|
def remove_empty_strings_from_dict(d):
|
|
@@ -81,3 +96,36 @@ def remove_empty_strings_from_dict(d):
|
|
|
81
96
|
if d[key] == "":
|
|
82
97
|
d[key] = None
|
|
83
98
|
return d
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def parse_request_data(request, attrib_prefix):
|
|
102
|
+
"""
|
|
103
|
+
Processes form data and creates a list of dictionaries
|
|
104
|
+
for the specified attributes.
|
|
105
|
+
"""
|
|
106
|
+
grouped_data = defaultdict(lambda: defaultdict(list))
|
|
107
|
+
|
|
108
|
+
# Group data based on prefix
|
|
109
|
+
for key in request.form.keys():
|
|
110
|
+
if key.startswith(attrib_prefix):
|
|
111
|
+
try:
|
|
112
|
+
_, field, data_type = key.split("-")
|
|
113
|
+
grouped_data[field][data_type] = request.form.getlist(key)
|
|
114
|
+
except ValueError:
|
|
115
|
+
log.warning(
|
|
116
|
+
f"Invalid key format: {key}. Expected format: '{attrib_prefix}-field-data_type'."
|
|
117
|
+
)
|
|
118
|
+
continue # Skip invalid keys
|
|
119
|
+
|
|
120
|
+
# Transform grouped data into desired structure
|
|
121
|
+
max_length = max(len(data["xpath"]) for data in grouped_data.values())
|
|
122
|
+
return [
|
|
123
|
+
{
|
|
124
|
+
field: {
|
|
125
|
+
"xpath": data["xpath"][i],
|
|
126
|
+
"value": data["value"][i],
|
|
127
|
+
}
|
|
128
|
+
for field, data in grouped_data.items()
|
|
129
|
+
}
|
|
130
|
+
for i in range(max_length)
|
|
131
|
+
]
|
tgp_ui/app.py
CHANGED
|
@@ -7,22 +7,22 @@ import logging
|
|
|
7
7
|
|
|
8
8
|
import click # type: ignore
|
|
9
9
|
import os
|
|
10
|
-
import shutil
|
|
11
10
|
|
|
12
|
-
from
|
|
13
|
-
from
|
|
14
|
-
from flask import url_for as default_url_for # type: ignore
|
|
15
|
-
from flask_json import json_response, FlaskJSON # type: ignore
|
|
11
|
+
from flask import Flask, render_template, session # type: ignore
|
|
12
|
+
from flask_json import FlaskJSON # type: ignore
|
|
16
13
|
|
|
17
|
-
from tgp_backend.
|
|
18
|
-
from tgp_backend.project import Project, TGProject
|
|
14
|
+
from tgp_backend.project import Project
|
|
19
15
|
|
|
20
16
|
from tgp_backend.auth import SecretKeyManager
|
|
21
17
|
from tgp_backend.nextcloud import Nextcloud
|
|
22
|
-
from tgp_backend.
|
|
23
|
-
from tgp_backend.util import remove_empty_strings_from_dict
|
|
18
|
+
from tgp_backend.config import LOG_LEVEL, MAIN_PATH, get_config_value
|
|
24
19
|
|
|
25
|
-
from
|
|
20
|
+
from .routes.project import project_routes
|
|
21
|
+
from .routes.views import main_views
|
|
22
|
+
from .routes.data import data_routes
|
|
23
|
+
from .routes.tabs import tab_manager
|
|
24
|
+
from .routes.collection import collection_routes
|
|
25
|
+
from .routes.publication import publication_routes
|
|
26
26
|
|
|
27
27
|
log = logging.getLogger(__name__)
|
|
28
28
|
|
|
@@ -30,44 +30,38 @@ base_params = {
|
|
|
30
30
|
"title": "TG Prepare",
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
MAIN_PATH = config("main", "path", default="./projects")
|
|
34
|
-
|
|
35
33
|
app = Flask(__name__)
|
|
36
34
|
FlaskJSON(app)
|
|
37
35
|
|
|
38
|
-
|
|
39
36
|
secret_manager = SecretKeyManager(MAIN_PATH)
|
|
40
37
|
app.secret_key = secret_manager.secret_key
|
|
41
38
|
|
|
42
39
|
# Additional security settings, if not in DEBUG mode
|
|
43
|
-
app.config.update(SESSION_COOKIE_NAME="
|
|
44
|
-
if
|
|
40
|
+
app.config.update(SESSION_COOKIE_NAME="tgp_session")
|
|
41
|
+
if LOG_LEVEL != "DEBUG":
|
|
45
42
|
app.config.update(
|
|
46
43
|
SESSION_COOKIE_SECURE=True, # Only allow cookies over HTTPS
|
|
47
44
|
SESSION_COOKIE_HTTPONLY=True, # Prevent JavaScript access to cookies
|
|
48
45
|
SESSION_COOKIE_SAMESITE="Strict", # Protect against CSRF attacks
|
|
49
46
|
)
|
|
50
47
|
|
|
51
|
-
app.jinja_env.globals.update(len=len, round=round)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
# Function to retrieve the prefix from headers, used for reverse proxy setups
|
|
55
|
-
def get_prefix():
|
|
56
|
-
return request.headers.get(
|
|
57
|
-
"X-Forwarded-Prefix", request.headers.get("X-Script-Name", "")
|
|
58
|
-
)
|
|
59
|
-
|
|
60
48
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
49
|
+
app.register_blueprint(main_views)
|
|
50
|
+
app.register_blueprint(project_routes)
|
|
51
|
+
app.register_blueprint(data_routes)
|
|
52
|
+
app.register_blueprint(tab_manager)
|
|
53
|
+
app.register_blueprint(collection_routes)
|
|
54
|
+
app.register_blueprint(publication_routes)
|
|
65
55
|
|
|
66
56
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
57
|
+
def get_textgrid_login_url(instance):
|
|
58
|
+
"""
|
|
59
|
+
Returns the TextGrid login URL based on the instance (test or production).
|
|
60
|
+
"""
|
|
61
|
+
if instance == "test":
|
|
62
|
+
return "https://test.textgridlab.org/1.0/Shibboleth.sso/Login?target=/1.0/secure/TextGrid-WebAuth.php?authZinstance=test.textgridlab.org"
|
|
63
|
+
else:
|
|
64
|
+
return "https://textgridlab.org/1.0/Shibboleth.sso/Login?target=/1.0/secure/TextGrid-WebAuth.php?authZinstance=textgrid-esx2.gwdg.de"
|
|
71
65
|
|
|
72
66
|
|
|
73
67
|
def get_projects():
|
|
@@ -79,7 +73,13 @@ def get_projects():
|
|
|
79
73
|
return projects
|
|
80
74
|
|
|
81
75
|
|
|
82
|
-
app.jinja_env.globals.update(
|
|
76
|
+
app.jinja_env.globals.update(
|
|
77
|
+
len=len,
|
|
78
|
+
round=round,
|
|
79
|
+
title="TG Prepare",
|
|
80
|
+
get_projects=get_projects,
|
|
81
|
+
get_textgrid_login_url=get_textgrid_login_url,
|
|
82
|
+
)
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
def _startup():
|
|
@@ -90,9 +90,9 @@ def _startup():
|
|
|
90
90
|
|
|
91
91
|
logging.getLogger("zeep").setLevel(logging.INFO)
|
|
92
92
|
app.run(
|
|
93
|
-
host=
|
|
94
|
-
port=
|
|
95
|
-
debug=
|
|
93
|
+
host=get_config_value("main", "host", default="0.0.0.0"),
|
|
94
|
+
port=get_config_value("main", "port", default=8077),
|
|
95
|
+
debug=get_config_value("log", "level", default="DEBUG") == "DEBUG",
|
|
96
96
|
)
|
|
97
97
|
|
|
98
98
|
|
|
@@ -103,185 +103,19 @@ def startup(path):
|
|
|
103
103
|
_startup()
|
|
104
104
|
|
|
105
105
|
|
|
106
|
-
#
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
"/xpath_parser_modal/<string:projectname>/<string:title>",
|
|
111
|
-
methods=["GET", "POST"],
|
|
112
|
-
)
|
|
113
|
-
def xpath_parser_modal(projectname=None, title=None):
|
|
114
|
-
project = Project(projectname)
|
|
115
|
-
collection = project.get_collection(title)
|
|
116
|
-
# collection_config = collection["config"]
|
|
117
|
-
collection_parser = collection["parser"]
|
|
118
|
-
|
|
119
|
-
return render_template(
|
|
120
|
-
"xpath_parser_modal_content.html",
|
|
121
|
-
# collection=collection_config,
|
|
122
|
-
collection_parser=collection_parser,
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
@app.route("/new_project", methods=["POST"])
|
|
127
|
-
def new_project():
|
|
128
|
-
project = Project(request.form.get("projectname"))
|
|
129
|
-
project.create()
|
|
130
|
-
return redirect(url_for("project", projectname=project.name))
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
@app.route("/upload_files/<string:projectname>", methods=["POST"])
|
|
134
|
-
def upload_files(projectname=None):
|
|
135
|
-
Project(projectname).file_upload(request.files.getlist("files"))
|
|
136
|
-
|
|
137
|
-
return redirect(url_for("project", projectname=projectname))
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
@app.route(
|
|
141
|
-
"/collection/<string:projectname>/<string:name>", methods=["GET", "POST"]
|
|
142
|
-
)
|
|
143
|
-
def collection(projectname, name):
|
|
144
|
-
project = Project(projectname)
|
|
145
|
-
collection = project.get_collection(name)
|
|
146
|
-
return render_template(
|
|
147
|
-
"collection.html",
|
|
148
|
-
project=project,
|
|
149
|
-
collection_title=name,
|
|
150
|
-
collection=collection["config"],
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
@app.route("/publication/<string:projectname>", methods=["GET", "POST"])
|
|
155
|
-
def publication(projectname):
|
|
156
|
-
project = Project(projectname)
|
|
157
|
-
return render_template(
|
|
158
|
-
"publication.html",
|
|
159
|
-
project=project,
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
@app.route("/project/<string:projectname>", methods=["GET", "POST"])
|
|
164
|
-
def project(projectname=None):
|
|
165
|
-
params = {
|
|
166
|
-
"sub_title": "Project: %s" % projectname,
|
|
167
|
-
"sub_description": "",
|
|
168
|
-
}
|
|
169
|
-
params.update(base_params)
|
|
170
|
-
|
|
171
|
-
return render_template(
|
|
172
|
-
"project.html",
|
|
173
|
-
user=session.get("user", "-"),
|
|
174
|
-
current_project=projectname,
|
|
175
|
-
project=Project(projectname),
|
|
176
|
-
tab=request.args.get("tab"),
|
|
177
|
-
**params,
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
@app.route("/", methods=["GET"])
|
|
182
|
-
@app.route("/project", methods=["GET", "POST"])
|
|
183
|
-
@app.route("/projects", methods=["GET", "POST"])
|
|
184
|
-
def projects():
|
|
185
|
-
params = {
|
|
186
|
-
"sub_title": "Projects",
|
|
187
|
-
"sub_description": "",
|
|
188
|
-
}
|
|
189
|
-
params.update(base_params)
|
|
190
|
-
|
|
191
|
-
projectname = request.form.get("projectname")
|
|
192
|
-
fullpath = f"{MAIN_PATH}/{projectname}"
|
|
193
|
-
|
|
194
|
-
if request.method == "POST":
|
|
195
|
-
if request.form.get("delete"):
|
|
196
|
-
# Delete the project
|
|
197
|
-
if fullpath.strip("/") == MAIN_PATH.strip("/"):
|
|
198
|
-
log.error(f"Cannot delete main path ({MAIN_PATH})!")
|
|
199
|
-
elif os.path.exists(fullpath):
|
|
200
|
-
shutil.rmtree(fullpath)
|
|
201
|
-
else:
|
|
202
|
-
log.warning("Project does not exist!")
|
|
203
|
-
|
|
204
|
-
# Get list of all existing projects/directories
|
|
205
|
-
projects = []
|
|
206
|
-
for sub in os.listdir(MAIN_PATH):
|
|
207
|
-
projectpath = "%s/%s" % (MAIN_PATH, sub)
|
|
208
|
-
if os.path.isdir(projectpath):
|
|
209
|
-
projects.append(Project(sub))
|
|
210
|
-
# projects.append({"name": sub, "fullpath": projectpath})
|
|
211
|
-
|
|
212
|
-
return render_template("projects.html", projects=projects, **params)
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
@app.route(
|
|
216
|
-
"/tei_explorer/<string:projectname>/<string:title>", methods=["GET"]
|
|
217
|
-
)
|
|
218
|
-
def tei_explorer(projectname, title):
|
|
106
|
+
# Step 9
|
|
107
|
+
@app.route("/tab-final-upload/<string:projectname>", methods=["GET"])
|
|
108
|
+
def tab_final_upload(projectname):
|
|
109
|
+
# Erstelle das Project-Objekt
|
|
219
110
|
project = Project(projectname)
|
|
220
|
-
dir_list_dict, file_list_dict = generateList(
|
|
221
|
-
project.get_subproject_inpath(title)
|
|
222
|
-
)
|
|
223
111
|
|
|
112
|
+
# Übergib das Project-Objekt an das Template
|
|
224
113
|
return render_template(
|
|
225
|
-
"
|
|
226
|
-
|
|
227
|
-
file_list=file_list_dict,
|
|
228
|
-
collection_title=title,
|
|
229
|
-
project=project,
|
|
114
|
+
"tab_final_upload.html",
|
|
115
|
+
project=project, # Das Project-Objekt wird hier übergeben
|
|
230
116
|
)
|
|
231
117
|
|
|
232
118
|
|
|
233
|
-
# *****************
|
|
234
|
-
# JSON-REQUESTS
|
|
235
|
-
# *****************
|
|
236
|
-
@app.route("/load_tei_content", methods=["GET"])
|
|
237
|
-
def load_tei_content():
|
|
238
|
-
path = request.args.get("path")
|
|
239
|
-
log.debug("load_tei_content path: %s" % path)
|
|
240
|
-
_type = request.args.get("type")
|
|
241
|
-
if path is not None:
|
|
242
|
-
tei_parser = TEIParser(fullpath=path)
|
|
243
|
-
if _type == "header":
|
|
244
|
-
return json_response(
|
|
245
|
-
value="OK",
|
|
246
|
-
content=tei_parser.find(
|
|
247
|
-
"//teiHeader", node_as_text=True
|
|
248
|
-
).decode("utf-8"),
|
|
249
|
-
)
|
|
250
|
-
elif _type == "text":
|
|
251
|
-
return json_response(
|
|
252
|
-
value="OK",
|
|
253
|
-
content=tei_parser.find(".//text", node_as_text=True).decode(
|
|
254
|
-
"utf-8"
|
|
255
|
-
),
|
|
256
|
-
)
|
|
257
|
-
return json_response(value="Unknown type requested!")
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
@app.route(
|
|
261
|
-
"/set_configs/<string:projectname>/<string:title>", methods=["POST"]
|
|
262
|
-
)
|
|
263
|
-
def save_collection(projectname, title):
|
|
264
|
-
project = Project(projectname)
|
|
265
|
-
collection = project.get_collection(title)
|
|
266
|
-
collection_config = collection["config"]
|
|
267
|
-
for _attrib in request.form:
|
|
268
|
-
attrib = _attrib.replace("[]", "")
|
|
269
|
-
if attrib in collection_config.multi_attribs:
|
|
270
|
-
value = [
|
|
271
|
-
remove_empty_strings_from_dict(loads(v))
|
|
272
|
-
for v in request.form.getlist(_attrib)
|
|
273
|
-
]
|
|
274
|
-
elif attrib in collection_config.xpath_or_value_attribs:
|
|
275
|
-
value = remove_empty_strings_from_dict(
|
|
276
|
-
loads(request.form.get(attrib))
|
|
277
|
-
)
|
|
278
|
-
else:
|
|
279
|
-
value = request.form.get(attrib)
|
|
280
|
-
setattr(collection_config, attrib, value)
|
|
281
|
-
collection_config.save()
|
|
282
|
-
return json_response(response="OK")
|
|
283
|
-
|
|
284
|
-
|
|
285
119
|
@app.route("/nextcloud_tab/", methods=["POST"])
|
|
286
120
|
def nextcloud_tab():
|
|
287
121
|
nextcloud = Nextcloud(**session)
|
|
@@ -292,131 +126,5 @@ def nextcloud_tab():
|
|
|
292
126
|
)
|
|
293
127
|
|
|
294
128
|
|
|
295
|
-
@app.route("/nextcloud_login/", methods=["POST"])
|
|
296
|
-
def nextcloud_login():
|
|
297
|
-
|
|
298
|
-
data = request.get_json()
|
|
299
|
-
login_data = data.get("data", [])
|
|
300
|
-
|
|
301
|
-
if Nextcloud(**login_data).test_connection():
|
|
302
|
-
for key in login_data:
|
|
303
|
-
session[key] = login_data[key]
|
|
304
|
-
|
|
305
|
-
return json_response(login_succes=True)
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
@app.route("/nextcloud_logout", methods=["POST"])
|
|
309
|
-
def nextcloud_logout():
|
|
310
|
-
session.clear()
|
|
311
|
-
return json_response(response="OK")
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
@app.route("/nextcloud_download", methods=["POST"])
|
|
315
|
-
def nextcloud_download():
|
|
316
|
-
data = request.get_json()
|
|
317
|
-
projectname = data.get("projectname")
|
|
318
|
-
file_paths = data.get("file_paths", [])
|
|
319
|
-
nxt = Nextcloud(**session)
|
|
320
|
-
nxt.download_nxc_files(file_paths, projectname)
|
|
321
|
-
|
|
322
|
-
return json_response(response="OK")
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
@app.route("/clone_git_project/<string:projectname>", methods=["POST"])
|
|
326
|
-
def clone_git_project(projectname=None):
|
|
327
|
-
Project(projectname).clone_git_project(request.form.get("github_repo"))
|
|
328
|
-
|
|
329
|
-
return json_response(response="OK")
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
@app.route(
|
|
333
|
-
"/check_xpath/<string:projectname>/<string:collectionname>",
|
|
334
|
-
methods=["GET"],
|
|
335
|
-
)
|
|
336
|
-
def check_xpath(projectname, collectionname):
|
|
337
|
-
project = Project(projectname)
|
|
338
|
-
collection = project.get_collection(collectionname)
|
|
339
|
-
collection_config = collection["config"]
|
|
340
|
-
|
|
341
|
-
xpath = request.args.get("xpath")
|
|
342
|
-
|
|
343
|
-
results = []
|
|
344
|
-
|
|
345
|
-
for file in collection_config.elements:
|
|
346
|
-
tei_parser = TEIParser(fullpath=file["fullpath"])
|
|
347
|
-
result = tei_parser.find(xpath)
|
|
348
|
-
if result is not None:
|
|
349
|
-
results.append({"filename": file["filename"], "result": result})
|
|
350
|
-
|
|
351
|
-
return json_response(value="OK", results=results)
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
@app.route("/set_configs/<string:projectname>", methods=["POST"])
|
|
355
|
-
def set_configs(projectname):
|
|
356
|
-
Project(projectname).init_configs(request.form.getlist("tei_directories"))
|
|
357
|
-
|
|
358
|
-
return json_response(response="OK")
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
@app.route(
|
|
362
|
-
"/publish_project/<string:projectname>/<string:instance>", methods=["POST"]
|
|
363
|
-
)
|
|
364
|
-
def publish_project(projectname, instance):
|
|
365
|
-
TGProject(projectname, instance).publish_tg_project()
|
|
366
|
-
return json_response(response="OK")
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
@app.route(
|
|
370
|
-
"/save_session_id/<string:projectname>/<string:instance>", methods=["POST"]
|
|
371
|
-
)
|
|
372
|
-
def save_session_id(projectname, instance):
|
|
373
|
-
TGProject(projectname, instance).tg_session_id = request.form.get(
|
|
374
|
-
"tg_auth_session_id"
|
|
375
|
-
)
|
|
376
|
-
|
|
377
|
-
return json_response(response="OK")
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
@app.route(
|
|
381
|
-
"/save_tg_project_id/<string:projectname>/<string:instance>",
|
|
382
|
-
methods=["POST"],
|
|
383
|
-
)
|
|
384
|
-
def save_tg_project_id(projectname, instance):
|
|
385
|
-
TGProject(projectname, instance).tg_project_id = request.form.get(
|
|
386
|
-
"tg_project_id"
|
|
387
|
-
)
|
|
388
|
-
return json_response(response="OK")
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
@app.route(
|
|
392
|
-
"/delete_tg_project_id/<string:projectname>/<string:instance>/<string:tg_project_id>",
|
|
393
|
-
methods=["POST"],
|
|
394
|
-
)
|
|
395
|
-
def delete_tg_project_id(projectname, instance, tg_project_id):
|
|
396
|
-
TGProject(projectname, instance).delete_tg_project(tg_project_id)
|
|
397
|
-
|
|
398
|
-
return json_response(response="OK")
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
@app.route(
|
|
402
|
-
"/get_tg_project_hits/<string:projectname>/<string:instance>/<string:tg_project_id>",
|
|
403
|
-
methods=["GET"],
|
|
404
|
-
)
|
|
405
|
-
def get_tg_project_hits(projectname, instance, tg_project_id):
|
|
406
|
-
hits = TGProject(projectname, instance).get_tg_project_hits(tg_project_id)
|
|
407
|
-
return json_response(response="OK", hits=hits)
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
@app.route(
|
|
411
|
-
"/create_tg_project/<string:projectname>/<string:instance>",
|
|
412
|
-
methods=["POST"],
|
|
413
|
-
)
|
|
414
|
-
def create_tg_project(projectname, instance):
|
|
415
|
-
TGProject(projectname, instance).create_tg_project(
|
|
416
|
-
request.form.get("tg_projectname")
|
|
417
|
-
)
|
|
418
|
-
return json_response(response="OK")
|
|
419
|
-
|
|
420
|
-
|
|
421
129
|
if __name__ == "__main__":
|
|
422
130
|
startup()
|
|
File without changes
|