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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tg_prepare
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.1.0b2
|
|
4
4
|
Summary: Simple UI to handle TextGrid imports visually.
|
|
5
5
|
Author: Ralf Klammer, Moritz Wilhelm
|
|
6
6
|
Author-email: ralf.klammer@tu-dresden.de, moritz.wilhelm@tu-dresden.de
|
|
@@ -8,8 +8,8 @@ License-File: LICENSE
|
|
|
8
8
|
Requires-Dist: click
|
|
9
9
|
Requires-Dist: flask
|
|
10
10
|
Requires-Dist: flask_json
|
|
11
|
-
Requires-Dist: tg_model
|
|
12
|
-
Requires-Dist: tgclients
|
|
11
|
+
Requires-Dist: tg_model==3.8.0.b2
|
|
12
|
+
Requires-Dist: tgclients
|
|
13
13
|
Requires-Dist: tgadmin
|
|
14
14
|
Requires-Dist: nextcloud-api-wrapper
|
|
15
15
|
Dynamic: author
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
tg_prepare-2.1.0b2.dist-info/licenses/LICENSE,sha256=deYu6g1OGKm0VUwhM4Octoh8qlzjsiHHxoI-KkCBVBE,11351
|
|
2
|
+
tg_prepare-2.1.0b2.dist-info/projects/.secret_key,sha256=PF3sI74fctNP5J8NoHmvl6nRsvyTeGMU82UTY_E3re4,66
|
|
3
|
+
tgp_backend/__init__.py,sha256=Hsy1huPlOgpNffJVJpxGZzUKdHU8X837K-cOW_DkEy0,373
|
|
4
|
+
tgp_backend/auth.py,sha256=hUPd0rc01BTT003xpkdmhNc6o0JztbAdimyDb0B9oTQ,2293
|
|
5
|
+
tgp_backend/cli.py,sha256=iw_gknn-_m_UFZZUKfkV9aJixG3sVcHIONybNtOG40I,551
|
|
6
|
+
tgp_backend/config.py,sha256=9rFr7bxZN4r1OOKaxs8eBYUnZ0_ccVHU6oqoEsNTKBE,922
|
|
7
|
+
tgp_backend/directories.py,sha256=wNmwc2Uhd9ivZYIM9UkfCv2HkQY8pmDQk2y39wOgBQo,2366
|
|
8
|
+
tgp_backend/interfaces.py,sha256=SO7mOdhkd1f7irUBrwFhp5aKx3UKkkUzU9QBYDl0Tvc,91
|
|
9
|
+
tgp_backend/nextcloud.py,sha256=JNhyJfuR26o33r5QV37ClTALQm_fMQn451SMV5lixNc,5133
|
|
10
|
+
tgp_backend/project.py,sha256=_qebCEkC_wRfSknOIL-c4BAPG830EUZ5m4HW_gkHRn4,12707
|
|
11
|
+
tgp_backend/session_manager.py,sha256=pQGhnXtGPqwdw6xQhZItjGgurx9JBUsIW8mzfSKk_WM,1395
|
|
12
|
+
tgp_backend/tgclient.py,sha256=QG2iFPrv2qLL4FRXoEfXzEMJriroiIaNL9rkreGtzuQ,2961
|
|
13
|
+
tgp_backend/util.py,sha256=4lTaC3liik2ixRcx5wDQS4-FW3QpPhRdXQm32_64J_E,3648
|
|
14
|
+
tgp_ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
tgp_ui/app.py,sha256=6elwUZ_hSM08_FstTerrLX2rB4QurQUSqu359rkhxrI,3704
|
|
16
|
+
tgp_ui/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
tgp_ui/routes/collection.py,sha256=NzfLnF-ZDlZI23ulDhvLXJXELlTlcJw0Z_LONHcU2bA,7861
|
|
18
|
+
tgp_ui/routes/data.py,sha256=xnw-0v72SK8Z2zjwCYNAHp8omkfsZKRtvUKr3YZSSFg,6891
|
|
19
|
+
tgp_ui/routes/project.py,sha256=AyCYI76V4vkEfZQPjSgXmPOIWClpryEEBTQoSjxSXkM,2794
|
|
20
|
+
tgp_ui/routes/publication.py,sha256=K_wDy3t_iwL9TMLLFXR7P2PdDWyHNQUMY9FArJBsmN4,3791
|
|
21
|
+
tgp_ui/routes/tabs.py,sha256=JaZpoY03S_p8uz_sVRCR-fIOfl-ml0M6CJ7_KaYN9aI,908
|
|
22
|
+
tgp_ui/routes/views.py,sha256=ZgxcfEZoyE_4ABrnRtHc8FFR11Rufs8HVaUr4cOBshA,1814
|
|
23
|
+
tgp_ui/static/css/bootstrap-icons.min.css,sha256=XxUvYRPQvG4RTCkukUmXwvf1N0YF9KQ_ocuWV6O1dk8,85797
|
|
24
|
+
tgp_ui/static/css/bootstrap.min.css,sha256=djO3wMl9GeaC_u6K-ic4Uj_LKhRUSlUFcsruzS7v5ms,155845
|
|
25
|
+
tgp_ui/static/css/bootstrap.min.css.map,sha256=EBs_YesgSHsqjgt20O58j-TenKwqNKfiRs25z_PF4Lg,551641
|
|
26
|
+
tgp_ui/static/css/main.css,sha256=EK8euwgxX8I3qsBiDmIvj8UBIxkSKQZz1mo_OX4Q1FQ,2641
|
|
27
|
+
tgp_ui/static/css/navbar.css,sha256=D68mfVJ88zruV1sRH1D6zjwQ2MoHRy2HQ7BAn_8OSkc,1609
|
|
28
|
+
tgp_ui/static/css/simpleXML.css,sha256=dfY7UZCiC79BkNOT1hM0GQ6v_yLSxhKCnmV0RZIT9S8,961
|
|
29
|
+
tgp_ui/static/img/favicon.ico,sha256=avMR6pxad-unbXWKHOw8LyGuF59y1-QwpwW3_bTMI0c,15086
|
|
30
|
+
tgp_ui/static/img/textgrid-logo.svg,sha256=wj4rBXvKsyASor_9lvpWQWb39CchruK4WPxE4phzbaI,35349
|
|
31
|
+
tgp_ui/static/js/bootstrap.bundle.min.js,sha256=fh8VA992XMpeCZiRuU4xii75UIG6KvHrbUF8yIS_2_4,78743
|
|
32
|
+
tgp_ui/static/js/collectionManager.js,sha256=gbeXe7CtEdCdka3WLfBx7cVRcT8cveUP_t3TDwRdgvo,2291
|
|
33
|
+
tgp_ui/static/js/fileManager.js,sha256=_plx7zrC039-3y0ZqLd77ymDhTtAiJC3XOLSeAooYAc,7095
|
|
34
|
+
tgp_ui/static/js/jquery.min.js,sha256=_xUj-3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej_m4,89501
|
|
35
|
+
tgp_ui/static/js/main.js,sha256=VCaLVlGFml8ObO0mbyV_kT1aDVH-OB4jqVlzsfT42xM,1107
|
|
36
|
+
tgp_ui/static/js/modalManager.js,sha256=8q4Dtx88aO4zbG5EgZ6Nw1NJa36-RKoRcVzy4DVHEVg,4030
|
|
37
|
+
tgp_ui/static/js/navbarManager.js,sha256=E1_SF262uU4I405vxVCrEXhAE7aEZt9ASixG7huL1As,6713
|
|
38
|
+
tgp_ui/static/js/projectManager.js,sha256=LoT8lZnyvrgquSD7aSNkYaAdggH5kUZYRXVFD-d3dzk,2296
|
|
39
|
+
tgp_ui/static/js/require.js,sha256=DCwpJYECNmnwjgb2xsUmuvSrkNPXRYgYADz7nlUc_-Y,20781
|
|
40
|
+
tgp_ui/static/js/sidebarManager.js,sha256=sfYPwLvKUQA8vMhyVKsA7CJe5cUJliCao8ccwfLKAV0,928
|
|
41
|
+
tgp_ui/static/js/simpleXML.js,sha256=jEkZe3TuiHuEt6V7If_1EmqYIgTywssJ3OwOQzOFYNg,8065
|
|
42
|
+
tgp_ui/static/js/tabManager.js,sha256=spS-Hr-LylqpW0nQz7ontsPfX64b3whilr6038VMq18,3304
|
|
43
|
+
tgp_ui/templates/file_tree.html,sha256=IKWp5MLUvnFF65cIUIxU4Jf5wi9Fg8koSXD96Mk328E,1640
|
|
44
|
+
tgp_ui/templates/layout.html,sha256=ClI6xHMBy6auir72i3Sm6SCJI97XUXhpPrzJSgf_7wM,2727
|
|
45
|
+
tgp_ui/templates/macros.html,sha256=3qetLd7wC__iAoWZ6g4--82Zd2t36XOZcwiLbi7DEAA,4463
|
|
46
|
+
tgp_ui/templates/nxc_login.html,sha256=tDxqHYPZqsY2ZNnkn4a5bMOYiD8ybcNRpzSq7MvMWCo,1269
|
|
47
|
+
tgp_ui/templates/nxc_tab.html,sha256=9HWCa7UZKxL0fZasT_g6uozI64L-497Y2LppPPTHF2M,517
|
|
48
|
+
tgp_ui/templates/project_main.html,sha256=Vdvr9QDfpnc9EU38uTm0H4pT0pzLdi7DckL3d9DC_u4,1878
|
|
49
|
+
tgp_ui/templates/project_navbar.html,sha256=WyS8WNI7tgNDdYOkuFaXeu9A58ER3OK7puVNO-Sfz-0,4412
|
|
50
|
+
tgp_ui/templates/projects_main.html,sha256=2c6PNdomNV1w6j6e-FH27bvdwVNfrzTf5DY1pNzHuMM,2530
|
|
51
|
+
tgp_ui/templates/publication.html,sha256=TXCHCE2198cHFmN4_l4JNmq0nQoy8GwnESePjRfjliU,9357
|
|
52
|
+
tgp_ui/templates/tab_final_upload.html,sha256=Nn1pwxI_Y_XBB81N5l2G8P_pSsVOyS2AQLsp8IE9a4s,1663
|
|
53
|
+
tgp_ui/templates/details/empty_container.html,sha256=-xNao7K8Sw74WGuF4pbeBUFZI8wDk9a_O4bq-LiCHaU,553
|
|
54
|
+
tgp_ui/templates/details/manage_collection.html,sha256=BJ0KbKHe414aqlWhDS25D-NVmlkNWp9S7kSHNlsuZ_M,11582
|
|
55
|
+
tgp_ui/templates/includes/set_session_id_form.html,sha256=xj15HOl1ujsiYsolRN7c2IGjUhNY72MpzhTEx4UMAq8,814
|
|
56
|
+
tgp_ui/templates/includes/upload_form.html,sha256=q_Bn_IECfal7SOHtVn6ESQZV9n6WCtrrW7rbxw9e-ck,7005
|
|
57
|
+
tgp_ui/templates/modal/delete_project.html,sha256=H_IBQWPtY9-V47WWeEMsSg5CzqCk5lxBvKJbOnD-MWo,1285
|
|
58
|
+
tgp_ui/templates/modal/empty_container.html,sha256=UYq6AEqrUXY7Qtn4-HrwXxtOUOq2l1Qj5ZPxgWApg3Y,423
|
|
59
|
+
tgp_ui/templates/modal/file_explorer_content.html,sha256=x3cA2b02VqrGe-YBw2j91hKQg6Vm32bNa0j9XOrL6E8,1317
|
|
60
|
+
tgp_ui/templates/modal/file_explorer_main.html,sha256=mOhEuPzBHSVupBuRU5VYAaTZWYdm84W5kUntKHpa3jo,890
|
|
61
|
+
tgp_ui/templates/modal/file_explorer_nextcloud.html,sha256=gV5w4MF8pk4bg_MiCThGY49hlXIoFhXYE1QpYdO_O7I,1260
|
|
62
|
+
tgp_ui/templates/modal/github_modal.html,sha256=nzH7Y8uMzdGxTlgu8LvvdOyxXSjMyK6TXHL94WYTP9s,1460
|
|
63
|
+
tgp_ui/templates/modal/nextcloud_login.html,sha256=S6ogSAGqNiYOheOV6eZGss7f5XKq88ul0rIuCfftbQs,2411
|
|
64
|
+
tgp_ui/templates/modal/tei_explorer.html,sha256=4JL2d3CfThgDRGnFlhtFONVZBd7nEenmJuZHtYnVxuo,3134
|
|
65
|
+
tgp_ui/templates/modal/xpath_parser.html,sha256=Qkk2Mh53E8l4z486hcboTsQlPHoFPezbMP59pEwB0fY,2552
|
|
66
|
+
tgp_ui/templates/tabs/check_result.html,sha256=9P0xYBB0EGhpmp-xzJyiOjBqfqtxRx2h2Zgdvyw8GEI,4530
|
|
67
|
+
tgp_ui/templates/tabs/edit_project.html,sha256=ssbtzgY9VfTeCgghJR6iov1GdCB2TZ34-H4sTwZwIXQ,6923
|
|
68
|
+
tgp_ui/templates/tabs/empty_container.html,sha256=yBNUUdrbmNbTNdc7xK2HrwztrEpiRPqCICGo0mZNCIQ,433
|
|
69
|
+
tgp_ui/templates/tabs/import_data.html,sha256=UUwb1w5Ku-FZKfFIFnJKV6pSJ6azoJGqIxSgDPqva8I,7082
|
|
70
|
+
tgp_ui/templates/tabs/manage_collections.html,sha256=OHo7QTpFLlEXirPay4RQ2Jqt82yQg97w92Q_5j_KzDQ,4672
|
|
71
|
+
tgp_ui/templates/tabs/select_directories.html,sha256=JfP3Gj9mprcy-jpPxWS3eiLdI3XS3IAbgmYCFvi8vOQ,1989
|
|
72
|
+
tgp_ui/templates/tabs/upload.html,sha256=tc-yv-T6hg3-gD3P3Xz7Xdb8qYyaQ9FVoyWDw144mm0,1785
|
|
73
|
+
tgp_ui/templates/tabs/validate_metadata.html,sha256=USGG08KDMrc0rHtDEmma-DCbVEXbspMCIZhBqYfVpe4,12190
|
|
74
|
+
tg_prepare-2.1.0b2.dist-info/METADATA,sha256=8W-QJmSFkr8llNeeofnG2TLlgSoOhj2gvTe-5v8yjDU,529
|
|
75
|
+
tg_prepare-2.1.0b2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
76
|
+
tg_prepare-2.1.0b2.dist-info/entry_points.txt,sha256=mbsfiEA8_fQdrFUE_oabDi-Syw8jjli37Ms7tawDDhs,78
|
|
77
|
+
tg_prepare-2.1.0b2.dist-info/top_level.txt,sha256=ueOyX_KdozreQJD_HRs6kAsvGNO4vfM9B_QqqhdyRPI,19
|
|
78
|
+
tg_prepare-2.1.0b2.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"94c9d50a8949b627be9608827a66d0025919e013d89236b092de90dd0b79fd12"
|
tgp_backend/__init__.py
CHANGED
|
@@ -4,15 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
6
|
|
|
7
|
-
from .
|
|
7
|
+
from .config import LOG_LEVEL
|
|
8
8
|
|
|
9
9
|
log = logging.getLogger(__name__)
|
|
10
10
|
|
|
11
|
-
log_level = config("log", "level", default="INFO")
|
|
12
11
|
log_config = dict(
|
|
13
|
-
level=
|
|
12
|
+
level=LOG_LEVEL,
|
|
14
13
|
format="%(asctime)s %(name)-10s %(levelname)-4s %(message)s",
|
|
15
14
|
)
|
|
16
15
|
|
|
17
16
|
logging.basicConfig(**log_config)
|
|
18
|
-
logging.getLogger("").setLevel(
|
|
17
|
+
logging.getLogger("").setLevel(LOG_LEVEL)
|
tgp_backend/config.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (C) 2023-2024 TU-Dresden (ZIH)
|
|
3
|
+
# ralf.klammer@tu-dresden.de
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
from configparser import ConfigParser
|
|
7
|
+
|
|
8
|
+
log = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_config_value(section, parameter, default=None):
|
|
12
|
+
_config = ConfigParser()
|
|
13
|
+
_config.read("config.ini")
|
|
14
|
+
|
|
15
|
+
if section not in _config:
|
|
16
|
+
log.warn("Section: %s not in *.ini -> using default" % section)
|
|
17
|
+
return default
|
|
18
|
+
config_val = _config[section].get(parameter)
|
|
19
|
+
if not config_val:
|
|
20
|
+
log.info(
|
|
21
|
+
"Parameter: %s not in section: (%s) of *.ini -> using default: %s"
|
|
22
|
+
% (parameter, section, default)
|
|
23
|
+
)
|
|
24
|
+
return default
|
|
25
|
+
else:
|
|
26
|
+
return config_val
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
LOG_LEVEL = get_config_value("log", "level", default="INFO")
|
|
30
|
+
MAIN_PATH = get_config_value("main", "path", default="./projects")
|
|
31
|
+
MAX_FILENAME_LENGTH = get_config_value("main", "maxFileNameLength", default=15)
|
tgp_backend/directories.py
CHANGED
|
@@ -6,13 +6,11 @@ import logging
|
|
|
6
6
|
import os
|
|
7
7
|
import re
|
|
8
8
|
|
|
9
|
-
from tgp_backend.
|
|
10
|
-
|
|
9
|
+
from tgp_backend.config import MAX_FILENAME_LENGTH
|
|
10
|
+
from tgp_backend.util import get_file_extension
|
|
11
11
|
|
|
12
12
|
log = logging.getLogger(__name__)
|
|
13
13
|
|
|
14
|
-
maxFileNameLength = config("main", "maxFileNameLength", default=15)
|
|
15
|
-
|
|
16
14
|
|
|
17
15
|
def generateList(path=None):
|
|
18
16
|
# path = path if path else config("main", "path", default="/tmp")
|
|
@@ -38,12 +36,12 @@ def generateList(path=None):
|
|
|
38
36
|
curDir = path
|
|
39
37
|
|
|
40
38
|
for d in dList:
|
|
41
|
-
if len(d["name"]) >
|
|
39
|
+
if len(d["name"]) > MAX_FILENAME_LENGTH:
|
|
42
40
|
dots = "..."
|
|
43
41
|
else:
|
|
44
42
|
dots = ""
|
|
45
43
|
temp_dir = {}
|
|
46
|
-
temp_dir["f"] = d["name"][0:
|
|
44
|
+
temp_dir["f"] = d["name"][0:MAX_FILENAME_LENGTH] + dots
|
|
47
45
|
temp_dir["name"] = d["name"]
|
|
48
46
|
temp_dir["f_url"] = re.sub("#", "|HASHTAG|", d["fullpath"])
|
|
49
47
|
temp_dir["currentDir"] = curDir
|
|
@@ -61,12 +59,12 @@ def generateList(path=None):
|
|
|
61
59
|
pass
|
|
62
60
|
if not image:
|
|
63
61
|
image = "files_icon/unknown-icon.png"
|
|
64
|
-
if len(f["name"]) >
|
|
62
|
+
if len(f["name"]) > MAX_FILENAME_LENGTH:
|
|
65
63
|
dots = "..."
|
|
66
64
|
else:
|
|
67
65
|
dots = ""
|
|
68
66
|
temp_file = {}
|
|
69
|
-
temp_file["f"] = f["name"][0:
|
|
67
|
+
temp_file["f"] = f["name"][0:MAX_FILENAME_LENGTH] + dots
|
|
70
68
|
temp_file["name"] = f["name"]
|
|
71
69
|
temp_file["name_stripped"] = f["name"].replace(f".{tp}", "")
|
|
72
70
|
temp_file["f_url"] = re.sub("#", "|HASHTAG|", f["fullpath"])
|
tgp_backend/nextcloud.py
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
# moritz.wilhelm@tu-dresden.de
|
|
5
5
|
|
|
6
6
|
import logging
|
|
7
|
-
|
|
8
7
|
import nextcloud
|
|
9
8
|
import os
|
|
10
9
|
|
|
@@ -14,21 +13,21 @@ log = logging.getLogger(__name__)
|
|
|
14
13
|
class Nextcloud:
|
|
15
14
|
def __init__(
|
|
16
15
|
self,
|
|
17
|
-
|
|
16
|
+
url=None,
|
|
18
17
|
username=None,
|
|
19
18
|
password=None,
|
|
20
|
-
|
|
19
|
+
folder=None,
|
|
21
20
|
**kwargs,
|
|
22
21
|
):
|
|
23
22
|
self._nxc = None
|
|
24
23
|
self._root = None
|
|
25
|
-
self.
|
|
24
|
+
self.url = url
|
|
26
25
|
self.username = username
|
|
27
26
|
self.password = password
|
|
28
|
-
self.root_dir =
|
|
27
|
+
self.root_dir = folder
|
|
29
28
|
|
|
30
29
|
def test_connection(self):
|
|
31
|
-
if all([self.
|
|
30
|
+
if all([self.url, self.username, self.password]):
|
|
32
31
|
return str(self.nxc.list_folders().status_code).startswith("2")
|
|
33
32
|
return False
|
|
34
33
|
|
|
@@ -36,7 +35,7 @@ class Nextcloud:
|
|
|
36
35
|
def nxc(self):
|
|
37
36
|
if self._nxc is None:
|
|
38
37
|
self._nxc = nextcloud.NextCloud(
|
|
39
|
-
endpoint=self.
|
|
38
|
+
endpoint=self.url,
|
|
40
39
|
user=self.username,
|
|
41
40
|
password=self.password,
|
|
42
41
|
)
|
|
@@ -51,29 +50,51 @@ class Nextcloud:
|
|
|
51
50
|
raise "Could not find the Root Directory"
|
|
52
51
|
return self._root
|
|
53
52
|
|
|
54
|
-
def nxc_list_files_and_folders(self):
|
|
53
|
+
def nxc_list_files_and_folders(self, get_selectable=False):
|
|
54
|
+
|
|
55
|
+
selectable_folders = []
|
|
55
56
|
|
|
56
|
-
def
|
|
57
|
+
def recursive_list(item, depth=0):
|
|
57
58
|
items = []
|
|
58
59
|
for d in item.list():
|
|
59
60
|
if d.isdir():
|
|
60
|
-
children =
|
|
61
|
+
children = recursive_list(d, depth=depth + 1)
|
|
62
|
+
contains_xml = any(
|
|
63
|
+
f.get("name", "").endswith(".xml") for f in children
|
|
64
|
+
)
|
|
65
|
+
item = {
|
|
66
|
+
"type": "folder",
|
|
67
|
+
"name": d.basename(),
|
|
68
|
+
"depth": depth,
|
|
69
|
+
"path": d.get_relative_path(),
|
|
70
|
+
"contains_xml": contains_xml,
|
|
71
|
+
"children": {
|
|
72
|
+
"count": len(children),
|
|
73
|
+
"list": children,
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
items.append(item)
|
|
77
|
+
if contains_xml:
|
|
78
|
+
selectable_folders.append(item)
|
|
79
|
+
else:
|
|
61
80
|
items.append(
|
|
62
81
|
{
|
|
63
|
-
"type": "
|
|
82
|
+
"type": "file",
|
|
64
83
|
"name": d.basename(),
|
|
65
|
-
"
|
|
66
|
-
"children": {
|
|
67
|
-
"count": len(children),
|
|
68
|
-
"list": children,
|
|
69
|
-
},
|
|
84
|
+
"depth": depth,
|
|
70
85
|
}
|
|
71
86
|
)
|
|
72
|
-
else:
|
|
73
|
-
items.append({"type": "file", "name": d.basename()})
|
|
74
87
|
return items
|
|
75
88
|
|
|
76
|
-
|
|
89
|
+
result = recursive_list(self.root)
|
|
90
|
+
if get_selectable:
|
|
91
|
+
return selectable_folders
|
|
92
|
+
else:
|
|
93
|
+
return result
|
|
94
|
+
|
|
95
|
+
def get_selectable_folders(self):
|
|
96
|
+
|
|
97
|
+
return self.nxc_list_files_and_folders(get_selectable=True)
|
|
77
98
|
|
|
78
99
|
def download_nxc_files(self, file_paths, projectname):
|
|
79
100
|
for path in file_paths:
|
tgp_backend/project.py
CHANGED
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
# ralf.klammer@tu-dresden.de
|
|
4
4
|
# moritz.wilhelm@tu-dresden.de
|
|
5
5
|
import logging
|
|
6
|
+
|
|
7
|
+
import json
|
|
6
8
|
import os
|
|
7
9
|
import subprocess
|
|
8
10
|
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
9
13
|
from tg_model.collection import CollectionModeler # type: ignore
|
|
14
|
+
from tg_model.project import Project as ProjectHandler # type: ignore
|
|
10
15
|
from tg_model.tei import TEIParser # type: ignore
|
|
11
16
|
|
|
12
17
|
from tg_model.yaml import ( # type: ignore
|
|
@@ -16,93 +21,172 @@ from tg_model.yaml import ( # type: ignore
|
|
|
16
21
|
ProjectConfig,
|
|
17
22
|
)
|
|
18
23
|
|
|
19
|
-
from
|
|
20
|
-
|
|
24
|
+
from tgp_backend.config import MAIN_PATH
|
|
21
25
|
from tgp_backend.tgclient import TGclient
|
|
22
|
-
from tgp_backend.util import
|
|
26
|
+
from tgp_backend.util import (
|
|
27
|
+
list_files_and_folders,
|
|
28
|
+
get_selectable_folders,
|
|
29
|
+
)
|
|
23
30
|
|
|
24
31
|
log = logging.getLogger(__name__)
|
|
25
32
|
|
|
26
|
-
MAIN_PATH = config("main", "path", default="./projects")
|
|
27
|
-
|
|
28
33
|
|
|
29
34
|
class Project(object):
|
|
30
|
-
def __init__(self,
|
|
31
|
-
self.
|
|
32
|
-
self.
|
|
33
|
-
self.datapath = f"{self.fullpath}/data"
|
|
34
|
-
self.metadatapath = f"{self.fullpath}/metadata"
|
|
35
|
-
self._main_config = None
|
|
35
|
+
def __init__(self, path):
|
|
36
|
+
self.path = path
|
|
37
|
+
self._project_config = None
|
|
36
38
|
self._collections = None
|
|
37
39
|
self._nextcloud = None
|
|
38
40
|
self.tgm_project = TGMProject(self.metadatapath)
|
|
39
41
|
|
|
42
|
+
@property
|
|
43
|
+
def name(self):
|
|
44
|
+
log.warning("Project.name is deprecated, use Project.path instead")
|
|
45
|
+
return self.path
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def fullpath(self):
|
|
49
|
+
return f"{MAIN_PATH}/{self.path}"
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def title(self):
|
|
53
|
+
return self.project_config.title
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def description(self):
|
|
57
|
+
return self.project_config.description
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def collectors(self):
|
|
61
|
+
return self.project_config.collectors
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def path_data(self):
|
|
65
|
+
return os.path.join(self.fullpath, "data")
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def path_metadata(self):
|
|
69
|
+
return os.path.join(self.fullpath, "metadata")
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def path_otherfiles(self):
|
|
73
|
+
return os.path.join(self.path_metadata, "other_files")
|
|
74
|
+
|
|
40
75
|
def create(self):
|
|
41
76
|
if not os.path.exists(self.fullpath):
|
|
42
77
|
os.makedirs(self.fullpath)
|
|
43
|
-
os.makedirs(self.
|
|
44
|
-
os.makedirs(self.
|
|
78
|
+
os.makedirs(self.path_data)
|
|
79
|
+
os.makedirs(self.path_metadata)
|
|
45
80
|
else:
|
|
46
81
|
log.warning("Project already exists!")
|
|
47
82
|
|
|
83
|
+
@property
|
|
84
|
+
def avatar(self):
|
|
85
|
+
if self.project_config.avatar:
|
|
86
|
+
return os.path.join(
|
|
87
|
+
self.path_otherfiles, self.project_config.avatar
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def xslt(self):
|
|
92
|
+
if self.project_config.xslt:
|
|
93
|
+
return os.path.join(self.path_otherfiles, self.project_config.xslt)
|
|
94
|
+
|
|
95
|
+
def save_avatar(self, file):
|
|
96
|
+
if file.filename and file.filename != "":
|
|
97
|
+
file.save(os.path.join(self.path_otherfiles, file.filename))
|
|
98
|
+
self.project_config.avatar = file.filename
|
|
99
|
+
|
|
100
|
+
def save_xslt(self, file):
|
|
101
|
+
if file.filename and file.filename != "":
|
|
102
|
+
file.save(os.path.join(self.path_otherfiles, file.filename))
|
|
103
|
+
self.project_config.xslt = file.filename
|
|
104
|
+
|
|
105
|
+
def clear_xslt(self):
|
|
106
|
+
self.project_config.xslt = None
|
|
107
|
+
self.project_config.save()
|
|
108
|
+
|
|
109
|
+
def update(self, title, description, collectors, avatar, xslt):
|
|
110
|
+
self.project_config.title = title
|
|
111
|
+
self.project_config.description = description
|
|
112
|
+
self.project_config.collectors = collectors
|
|
113
|
+
|
|
114
|
+
if avatar:
|
|
115
|
+
self.save_avatar(avatar)
|
|
116
|
+
self.save_xslt(xslt)
|
|
117
|
+
|
|
118
|
+
self.project_config.save()
|
|
119
|
+
|
|
48
120
|
def clone_git_project(self, url):
|
|
49
121
|
repo_name = url.split("/")[-1].replace(".git", "")
|
|
50
|
-
repo_path = os.path.join(self.
|
|
122
|
+
repo_path = os.path.join(self.path_data, repo_name)
|
|
51
123
|
|
|
52
124
|
if not os.path.exists(repo_path):
|
|
53
125
|
subprocess.run(["git", "clone", url, repo_path])
|
|
54
126
|
else:
|
|
55
|
-
log.
|
|
127
|
+
log.info("Repository already exists!")
|
|
56
128
|
|
|
57
129
|
def file_upload(self, files):
|
|
58
130
|
for file in files:
|
|
59
131
|
if file:
|
|
60
132
|
filename = file.filename
|
|
61
|
-
filepath = os.path.join(self.
|
|
133
|
+
filepath = os.path.join(self.path_data, filename)
|
|
62
134
|
directory = os.path.dirname(filepath)
|
|
63
135
|
if not os.path.exists(directory):
|
|
64
136
|
os.makedirs(directory)
|
|
65
137
|
file.save(filepath)
|
|
66
138
|
|
|
67
139
|
def list_files_and_folders(self):
|
|
68
|
-
return list_files_and_folders(self.
|
|
140
|
+
return list_files_and_folders(self.path_data)
|
|
141
|
+
|
|
142
|
+
def get_selectable_folders(self):
|
|
143
|
+
selectable_folders = get_selectable_folders(self.path_data)
|
|
144
|
+
for folder in selectable_folders:
|
|
145
|
+
folder["relative_path"] = folder["path"].replace(
|
|
146
|
+
self.path_data, ""
|
|
147
|
+
)
|
|
148
|
+
return selectable_folders
|
|
69
149
|
|
|
70
150
|
@property
|
|
71
151
|
def main_config(self):
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return self._main_config
|
|
75
|
-
|
|
76
|
-
@main_config.setter
|
|
77
|
-
def main_config(self, tei_directories):
|
|
78
|
-
self._main_config = ProjectConfigTemplate(self.metadatapath).render(
|
|
79
|
-
tei_directories=tei_directories
|
|
152
|
+
log.warning(
|
|
153
|
+
"Project.main_config is deprecated, use Project.project_config instead"
|
|
80
154
|
)
|
|
155
|
+
return self.project_config
|
|
81
156
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
157
|
+
@property
|
|
158
|
+
def project_config(self):
|
|
159
|
+
if not self._project_config:
|
|
160
|
+
self._project_config = ProjectConfig(
|
|
161
|
+
projectpath=self.path_metadata
|
|
162
|
+
)
|
|
163
|
+
if not self._project_config.exists():
|
|
164
|
+
self._project_config = ProjectConfigTemplate(
|
|
165
|
+
self.path_metadata
|
|
166
|
+
).render()
|
|
167
|
+
self._project_config.title = self.path
|
|
168
|
+
self._project_config.save()
|
|
169
|
+
|
|
170
|
+
return self._project_config
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def project_handler(self):
|
|
174
|
+
return ProjectHandler(self.path_metadata)
|
|
91
175
|
|
|
92
176
|
def get_subproject_inpath(self, name):
|
|
93
|
-
for subproject in self.
|
|
177
|
+
for subproject in self.project_config.content["subprojects"]:
|
|
94
178
|
if subproject["name"] == name:
|
|
95
179
|
return subproject["inpath"]
|
|
96
180
|
return None
|
|
97
181
|
|
|
98
182
|
def _set_collections(self):
|
|
99
183
|
self._collections = {}
|
|
100
|
-
if self.
|
|
101
|
-
for subproject in self.
|
|
184
|
+
if self.project_config.exists():
|
|
185
|
+
for subproject in self.project_config.content["subprojects"]:
|
|
102
186
|
collection_config = CollectionConfig(subproject["basepath"])
|
|
103
187
|
if not collection_config.exists():
|
|
104
188
|
collection_config = CollectionConfigTemplate(
|
|
105
|
-
projectpath=self.
|
|
189
|
+
projectpath=self.path_metadata,
|
|
106
190
|
subproject=subproject,
|
|
107
191
|
files=[
|
|
108
192
|
TEIParser(fullpath=file)
|
|
@@ -115,7 +199,7 @@ class Project(object):
|
|
|
115
199
|
"paths": subproject,
|
|
116
200
|
"parser": CollectionParser(collection_config),
|
|
117
201
|
"modeler": CollectionModeler(
|
|
118
|
-
subproject, self.
|
|
202
|
+
subproject, self.path_metadata
|
|
119
203
|
),
|
|
120
204
|
}
|
|
121
205
|
|
|
@@ -134,6 +218,49 @@ class Project(object):
|
|
|
134
218
|
def get_tgp(self, instance):
|
|
135
219
|
return TGProject(self, instance)
|
|
136
220
|
|
|
221
|
+
def _save_validation_results(self, results, filepath):
|
|
222
|
+
"""
|
|
223
|
+
Saves the validation results to a JSON file.
|
|
224
|
+
Adds the date of the last execution.
|
|
225
|
+
"""
|
|
226
|
+
results["last_run"] = datetime.now().strftime("%Y-%m-%d %H:%M")
|
|
227
|
+
|
|
228
|
+
with open(filepath, "w", encoding="utf-8") as f:
|
|
229
|
+
json.dump(results, f, indent=4, ensure_ascii=False)
|
|
230
|
+
|
|
231
|
+
log.info(f"Validation results saved to {filepath}")
|
|
232
|
+
|
|
233
|
+
def _run_validation(self):
|
|
234
|
+
validation_results = self.project_handler.validate()
|
|
235
|
+
self._save_validation_results(validation_results, self.validation_file)
|
|
236
|
+
return validation_results
|
|
237
|
+
|
|
238
|
+
@property
|
|
239
|
+
def validation_file(self):
|
|
240
|
+
"""
|
|
241
|
+
Returns the path to the validation results file.
|
|
242
|
+
"""
|
|
243
|
+
return os.path.join(self.path_metadata, "validation_results.json")
|
|
244
|
+
|
|
245
|
+
def get_validation_results(self, refresh=False):
|
|
246
|
+
"""
|
|
247
|
+
Returns stored validation results.
|
|
248
|
+
If no results are saved or `refresh=True`, a new validation will
|
|
249
|
+
be performed.
|
|
250
|
+
"""
|
|
251
|
+
# If `refresh` is set or file doesn't exist, perform new validation
|
|
252
|
+
if refresh or not os.path.exists(self.validation_file):
|
|
253
|
+
validation_results = self._run_validation()
|
|
254
|
+
else:
|
|
255
|
+
# Load results from file
|
|
256
|
+
with open(self.validation_file, "r", encoding="utf-8") as f:
|
|
257
|
+
validation_results = json.load(f)
|
|
258
|
+
|
|
259
|
+
if "ready_for_publication" not in validation_results:
|
|
260
|
+
validation_results = self._run_validation()
|
|
261
|
+
|
|
262
|
+
return validation_results
|
|
263
|
+
|
|
137
264
|
|
|
138
265
|
class TGProject(object):
|
|
139
266
|
|
|
@@ -143,7 +270,7 @@ class TGProject(object):
|
|
|
143
270
|
else:
|
|
144
271
|
self.project = Project(project)
|
|
145
272
|
self.instance = instance
|
|
146
|
-
self.
|
|
273
|
+
self.project_config = self.project.project_config
|
|
147
274
|
self.collections = self.project.collections
|
|
148
275
|
self._tg_client = None
|
|
149
276
|
self._tg_session_id = None
|
|
@@ -152,7 +279,7 @@ class TGProject(object):
|
|
|
152
279
|
@property
|
|
153
280
|
def tg_session_id(self):
|
|
154
281
|
if not self._tg_session_id:
|
|
155
|
-
self._tg_session_id = self.
|
|
282
|
+
self._tg_session_id = self.project_config.get_tg_session_id(
|
|
156
283
|
self.instance
|
|
157
284
|
)
|
|
158
285
|
return self._tg_session_id
|
|
@@ -160,12 +287,12 @@ class TGProject(object):
|
|
|
160
287
|
@tg_session_id.setter
|
|
161
288
|
def tg_session_id(self, session_id):
|
|
162
289
|
self._tg_session_id = session_id
|
|
163
|
-
self.
|
|
290
|
+
self.project_config.set_tg_session_id(session_id, self.instance)
|
|
164
291
|
|
|
165
292
|
@property
|
|
166
293
|
def tg_project_id(self):
|
|
167
294
|
if not self._tg_project_id:
|
|
168
|
-
self._tg_project_id = self.
|
|
295
|
+
self._tg_project_id = self.project_config.get_tg_project_id(
|
|
169
296
|
self.instance
|
|
170
297
|
)
|
|
171
298
|
return self._tg_project_id
|
|
@@ -173,7 +300,7 @@ class TGProject(object):
|
|
|
173
300
|
@tg_project_id.setter
|
|
174
301
|
def tg_project_id(self, project_id):
|
|
175
302
|
self._tg_project_id = project_id
|
|
176
|
-
self.
|
|
303
|
+
self.project_config.set_tg_project_id(project_id, self.instance)
|
|
177
304
|
|
|
178
305
|
@property
|
|
179
306
|
def tg_client(self):
|
|
@@ -208,7 +335,7 @@ class TGProject(object):
|
|
|
208
335
|
if self.tg_session_id:
|
|
209
336
|
return self.tg_client.get_project_content(project_id).hits
|
|
210
337
|
|
|
211
|
-
def
|
|
338
|
+
def upload_tg_project(self, instance="test"):
|
|
212
339
|
if not self.tg_session_id:
|
|
213
340
|
return False
|
|
214
341
|
|