tg-prepare 2.2.2__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.
Files changed (82) hide show
  1. tg_prepare-2.2.2.dist-info/METADATA +20 -0
  2. tg_prepare-2.2.2.dist-info/RECORD +82 -0
  3. tg_prepare-2.2.2.dist-info/WHEEL +5 -0
  4. tg_prepare-2.2.2.dist-info/entry_points.txt +4 -0
  5. tg_prepare-2.2.2.dist-info/licenses/LICENSE +202 -0
  6. tg_prepare-2.2.2.dist-info/projects/.secret_key +1 -0
  7. tg_prepare-2.2.2.dist-info/top_level.txt +2 -0
  8. tgp_backend/__init__.py +17 -0
  9. tgp_backend/auth.py +71 -0
  10. tgp_backend/cli.py +95 -0
  11. tgp_backend/config.py +35 -0
  12. tgp_backend/directories.py +79 -0
  13. tgp_backend/interfaces.py +3 -0
  14. tgp_backend/nextcloud.py +146 -0
  15. tgp_backend/project.py +468 -0
  16. tgp_backend/session_manager.py +47 -0
  17. tgp_backend/tgclient.py +187 -0
  18. tgp_backend/user.py +137 -0
  19. tgp_backend/util.py +131 -0
  20. tgp_ui/__init__.py +0 -0
  21. tgp_ui/app.py +150 -0
  22. tgp_ui/routes/__init__.py +0 -0
  23. tgp_ui/routes/auth.py +72 -0
  24. tgp_ui/routes/collection.py +319 -0
  25. tgp_ui/routes/data.py +229 -0
  26. tgp_ui/routes/project.py +103 -0
  27. tgp_ui/routes/publication.py +229 -0
  28. tgp_ui/routes/tabs.py +34 -0
  29. tgp_ui/routes/views.py +66 -0
  30. tgp_ui/static/css/bootstrap-icons.min.css +5 -0
  31. tgp_ui/static/css/bootstrap.min.css +6 -0
  32. tgp_ui/static/css/bootstrap.min.css.map +1 -0
  33. tgp_ui/static/css/main.css +141 -0
  34. tgp_ui/static/css/navbar.css +92 -0
  35. tgp_ui/static/css/simpleXML.css +67 -0
  36. tgp_ui/static/img/favicon.ico +0 -0
  37. tgp_ui/static/img/textgrid-logo.svg +1 -0
  38. tgp_ui/static/js/bootstrap.bundle.min.js +7 -0
  39. tgp_ui/static/js/collectionManager.js +60 -0
  40. tgp_ui/static/js/fileManager.js +153 -0
  41. tgp_ui/static/js/jquery.min.js +2 -0
  42. tgp_ui/static/js/main.js +36 -0
  43. tgp_ui/static/js/modalManager.js +105 -0
  44. tgp_ui/static/js/navbarManager.js +151 -0
  45. tgp_ui/static/js/projectManager.js +60 -0
  46. tgp_ui/static/js/require.js +5 -0
  47. tgp_ui/static/js/sidebarManager.js +44 -0
  48. tgp_ui/static/js/simpleXML.js +193 -0
  49. tgp_ui/static/js/tabManager.js +83 -0
  50. tgp_ui/templates/auth/login.html +42 -0
  51. tgp_ui/templates/details/empty_container.html +16 -0
  52. tgp_ui/templates/details/manage_collection.html +209 -0
  53. tgp_ui/templates/file_tree.html +39 -0
  54. tgp_ui/templates/includes/get_sessionid.html +29 -0
  55. tgp_ui/templates/includes/publish_form.html +55 -0
  56. tgp_ui/templates/includes/set_sessionid.html +26 -0
  57. tgp_ui/templates/includes/upload_form.html +258 -0
  58. tgp_ui/templates/layout.html +74 -0
  59. tgp_ui/templates/macros.html +101 -0
  60. tgp_ui/templates/modal/delete_project.html +25 -0
  61. tgp_ui/templates/modal/empty_container.html +9 -0
  62. tgp_ui/templates/modal/file_explorer_content.html +34 -0
  63. tgp_ui/templates/modal/file_explorer_main.html +22 -0
  64. tgp_ui/templates/modal/file_explorer_nextcloud.html +27 -0
  65. tgp_ui/templates/modal/github_modal.html +29 -0
  66. tgp_ui/templates/modal/nextcloud_login.html +48 -0
  67. tgp_ui/templates/modal/tei_explorer.html +58 -0
  68. tgp_ui/templates/modal/xpath_parser.html +52 -0
  69. tgp_ui/templates/nxc_login.html +25 -0
  70. tgp_ui/templates/nxc_tab.html +15 -0
  71. tgp_ui/templates/project_main.html +36 -0
  72. tgp_ui/templates/project_navbar.html +81 -0
  73. tgp_ui/templates/projects_main.html +58 -0
  74. tgp_ui/templates/tabs/check_upload.html +87 -0
  75. tgp_ui/templates/tabs/edit_project.html +113 -0
  76. tgp_ui/templates/tabs/empty_container.html +12 -0
  77. tgp_ui/templates/tabs/import_data.html +122 -0
  78. tgp_ui/templates/tabs/manage_collections.html +107 -0
  79. tgp_ui/templates/tabs/publication.html +42 -0
  80. tgp_ui/templates/tabs/select_directories.html +68 -0
  81. tgp_ui/templates/tabs/upload.html +42 -0
  82. tgp_ui/templates/tabs/validate_metadata.html +227 -0
@@ -0,0 +1,319 @@
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
+ import os
9
+
10
+ from flask import Blueprint, render_template, request, send_file
11
+ from flask_json import json_response
12
+ from flask_login import current_user
13
+
14
+ from io import BytesIO
15
+
16
+ from tg_model.tei import TEIParser
17
+
18
+ from tgp_backend.directories import generateList
19
+ from tgp_backend.project import Project
20
+ from tgp_backend.util import parse_request_data
21
+
22
+ log = logging.getLogger(__name__)
23
+
24
+ collection_routes = Blueprint("collection", __name__)
25
+
26
+
27
+ # ***TABS***
28
+ # **********
29
+ @collection_routes.route(
30
+ "/tab_select_directories/<string:projectname>", methods=["GET", "POST"]
31
+ )
32
+ def tab_select_directories(projectname):
33
+
34
+ project = Project(projectname, current_user.username)
35
+ if request.method == "POST":
36
+ project.project_config.update(
37
+ tei_directories=request.form.getlist("selected_folder")
38
+ )
39
+
40
+ tei_directories = [
41
+ sp["inpath"] for sp in project.project_config.get_subprojects()
42
+ ]
43
+
44
+ return render_template(
45
+ "tabs/select_directories.html",
46
+ project=project,
47
+ selected_directories=tei_directories,
48
+ )
49
+
50
+
51
+ @collection_routes.route(
52
+ "/tab_manage_collections/<string:projectname>", methods=["GET"]
53
+ )
54
+ def tab_manage_collections(projectname):
55
+
56
+ project = Project(projectname, current_user.username)
57
+
58
+ return render_template(
59
+ "tabs/manage_collections.html",
60
+ project=project,
61
+ )
62
+
63
+
64
+ @collection_routes.route(
65
+ "/tab_validate_metadata/<string:projectname>", methods=["GET"]
66
+ )
67
+ @collection_routes.route(
68
+ "/tab_validate_metadata/<string:projectname>/<string:refresh>",
69
+ methods=["GET"],
70
+ )
71
+ def tab_validate_metadata(projectname, refresh=False):
72
+
73
+ project = Project(projectname, current_user.username)
74
+ return render_template(
75
+ "tabs/validate_metadata.html",
76
+ projectname=projectname,
77
+ validation_results=project.get_validation_results(refresh=refresh),
78
+ )
79
+
80
+
81
+ # ***OTHER***
82
+ # **********
83
+ @collection_routes.route(
84
+ "/load_collection/<string:projectname>/<string:collectionname>",
85
+ methods=["GET"],
86
+ )
87
+ def load_collection(projectname, collectionname):
88
+ collection = None
89
+ project = Project(projectname, current_user.username)
90
+ collection = None
91
+ if collectionname:
92
+ collection = project.get_collection(collectionname)
93
+
94
+ return render_template(
95
+ "details/manage_collection.html",
96
+ collectionname=collectionname,
97
+ collection=collection["config"],
98
+ project=project,
99
+ )
100
+
101
+
102
+ @collection_routes.route(
103
+ "/save_collection_attributes/<string:projectname>/<string:collectionname>",
104
+ methods=["POST"],
105
+ )
106
+ def save_collection_attributes(projectname, collectionname):
107
+ project = Project(projectname, current_user.username)
108
+ collection = project.get_collection(collectionname)
109
+ collection_config = collection["config"]
110
+
111
+ multi_attribs = ["collector", "rights_holder"]
112
+ for multi_attrib in multi_attribs:
113
+ elements = []
114
+ for name, url in zip(
115
+ request.form.getlist(f"{multi_attrib}_name"),
116
+ request.form.getlist(f"{multi_attrib}_url"),
117
+ ):
118
+ elements.append({"fullname": name, "url": url})
119
+ setattr(collection_config, multi_attrib, elements)
120
+
121
+ for attrib in ["short_title", "long_title"]:
122
+ value = request.form.get(attrib)
123
+ setattr(collection_config, attrib, value)
124
+
125
+ collection_config.save()
126
+ return load_collection(
127
+ projectname=projectname, collectionname=collectionname
128
+ )
129
+
130
+
131
+ @collection_routes.route(
132
+ "/save_collection_classifications/<string:projectname>/<string:collectionname>",
133
+ methods=["POST"],
134
+ )
135
+ def save_collection_classifications(projectname, collectionname):
136
+ project = Project(projectname, current_user.username)
137
+ collection = project.get_collection(collectionname)
138
+ collection_config = collection["config"]
139
+
140
+ # Save basic classifications...
141
+ collection_config.basic_classifications = parse_request_data(
142
+ request, "basic_classifications"
143
+ )
144
+ # ...and GND subjects
145
+ collection_config.gnd_subjects = parse_request_data(
146
+ request, "gnd_subjects"
147
+ )
148
+
149
+ collection_config.save()
150
+ return load_collection(
151
+ projectname=projectname, collectionname=collectionname
152
+ )
153
+
154
+
155
+ @collection_routes.route(
156
+ "/save_collection_metadata/<string:projectname>/<string:collectionname>",
157
+ methods=["POST"],
158
+ )
159
+ def save_collection_metadata(projectname, collectionname):
160
+ project = Project(projectname, current_user.username)
161
+ collection = project.get_collection(collectionname)
162
+ collection_config = collection["config"]
163
+ for attrib in request.form:
164
+ if "xpath" in attrib:
165
+ key = attrib.replace("_xpath", "")
166
+ type_ = "xpath"
167
+ elif "value" in attrib:
168
+ key = attrib.replace("_value", "")
169
+ type_ = "value"
170
+ if key in collection_config.xpath_or_value_attribs:
171
+ cc_attrib = getattr(collection_config, key)
172
+ cc_attrib[type_] = request.form.get(attrib)
173
+ else:
174
+ log.warning(
175
+ f"Attribute '{attrib}' not found in collection config."
176
+ )
177
+ collection_config.save()
178
+ return load_collection(
179
+ projectname=projectname, collectionname=collectionname
180
+ )
181
+
182
+
183
+ @collection_routes.route(
184
+ "/download_collection_yaml/<string:projectname>/<string:collectionname>",
185
+ methods=["GET"],
186
+ )
187
+ def download_collection_yaml(projectname, collectionname):
188
+ project = Project(projectname, current_user.username)
189
+ collection = project.get_collection(collectionname)
190
+ return send_file(
191
+ collection["config"].path,
192
+ mimetype="application/yaml",
193
+ as_attachment=True,
194
+ download_name=f"{collectionname}.yaml",
195
+ )
196
+
197
+
198
+ @collection_routes.route(
199
+ "/upload_collection_yaml/<string:projectname>/<string:collectionname>",
200
+ methods=["POST"],
201
+ )
202
+ def upload_collection_yaml(projectname, collectionname):
203
+ collection = Project(projectname, current_user.username).get_collection(
204
+ collectionname
205
+ )
206
+
207
+ # Get the uploaded file and save it to the collection config path
208
+ new_config_file = request.files.get("config")
209
+ new_config_file.save(collection["config"].path)
210
+
211
+ # Reload the collection config
212
+ new_collection = Project(
213
+ projectname, current_user.username
214
+ ).get_collection(collectionname)
215
+
216
+ # Preserve short and long title
217
+ for key in ["short_title", "long_title"]:
218
+ setattr(
219
+ new_collection["config"], key, getattr(collection["config"], key)
220
+ )
221
+ new_collection["config"].save()
222
+
223
+ # reload the collection view
224
+ return load_collection(
225
+ projectname=projectname, collectionname=collectionname
226
+ )
227
+
228
+
229
+ @collection_routes.route(
230
+ "/modal/tei_explorer/<string:projectname>/<string:collectionname>",
231
+ methods=["GET", "POST"],
232
+ )
233
+ def modal_tei_explorer(projectname, collectionname):
234
+ project = Project(projectname, current_user.username)
235
+ # collection = project.get_collection(collectionname)
236
+ dir_list_dict, file_list_dict = generateList(
237
+ project.get_subproject_inpath(collectionname)
238
+ )
239
+
240
+ xpath = request.args.get("xpath", "")
241
+
242
+ return render_template(
243
+ "modal/tei_explorer.html",
244
+ projectname=projectname,
245
+ collectionname=collectionname,
246
+ dir_list=dir_list_dict,
247
+ file_list=file_list_dict,
248
+ xpath=xpath,
249
+ project=project,
250
+ )
251
+
252
+
253
+ @collection_routes.route("/load_tei_content", methods=["GET"])
254
+ def load_tei_content():
255
+ path = request.args.get("path")
256
+ log.debug("load_tei_content path: %s" % path)
257
+ _type = request.args.get("type")
258
+ if path is not None:
259
+ tei_parser = TEIParser(fullpath=path)
260
+ if _type == "header":
261
+ return json_response(
262
+ value="OK",
263
+ content=tei_parser.find(
264
+ "//teiHeader", node_as_text=True
265
+ ).decode("utf-8"),
266
+ )
267
+ elif _type == "text":
268
+ return json_response(
269
+ value="OK",
270
+ content=tei_parser.find(".//text", node_as_text=True).decode(
271
+ "utf-8"
272
+ ),
273
+ )
274
+ return json_response(value="Unknown type requested!")
275
+
276
+
277
+ @collection_routes.route(
278
+ "/modal/xpath_parser/<string:projectname>/<string:collectionname>",
279
+ methods=["GET", "POST"],
280
+ )
281
+ def modal_xpath_parser(
282
+ projectname,
283
+ collectionname,
284
+ ):
285
+ project = Project(projectname, current_user.username)
286
+ collection = project.get_collection(
287
+ collectionname,
288
+ )
289
+ collection_parser = collection["parser"]
290
+
291
+ xpath = request.args.get("xpath")
292
+ if not xpath:
293
+ xpath = request.form.get("xpath", "")
294
+
295
+ return render_template(
296
+ "modal/xpath_parser.html",
297
+ xpath=xpath,
298
+ projectname=projectname,
299
+ collectionname=collectionname,
300
+ collection_parser=collection_parser,
301
+ )
302
+
303
+
304
+ @collection_routes.route("/export_tsv/<projectname>/<collectionname>")
305
+ def export_tsv(projectname, collectionname):
306
+ project = Project(projectname, current_user.username)
307
+ collection = project.get_collection(
308
+ collectionname,
309
+ )
310
+ filepath = collection["modeler"].export()
311
+ if os.path.isfile(filepath):
312
+ with open(filepath, "rb") as file:
313
+ file_content = BytesIO(file.read())
314
+
315
+ return send_file(
316
+ file_content,
317
+ download_name=os.path.basename(filepath),
318
+ as_attachment=True,
319
+ )
tgp_ui/routes/data.py ADDED
@@ -0,0 +1,229 @@
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
+ import os
9
+ import shutil
10
+
11
+ from flask import Blueprint, render_template, request, send_file, session
12
+ from flask_json import json_response
13
+ from flask_login import current_user
14
+
15
+ from io import BytesIO
16
+
17
+ from tgp_backend.config import MAIN_PATH
18
+ from tgp_backend.nextcloud import Nextcloud
19
+ from tgp_backend.project import Project
20
+ from tgp_backend.session_manager import SessionManagerNextcloud
21
+
22
+ log = logging.getLogger(__name__)
23
+
24
+ data_routes = Blueprint("data", __name__)
25
+
26
+
27
+ # ***TABS***
28
+ # **********
29
+ @data_routes.route("/tab-import-data/<string:projectname>", methods=["GET"])
30
+ def tab_import_data(projectname=None, project=None, error_message=None):
31
+ if not project:
32
+ if not projectname:
33
+ raise ValueError("Project name must be provided.")
34
+ else:
35
+ project = Project(projectname, current_user.username)
36
+ return render_template(
37
+ "tabs/import_data.html",
38
+ project=project,
39
+ error_message=error_message,
40
+ )
41
+
42
+
43
+ # ***DIRECT UPLOAD***
44
+ # *******************
45
+ @data_routes.route("/upload_files/<string:projectname>", methods=["POST"])
46
+ def upload_files(projectname=None):
47
+ project = Project(projectname, current_user.username)
48
+ project.file_upload(request.files.getlist("files"))
49
+
50
+ return tab_import_data(project=project)
51
+
52
+
53
+ # ***GITHUB***
54
+ # ************
55
+ @data_routes.route("/modal/github/<projectname>", methods=["GET", "POST"])
56
+ def modal_github(projectname):
57
+ """
58
+ Render the Github modal.
59
+ """
60
+ project = Project(projectname, current_user.username)
61
+ return render_template(
62
+ "modal/github_modal.html",
63
+ project=project,
64
+ )
65
+
66
+
67
+ @data_routes.route("/clone_git_project/<string:projectname>", methods=["POST"])
68
+ def clone_git_project(projectname=None):
69
+ project = Project(projectname, current_user.username)
70
+ project.clone_git_project(request.form.get("github_repo"))
71
+
72
+ return tab_import_data(project=project)
73
+
74
+
75
+ # ***NEXTCLOUD***
76
+ # ***************
77
+
78
+
79
+ def render_nextcloud_tree(projectname, items):
80
+ """
81
+ Render the Nextcloud tree view.
82
+ """
83
+ # items = items or nc.nxc_list_files_and_folders()
84
+ project = Project(projectname, current_user.username)
85
+ return render_template(
86
+ "modal/file_explorer_nextcloud.html",
87
+ project=project,
88
+ items=items,
89
+ show_checkbox=True,
90
+ show_all_folders=True,
91
+ )
92
+
93
+
94
+ def render_nextcloud_login(projectname, message=None):
95
+ """
96
+ Render the Nextcloud login form.
97
+ """
98
+ return render_template(
99
+ "modal/nextcloud_login.html", projectname=projectname, message=message
100
+ )
101
+
102
+
103
+ @data_routes.route("/modal/nextcloud/<projectname>", methods=["GET", "POST"])
104
+ @data_routes.route(
105
+ "/modal/nextcloud/<projectname>/<logout>", methods=["GET", "POST"]
106
+ )
107
+ def modal_nextcloud(projectname, form_type=None, logout=False):
108
+
109
+ nxc_session_manager = SessionManagerNextcloud(session)
110
+
111
+ if logout:
112
+ # If the user wants to log out, delete the session credentials
113
+ nxc_session_manager.delete_nextcloud_credentials()
114
+ return render_nextcloud_login(projectname, message="You logged out.")
115
+
116
+ nc = Nextcloud(**nxc_session_manager.get_credentials())
117
+ if nc.test_connection():
118
+ # An active Nextcloud session exists, so we can use it to render
119
+ # the tree view
120
+ return render_nextcloud_tree(
121
+ projectname, nc.nxc_list_files_and_folders()
122
+ )
123
+ elif nxc_session_manager.request_has_valid_credentials(request):
124
+ # If credentials are provided,
125
+ # Recreate a Nextcloud instance and test the connection
126
+ nxc_session_manager.save_credentials(request.form)
127
+ nc = Nextcloud(**nxc_session_manager.get_credentials())
128
+ if nc.test_connection():
129
+ return render_nextcloud_tree(
130
+ projectname, nc.nxc_list_files_and_folders()
131
+ )
132
+
133
+ else:
134
+ return render_nextcloud_login(
135
+ projectname,
136
+ message="Login failed. Please check your credentials.",
137
+ )
138
+ else:
139
+ # If no valid credentials are provided, render the login form
140
+ log.info("No valid Nextcloud credentials found, showing login form.")
141
+ # This will clear any previous session data
142
+ nxc_session_manager.delete_nextcloud_credentials()
143
+ return render_nextcloud_login(projectname)
144
+
145
+
146
+ @data_routes.route("/download_nextcloud/<projectname>", methods=["POST"])
147
+ def download_nextcloud(projectname):
148
+
149
+ nxc_session_manager = SessionManagerNextcloud(session)
150
+
151
+ selected_option = request.form.getlist("selected_folder")
152
+
153
+ if selected_option:
154
+ nc = Nextcloud(**nxc_session_manager.get_credentials())
155
+ nc.download_nxc_files(selected_option, projectname=projectname)
156
+
157
+ return json_response(
158
+ status=200,
159
+ message="Downloaded.",
160
+ )
161
+ else:
162
+ return json_response(
163
+ status=400, message="No folder selected for download."
164
+ )
165
+
166
+
167
+ # ***OTHER***
168
+ # *******************
169
+ @data_routes.route("/image/<path:filepath>")
170
+ def serve_image(filepath):
171
+ filepath = "/" + filepath
172
+ if os.path.isfile(filepath):
173
+ return send_file(filepath)
174
+ return "", 404
175
+
176
+
177
+ @data_routes.route("/file/<path:filepath>")
178
+ def serve_file(filepath):
179
+
180
+ filepath = "/" + filepath
181
+
182
+ if os.path.isfile(filepath):
183
+ with open(filepath, "rb") as file:
184
+ file_content = BytesIO(file.read())
185
+
186
+ return send_file(
187
+ file_content,
188
+ download_name=os.path.basename(filepath),
189
+ as_attachment=True,
190
+ )
191
+
192
+
193
+ @data_routes.route("/api/delete-folder", methods=["DELETE"])
194
+ def delete_folder():
195
+ error_message = None # Variable für die Fehlermeldung
196
+ try:
197
+ path = request.form.get("path")
198
+ projectname = request.form.get("projectname")
199
+
200
+ if not path:
201
+ error_message = "No path specified"
202
+ elif not path.startswith(MAIN_PATH):
203
+ # Security check to ensure path is within allowed directory
204
+ error_message = "Invalid path"
205
+ elif not os.path.exists(path):
206
+ # Check if path exists
207
+ error_message = "Path not found"
208
+ else:
209
+ # Check if the path is a file or a folder
210
+ if os.path.isfile(path):
211
+ # Delete the file
212
+ os.remove(path)
213
+ log.info(f"File deleted: {path}")
214
+ elif os.path.isdir(path):
215
+ # Delete the folder and its contents
216
+ shutil.rmtree(path)
217
+ log.info(f"Folder deleted: {path}")
218
+ else:
219
+ error_message = "Path is neither a file nor a folder"
220
+
221
+ except Exception as e:
222
+ log.error(f"Error deleting path: {e}")
223
+ error_message = f"An error occurred: {str(e)}"
224
+
225
+ # Am Ende einmal `tab_import_data` aufrufen
226
+ return tab_import_data(
227
+ projectname=projectname,
228
+ error_message=error_message,
229
+ )
@@ -0,0 +1,103 @@
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
+ import os
9
+ import shutil
10
+
11
+ from flask import Blueprint, redirect, render_template, request
12
+ from flask import url_for as default_url_for
13
+ from flask_json import json_response
14
+ from flask_login import current_user
15
+
16
+
17
+ from tgp_backend.config import MAIN_PATH
18
+ from tgp_backend.project import Project
19
+
20
+ from .views import overview
21
+
22
+ log = logging.getLogger(__name__)
23
+
24
+ project_routes = Blueprint("project", __name__)
25
+
26
+
27
+ def get_prefix():
28
+ return request.headers.get(
29
+ "X-Forwarded-Prefix", request.headers.get("X-Script-Name", "")
30
+ )
31
+
32
+
33
+ def url_for(*args, **kwargs):
34
+ """Overrides Flask's url_for globally to include the prefix"""
35
+ return get_prefix() + default_url_for(*args, **kwargs)
36
+
37
+
38
+ @project_routes.route("/new_project", methods=["POST"])
39
+ def new_project():
40
+ project = Project(request.form.get("projectname"), current_user.username)
41
+ project.create()
42
+ return redirect(url_for("views.project_view", projectname=project.path))
43
+
44
+
45
+ @project_routes.route("/delete_project/<string:projectname>", methods=["POST"])
46
+ def delete_project(projectname):
47
+
48
+ # projectname = request.form.get("projectname")
49
+ fullpath = f"{MAIN_PATH}/{projectname}"
50
+
51
+ # Delete the project
52
+ if fullpath.strip("/") == MAIN_PATH.strip("/"):
53
+ log.error(f"Cannot delete main path ({MAIN_PATH})!")
54
+ elif os.path.exists(fullpath):
55
+ shutil.rmtree(fullpath)
56
+ else:
57
+ log.warning("Project does not exist!")
58
+
59
+ return overview()
60
+
61
+
62
+ @project_routes.route(
63
+ "/modal_delete_project/<string:projectname>", methods=["POST"]
64
+ )
65
+ def modal_delete_project(projectname):
66
+ return render_template(
67
+ "modal/delete_project.html",
68
+ projectname=projectname,
69
+ )
70
+
71
+
72
+ @project_routes.route(
73
+ "/tab-edit-project/<string:projectname>", methods=["GET", "POST"]
74
+ )
75
+ def tab_edit_project(projectname):
76
+ project = Project(projectname, current_user.username)
77
+ if request.method == "POST":
78
+ collectors = []
79
+ for name, url in zip(
80
+ request.form.getlist("collector_name"),
81
+ request.form.getlist("collector_url"),
82
+ ):
83
+ collectors.append({"name": name, "url": url})
84
+
85
+ project.update(
86
+ title=request.form["title"],
87
+ description=request.form["description"],
88
+ collectors=collectors,
89
+ avatar=request.files["avatar"],
90
+ xslt=request.files.get("xslt"),
91
+ )
92
+ return render_template(
93
+ "tabs/edit_project.html",
94
+ project=project,
95
+ )
96
+
97
+
98
+ @project_routes.route("/delete-xslt/<string:projectname>", methods=["DELETE"])
99
+ def delete_xslt(projectname):
100
+ project = Project(projectname, current_user.username)
101
+ log.debug(f"Deleting XSLT for project {projectname}")
102
+ project.clear_xslt()
103
+ return json_response("OK")