ckanext-csvwmapandtransform 0.0.1__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.
- ckanext/csvwmapandtransform/__init__.py +22 -0
- ckanext/csvwmapandtransform/action.py +405 -0
- ckanext/csvwmapandtransform/assets/.gitignore +0 -0
- ckanext/csvwmapandtransform/assets/script.js +81 -0
- ckanext/csvwmapandtransform/assets/style.css +124 -0
- ckanext/csvwmapandtransform/assets/webassets.yml +13 -0
- ckanext/csvwmapandtransform/auth.py +23 -0
- ckanext/csvwmapandtransform/cli.py +18 -0
- ckanext/csvwmapandtransform/db.py +397 -0
- ckanext/csvwmapandtransform/helpers.py +67 -0
- ckanext/csvwmapandtransform/i18n/.gitignore +0 -0
- ckanext/csvwmapandtransform/i18n/ckanext-csvwmapandtransform.pot +108 -0
- ckanext/csvwmapandtransform/i18n/de/LC_MESSAGES/ckanext-csvwmapandtransform.mo +0 -0
- ckanext/csvwmapandtransform/i18n/de/LC_MESSAGES/ckanext-csvwmapandtransform.po +113 -0
- ckanext/csvwmapandtransform/mapper.py +133 -0
- ckanext/csvwmapandtransform/plugin.py +140 -0
- ckanext/csvwmapandtransform/public/.gitignore +0 -0
- ckanext/csvwmapandtransform/public/dotted.png +0 -0
- ckanext/csvwmapandtransform/tasks.py +262 -0
- ckanext/csvwmapandtransform/templates/.gitignore +0 -0
- ckanext/csvwmapandtransform/templates/csvwmapandtransform/create_mapping.html +56 -0
- ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html +108 -0
- ckanext/csvwmapandtransform/templates/package/resource_read.html +8 -0
- ckanext/csvwmapandtransform/templates/package/snippets/resource_item.html +23 -0
- ckanext/csvwmapandtransform/tests/__init__.py +0 -0
- ckanext/csvwmapandtransform/views.py +205 -0
- ckanext_csvwmapandtransform-0.0.1-py3.14-nspkg.pth +1 -0
- ckanext_csvwmapandtransform-0.0.1.dist-info/METADATA +121 -0
- ckanext_csvwmapandtransform-0.0.1.dist-info/RECORD +34 -0
- ckanext_csvwmapandtransform-0.0.1.dist-info/WHEEL +5 -0
- ckanext_csvwmapandtransform-0.0.1.dist-info/entry_points.txt +5 -0
- ckanext_csvwmapandtransform-0.0.1.dist-info/licenses/LICENSE +661 -0
- ckanext_csvwmapandtransform-0.0.1.dist-info/namespace_packages.txt +1 -0
- ckanext_csvwmapandtransform-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Abstracts a database. Used for storing logging when it aiembeddings a resource into
|
|
3
|
+
DataStore.
|
|
4
|
+
|
|
5
|
+
Loosely based on ckan-service-provider's db.py
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
Abstracts a database. Used for storing logging when it aiembeddings a resource into
|
|
10
|
+
DataStore.
|
|
11
|
+
|
|
12
|
+
Loosely based on ckan-service-provider's db.py
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import datetime
|
|
16
|
+
import json
|
|
17
|
+
|
|
18
|
+
import six
|
|
19
|
+
import sqlalchemy
|
|
20
|
+
from ckan.plugins import toolkit
|
|
21
|
+
|
|
22
|
+
ENGINE = None
|
|
23
|
+
_METADATA = None
|
|
24
|
+
JOBS_TABLE = None
|
|
25
|
+
METADATA_TABLE = None
|
|
26
|
+
LOGS_TABLE = None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def init(db_uri: str = "", echo=False):
|
|
30
|
+
"""Initialise the database.
|
|
31
|
+
|
|
32
|
+
Initialise the sqlalchemy engine, metadata and table objects that we use to
|
|
33
|
+
connect to the database.
|
|
34
|
+
|
|
35
|
+
Create the database and the database tables themselves if they don't
|
|
36
|
+
already exist.
|
|
37
|
+
|
|
38
|
+
:param uri: the sqlalchemy database URI
|
|
39
|
+
:type uri: string
|
|
40
|
+
|
|
41
|
+
:param echo: whether or not to have the sqlalchemy engine log all
|
|
42
|
+
statements to stdout
|
|
43
|
+
:type echo: bool
|
|
44
|
+
|
|
45
|
+
"""
|
|
46
|
+
if not db_uri:
|
|
47
|
+
db_uri = toolkit.config.get("ckanext.csvwmapandtransform.db_url")
|
|
48
|
+
global ENGINE, _METADATA, JOBS_TABLE, METADATA_TABLE, LOGS_TABLE
|
|
49
|
+
ENGINE = sqlalchemy.create_engine(db_uri, echo=echo, convert_unicode=True)
|
|
50
|
+
_METADATA = sqlalchemy.MetaData(ENGINE)
|
|
51
|
+
JOBS_TABLE = _init_jobs_table()
|
|
52
|
+
METADATA_TABLE = _init_metadata_table()
|
|
53
|
+
LOGS_TABLE = _init_logs_table()
|
|
54
|
+
_METADATA.create_all(ENGINE)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def drop_all():
|
|
58
|
+
"""Delete all the database tables (if they exist).
|
|
59
|
+
|
|
60
|
+
This is for tests to reset the DB. Note that this will delete *all* tables
|
|
61
|
+
in the database, not just tables created by this module (for example
|
|
62
|
+
apscheduler's tables will also be deleted).
|
|
63
|
+
|
|
64
|
+
"""
|
|
65
|
+
if _METADATA:
|
|
66
|
+
_METADATA.drop_all(ENGINE)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def delete_job(job_id):
|
|
70
|
+
"""Delete a job from the jobs table by job_id.
|
|
71
|
+
|
|
72
|
+
:param job_id: the job_id of the job to be deleted
|
|
73
|
+
:type job_id: unicode
|
|
74
|
+
"""
|
|
75
|
+
if job_id:
|
|
76
|
+
job_id = six.text_type(job_id)
|
|
77
|
+
|
|
78
|
+
msg = ""
|
|
79
|
+
with ENGINE.connect() as conn:
|
|
80
|
+
trans = conn.begin()
|
|
81
|
+
try:
|
|
82
|
+
result = conn.execute(
|
|
83
|
+
JOBS_TABLE.delete().where(JOBS_TABLE.c.job_id == job_id)
|
|
84
|
+
)
|
|
85
|
+
if result.rowcount == 0:
|
|
86
|
+
msg = f"No job found with id: {job_id}"
|
|
87
|
+
else:
|
|
88
|
+
msg = f"Job with id: {job_id} has been deleted successfully."
|
|
89
|
+
trans.commit()
|
|
90
|
+
except Exception as e:
|
|
91
|
+
trans.rollback()
|
|
92
|
+
msg = f"An error occurred: {e}"
|
|
93
|
+
return msg
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def get_job(job_id):
|
|
97
|
+
"""Return the job with the given job_id as a dict."""
|
|
98
|
+
if job_id:
|
|
99
|
+
job_id = six.text_type(job_id)
|
|
100
|
+
|
|
101
|
+
with ENGINE.connect() as conn:
|
|
102
|
+
result = conn.execute(
|
|
103
|
+
JOBS_TABLE.select().where(JOBS_TABLE.c.job_id == job_id)
|
|
104
|
+
).first()
|
|
105
|
+
|
|
106
|
+
if not result:
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
result_dict = {
|
|
110
|
+
field: (
|
|
111
|
+
value.isoformat()
|
|
112
|
+
if isinstance(value := getattr(result, field), datetime.datetime)
|
|
113
|
+
else value
|
|
114
|
+
)
|
|
115
|
+
for field in result.keys()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
result_dict["metadata"] = _get_metadata(job_id)
|
|
119
|
+
result_dict["logs"] = _get_logs(job_id)
|
|
120
|
+
|
|
121
|
+
return result_dict
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def add_pending_job(job_id, job_type, data=None, metadata=None, result_url=None):
|
|
125
|
+
"""Add a new job with status "pending" to the jobs table."""
|
|
126
|
+
if not data:
|
|
127
|
+
data = {}
|
|
128
|
+
data = six.text_type(json.dumps(data))
|
|
129
|
+
|
|
130
|
+
if job_id:
|
|
131
|
+
job_id = six.text_type(job_id)
|
|
132
|
+
if job_type:
|
|
133
|
+
job_type = six.text_type(job_type)
|
|
134
|
+
if result_url:
|
|
135
|
+
result_url = six.text_type(result_url)
|
|
136
|
+
|
|
137
|
+
if not metadata:
|
|
138
|
+
metadata = {}
|
|
139
|
+
|
|
140
|
+
with ENGINE.connect() as conn:
|
|
141
|
+
trans = conn.begin()
|
|
142
|
+
try:
|
|
143
|
+
conn.execute(
|
|
144
|
+
JOBS_TABLE.insert().values(
|
|
145
|
+
job_id=job_id,
|
|
146
|
+
job_type=job_type,
|
|
147
|
+
status="pending",
|
|
148
|
+
requested_timestamp=datetime.datetime.utcnow(),
|
|
149
|
+
sent_data=data,
|
|
150
|
+
result_url=result_url,
|
|
151
|
+
)
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
inserts = [
|
|
155
|
+
{
|
|
156
|
+
"job_id": job_id,
|
|
157
|
+
"key": six.text_type(key),
|
|
158
|
+
"value": six.text_type(
|
|
159
|
+
json.dumps(value)
|
|
160
|
+
if not isinstance(value, six.string_types)
|
|
161
|
+
else value
|
|
162
|
+
),
|
|
163
|
+
"type": (
|
|
164
|
+
"json" if not isinstance(value, six.string_types) else "string"
|
|
165
|
+
),
|
|
166
|
+
}
|
|
167
|
+
for key, value in metadata.items()
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
if inserts:
|
|
171
|
+
conn.execute(METADATA_TABLE.insert(), inserts)
|
|
172
|
+
trans.commit()
|
|
173
|
+
except Exception:
|
|
174
|
+
trans.rollback()
|
|
175
|
+
raise
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class InvalidErrorObjectError(Exception):
|
|
179
|
+
pass
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _validate_error(error):
|
|
183
|
+
"""Validate and return the given error object.
|
|
184
|
+
|
|
185
|
+
Based on the given error object, return either None or a dict with a
|
|
186
|
+
"message" key whose value is a string (the dict may also have any other
|
|
187
|
+
keys that it wants).
|
|
188
|
+
|
|
189
|
+
The given "error" object can be:
|
|
190
|
+
|
|
191
|
+
- None, in which case None is returned
|
|
192
|
+
|
|
193
|
+
- A string, in which case a dict like this will be returned:
|
|
194
|
+
{"message": error_string}
|
|
195
|
+
|
|
196
|
+
- A dict with a "message" key whose value is a string, in which case the
|
|
197
|
+
dict will be returned unchanged
|
|
198
|
+
|
|
199
|
+
:param error: the error object to validate
|
|
200
|
+
|
|
201
|
+
:raises InvalidErrorObjectError: If the error object doesn't match any of
|
|
202
|
+
the allowed types
|
|
203
|
+
|
|
204
|
+
"""
|
|
205
|
+
if error is None:
|
|
206
|
+
return None
|
|
207
|
+
elif isinstance(error, six.string_types):
|
|
208
|
+
return {"message": error}
|
|
209
|
+
else:
|
|
210
|
+
try:
|
|
211
|
+
message = error["message"]
|
|
212
|
+
if isinstance(message, six.string_types):
|
|
213
|
+
return error
|
|
214
|
+
else:
|
|
215
|
+
raise InvalidErrorObjectError("error['message'] must be a string")
|
|
216
|
+
except (TypeError, KeyError):
|
|
217
|
+
raise InvalidErrorObjectError(
|
|
218
|
+
"error must be either a string or a dict with a message key"
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _update_job(job_id, job_dict):
|
|
223
|
+
"""Update the database row for the given job_id with the given job_dict."""
|
|
224
|
+
if job_id:
|
|
225
|
+
job_id = six.text_type(job_id)
|
|
226
|
+
|
|
227
|
+
if "error" in job_dict:
|
|
228
|
+
job_dict["error"] = json.dumps(_validate_error(job_dict["error"]))
|
|
229
|
+
job_dict["error"] = six.text_type(job_dict["error"])
|
|
230
|
+
|
|
231
|
+
if "data" in job_dict:
|
|
232
|
+
job_dict["data"] = six.text_type(job_dict["data"])
|
|
233
|
+
|
|
234
|
+
with ENGINE.connect() as conn:
|
|
235
|
+
conn.execute(
|
|
236
|
+
JOBS_TABLE.update().where(JOBS_TABLE.c.job_id == job_id).values(**job_dict)
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def mark_job_as_completed(job_id, data=None):
|
|
241
|
+
"""Mark a job as completed successfully.
|
|
242
|
+
|
|
243
|
+
:param job_id: the job_id of the job to be updated
|
|
244
|
+
:type job_id: unicode
|
|
245
|
+
|
|
246
|
+
:param data: the output data returned by the job
|
|
247
|
+
:type data: any JSON-serializable type (including None)
|
|
248
|
+
|
|
249
|
+
"""
|
|
250
|
+
update_dict = {
|
|
251
|
+
"status": "complete",
|
|
252
|
+
"data": json.dumps(data),
|
|
253
|
+
"finished_timestamp": datetime.datetime.utcnow(),
|
|
254
|
+
}
|
|
255
|
+
_update_job(job_id, update_dict)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def mark_job_as_missed(job_id):
|
|
259
|
+
"""Mark a job as missed because it was in the queue for too long.
|
|
260
|
+
|
|
261
|
+
:param job_id: the job_id of the job to be updated
|
|
262
|
+
:type job_id: unicode
|
|
263
|
+
|
|
264
|
+
"""
|
|
265
|
+
update_dict = {
|
|
266
|
+
"status": "error",
|
|
267
|
+
"error": "Job delayed too long, service full",
|
|
268
|
+
"finished_timestamp": datetime.datetime.utcnow(),
|
|
269
|
+
}
|
|
270
|
+
_update_job(job_id, update_dict)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def mark_job_as_errored(job_id, error_object):
|
|
274
|
+
"""Mark a job as failed with an error.
|
|
275
|
+
|
|
276
|
+
:param job_id: the job_id of the job to be updated
|
|
277
|
+
:type job_id: unicode
|
|
278
|
+
|
|
279
|
+
:param error_object: the error returned by the job
|
|
280
|
+
:type error_object: either a string or a dict with a "message" key whose
|
|
281
|
+
value is a string
|
|
282
|
+
|
|
283
|
+
"""
|
|
284
|
+
update_dict = {
|
|
285
|
+
"status": "error",
|
|
286
|
+
"error": error_object,
|
|
287
|
+
"finished_timestamp": datetime.datetime.utcnow(),
|
|
288
|
+
}
|
|
289
|
+
_update_job(job_id, update_dict)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def mark_job_as_failed_to_post_result(job_id):
|
|
293
|
+
"""Mark a job as 'failed to post result'.
|
|
294
|
+
|
|
295
|
+
This happens when a job completes (either successfully or with an error)
|
|
296
|
+
then trying to post the job result back to the job's callback URL fails.
|
|
297
|
+
|
|
298
|
+
FIXME: This overwrites any error from the job itself!
|
|
299
|
+
|
|
300
|
+
:param job_id: the job_id of the job to be updated
|
|
301
|
+
:type job_id: unicode
|
|
302
|
+
|
|
303
|
+
"""
|
|
304
|
+
update_dict = {
|
|
305
|
+
"error": "Process completed but unable to post to result_url",
|
|
306
|
+
}
|
|
307
|
+
_update_job(job_id, update_dict)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def _init_jobs_table():
|
|
311
|
+
"""Initialise the "jobs" table in the db."""
|
|
312
|
+
_jobs_table = sqlalchemy.Table(
|
|
313
|
+
"jobs",
|
|
314
|
+
_METADATA,
|
|
315
|
+
sqlalchemy.Column("job_id", sqlalchemy.UnicodeText, primary_key=True),
|
|
316
|
+
sqlalchemy.Column("job_type", sqlalchemy.UnicodeText),
|
|
317
|
+
sqlalchemy.Column("status", sqlalchemy.UnicodeText, index=True),
|
|
318
|
+
sqlalchemy.Column("data", sqlalchemy.UnicodeText),
|
|
319
|
+
sqlalchemy.Column("error", sqlalchemy.UnicodeText),
|
|
320
|
+
sqlalchemy.Column("requested_timestamp", sqlalchemy.DateTime),
|
|
321
|
+
sqlalchemy.Column("finished_timestamp", sqlalchemy.DateTime),
|
|
322
|
+
sqlalchemy.Column("sent_data", sqlalchemy.UnicodeText),
|
|
323
|
+
# Callback URL:
|
|
324
|
+
sqlalchemy.Column("result_url", sqlalchemy.UnicodeText),
|
|
325
|
+
)
|
|
326
|
+
return _jobs_table
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def _init_metadata_table():
|
|
330
|
+
"""Initialise the "metadata" table in the db."""
|
|
331
|
+
_metadata_table = sqlalchemy.Table(
|
|
332
|
+
"metadata",
|
|
333
|
+
_METADATA,
|
|
334
|
+
sqlalchemy.Column(
|
|
335
|
+
"job_id",
|
|
336
|
+
sqlalchemy.ForeignKey("jobs.job_id", ondelete="CASCADE"),
|
|
337
|
+
nullable=False,
|
|
338
|
+
primary_key=True,
|
|
339
|
+
),
|
|
340
|
+
sqlalchemy.Column("key", sqlalchemy.UnicodeText, primary_key=True),
|
|
341
|
+
sqlalchemy.Column("value", sqlalchemy.UnicodeText, index=True),
|
|
342
|
+
sqlalchemy.Column("type", sqlalchemy.UnicodeText),
|
|
343
|
+
)
|
|
344
|
+
return _metadata_table
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def _init_logs_table():
|
|
348
|
+
"""Initialise the "logs" table in the db."""
|
|
349
|
+
_logs_table = sqlalchemy.Table(
|
|
350
|
+
"logs",
|
|
351
|
+
_METADATA,
|
|
352
|
+
sqlalchemy.Column(
|
|
353
|
+
"job_id",
|
|
354
|
+
sqlalchemy.ForeignKey("jobs.job_id", ondelete="CASCADE"),
|
|
355
|
+
nullable=False,
|
|
356
|
+
),
|
|
357
|
+
sqlalchemy.Column("timestamp", sqlalchemy.DateTime),
|
|
358
|
+
sqlalchemy.Column("message", sqlalchemy.UnicodeText),
|
|
359
|
+
sqlalchemy.Column("level", sqlalchemy.UnicodeText),
|
|
360
|
+
sqlalchemy.Column("module", sqlalchemy.UnicodeText),
|
|
361
|
+
sqlalchemy.Column("funcName", sqlalchemy.UnicodeText),
|
|
362
|
+
sqlalchemy.Column("lineno", sqlalchemy.Integer),
|
|
363
|
+
)
|
|
364
|
+
return _logs_table
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def _get_metadata(job_id):
|
|
368
|
+
"""Return any metadata for the given job_id from the metadata table."""
|
|
369
|
+
job_id = six.text_type(job_id)
|
|
370
|
+
|
|
371
|
+
with ENGINE.connect() as conn:
|
|
372
|
+
results = conn.execute(
|
|
373
|
+
METADATA_TABLE.select().where(METADATA_TABLE.c.job_id == job_id)
|
|
374
|
+
).fetchall()
|
|
375
|
+
|
|
376
|
+
metadata = {
|
|
377
|
+
row["key"]: json.loads(row["value"]) if row["type"] == "json" else row["value"]
|
|
378
|
+
for row in results
|
|
379
|
+
}
|
|
380
|
+
return metadata
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def _get_logs(job_id):
|
|
384
|
+
"""Return any logs for the given job_id from the logs table."""
|
|
385
|
+
job_id = six.text_type(job_id)
|
|
386
|
+
|
|
387
|
+
with ENGINE.connect() as conn:
|
|
388
|
+
results = conn.execute(
|
|
389
|
+
LOGS_TABLE.select().where(LOGS_TABLE.c.job_id == job_id)
|
|
390
|
+
).fetchall()
|
|
391
|
+
|
|
392
|
+
results = [dict(result) for result in results]
|
|
393
|
+
|
|
394
|
+
for result in results:
|
|
395
|
+
result.pop("job_id")
|
|
396
|
+
|
|
397
|
+
return results
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import ckan.plugins.toolkit as toolkit
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
log = __import__("logging").getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def csvwmapandtransform__status_description(status: dict[str, Any]):
|
|
13
|
+
_ = toolkit._
|
|
14
|
+
|
|
15
|
+
if status.get("status"):
|
|
16
|
+
captions = {
|
|
17
|
+
"complete": _("Complete"),
|
|
18
|
+
"pending": _("Pending"),
|
|
19
|
+
"submitting": _("Submitting"),
|
|
20
|
+
"error": _("Error"),
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return captions.get(status["status"], status["status"].capitalize())
|
|
24
|
+
else:
|
|
25
|
+
return _("Not Uploaded Yet")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def common_member(a, b):
|
|
29
|
+
return any(i in b for i in a)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def csvwmapandtransform_show_tools(resource):
|
|
33
|
+
formats = toolkit.config.get("ckanext.csvwmapandtransform.formats")
|
|
34
|
+
|
|
35
|
+
format_parts = re.split("/|;", resource["format"].lower().replace(" ", ""))
|
|
36
|
+
if common_member(format_parts, formats):
|
|
37
|
+
return True
|
|
38
|
+
else:
|
|
39
|
+
False
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def csvwmapandtransform_service_available():
|
|
43
|
+
url = toolkit.config.get("ckanext.csvwmapandtransform.maptomethod_url")
|
|
44
|
+
ssl_verify = toolkit.config.get("ckanext.csvwmapandtransform.ssl_verify")
|
|
45
|
+
# log.debug(f"mapomethodurl: {url} {bool(url)}")
|
|
46
|
+
if not url:
|
|
47
|
+
return False # If EXTRACT_URL is not set, return False
|
|
48
|
+
try:
|
|
49
|
+
# Perform a HEAD request (lightweight check) to see if the service responds
|
|
50
|
+
response = requests.head(url, timeout=5, verify=ssl_verify)
|
|
51
|
+
# log.debug(f"reponse: {response}")
|
|
52
|
+
if (200 <= response.status_code < 400) or response.status_code == 405:
|
|
53
|
+
return True # URL is reachable and returns a valid status code
|
|
54
|
+
else:
|
|
55
|
+
return False # URL is reachable but response status is not valid
|
|
56
|
+
except requests.RequestException as e:
|
|
57
|
+
# If there's any issue (timeout, connection error, etc.)
|
|
58
|
+
# log.debug(e)
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_helpers():
|
|
63
|
+
return {
|
|
64
|
+
"csvwmapandtransform__status_description": csvwmapandtransform__status_description,
|
|
65
|
+
"csvwmapandtransform_show_tools": csvwmapandtransform_show_tools,
|
|
66
|
+
"csvwmapandtransform_service_available": csvwmapandtransform_service_available,
|
|
67
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Translations template for ckanext-csvwmapandtransform.
|
|
2
|
+
# Copyright (C) 2025 ORGANIZATION
|
|
3
|
+
# This file is distributed under the same license as the
|
|
4
|
+
# ckanext-csvwmapandtransform project.
|
|
5
|
+
# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.
|
|
6
|
+
#
|
|
7
|
+
#, fuzzy
|
|
8
|
+
msgid ""
|
|
9
|
+
msgstr ""
|
|
10
|
+
"Project-Id-Version: ckanext-csvwmapandtransform 0.0.0\n"
|
|
11
|
+
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
|
12
|
+
"POT-Creation-Date: 2025-05-14 07:19+0000\n"
|
|
13
|
+
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
14
|
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
15
|
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
16
|
+
"MIME-Version: 1.0\n"
|
|
17
|
+
"Content-Type: text/plain; charset=utf-8\n"
|
|
18
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
19
|
+
"Generated-By: Babel 2.15.0\n"
|
|
20
|
+
|
|
21
|
+
#: ckanext/csvwmapandtransform/helpers.py:17
|
|
22
|
+
msgid "Complete"
|
|
23
|
+
msgstr ""
|
|
24
|
+
|
|
25
|
+
#: ckanext/csvwmapandtransform/helpers.py:18
|
|
26
|
+
msgid "Pending"
|
|
27
|
+
msgstr ""
|
|
28
|
+
|
|
29
|
+
#: ckanext/csvwmapandtransform/helpers.py:19
|
|
30
|
+
msgid "Submitting"
|
|
31
|
+
msgstr ""
|
|
32
|
+
|
|
33
|
+
#: ckanext/csvwmapandtransform/helpers.py:20
|
|
34
|
+
msgid "Error"
|
|
35
|
+
msgstr ""
|
|
36
|
+
|
|
37
|
+
#: ckanext/csvwmapandtransform/helpers.py:25
|
|
38
|
+
msgid "Not Uploaded Yet"
|
|
39
|
+
msgstr ""
|
|
40
|
+
|
|
41
|
+
#: ckanext/csvwmapandtransform/views.py:29 ckanext/csvwmapandtransform/views.py:52
|
|
42
|
+
#: ckanext/csvwmapandtransform/views.py:89 ckanext/csvwmapandtransform/views.py:163
|
|
43
|
+
msgid "Not authorized to see this page"
|
|
44
|
+
msgstr ""
|
|
45
|
+
|
|
46
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/create_mapping.html:13
|
|
47
|
+
msgid "Map"
|
|
48
|
+
msgstr ""
|
|
49
|
+
|
|
50
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/create_mapping.html:19
|
|
51
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:24
|
|
52
|
+
msgid "View resource"
|
|
53
|
+
msgstr ""
|
|
54
|
+
|
|
55
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/create_mapping.html:28
|
|
56
|
+
msgid "Map resource"
|
|
57
|
+
msgstr ""
|
|
58
|
+
|
|
59
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:18
|
|
60
|
+
#: ckanext/csvwmapandtransform/templates/package/resource_read.html:6
|
|
61
|
+
#: ckanext/csvwmapandtransform/templates/package/snippets/resource_item.html:17
|
|
62
|
+
msgid "Transform"
|
|
63
|
+
msgstr ""
|
|
64
|
+
|
|
65
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:30
|
|
66
|
+
msgid "Edit resource"
|
|
67
|
+
msgstr ""
|
|
68
|
+
|
|
69
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:32
|
|
70
|
+
msgid "Views"
|
|
71
|
+
msgstr ""
|
|
72
|
+
|
|
73
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:36
|
|
74
|
+
msgid "Transform Status"
|
|
75
|
+
msgstr ""
|
|
76
|
+
|
|
77
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:45
|
|
78
|
+
msgid "Run Transformation"
|
|
79
|
+
msgstr ""
|
|
80
|
+
|
|
81
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:48
|
|
82
|
+
msgid "Delete"
|
|
83
|
+
msgstr ""
|
|
84
|
+
|
|
85
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:63
|
|
86
|
+
msgid "The status of the service (Green means available, Red means unavailable)"
|
|
87
|
+
msgstr ""
|
|
88
|
+
|
|
89
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:78
|
|
90
|
+
msgid "Status"
|
|
91
|
+
msgstr ""
|
|
92
|
+
|
|
93
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:82
|
|
94
|
+
msgid "Last updated"
|
|
95
|
+
msgstr ""
|
|
96
|
+
|
|
97
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:87
|
|
98
|
+
msgid "Never"
|
|
99
|
+
msgstr ""
|
|
100
|
+
|
|
101
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:92
|
|
102
|
+
msgid "Graph Update Log"
|
|
103
|
+
msgstr ""
|
|
104
|
+
|
|
105
|
+
#: ckanext/csvwmapandtransform/templates/package/snippets/resource_item.html:10
|
|
106
|
+
msgid "Create Mapping"
|
|
107
|
+
msgstr ""
|
|
108
|
+
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# German translations for ckanext-csvwmapandtransform.
|
|
2
|
+
# Copyright (C) 2025 ORGANIZATION
|
|
3
|
+
# This file is distributed under the same license as the
|
|
4
|
+
# ckanext-csvwmapandtransform project.
|
|
5
|
+
# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.
|
|
6
|
+
#
|
|
7
|
+
msgid ""
|
|
8
|
+
msgstr ""
|
|
9
|
+
"Project-Id-Version: ckanext-csvwmapandtransform 0.0.0\n"
|
|
10
|
+
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
|
11
|
+
"POT-Creation-Date: 2025-05-14 07:19+0000\n"
|
|
12
|
+
"PO-Revision-Date: 2025-05-14 07:20+0000\n"
|
|
13
|
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
14
|
+
"Language: de\n"
|
|
15
|
+
"Language-Team: de <LL@li.org>\n"
|
|
16
|
+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
17
|
+
"MIME-Version: 1.0\n"
|
|
18
|
+
"Content-Type: text/plain; charset=utf-8\n"
|
|
19
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
20
|
+
"Generated-By: Babel 2.15.0\n"
|
|
21
|
+
|
|
22
|
+
#: ckanext/csvwmapandtransform/helpers.py:17
|
|
23
|
+
msgid "Complete"
|
|
24
|
+
msgstr "Vollständig"
|
|
25
|
+
|
|
26
|
+
#: ckanext/csvwmapandtransform/helpers.py:18
|
|
27
|
+
msgid "Pending"
|
|
28
|
+
msgstr "Wartet"
|
|
29
|
+
|
|
30
|
+
#: ckanext/csvwmapandtransform/helpers.py:19
|
|
31
|
+
msgid "Submitting"
|
|
32
|
+
msgstr "Übersenden"
|
|
33
|
+
|
|
34
|
+
#: ckanext/csvwmapandtransform/helpers.py:20
|
|
35
|
+
msgid "Error"
|
|
36
|
+
msgstr "Fehler"
|
|
37
|
+
|
|
38
|
+
#: ckanext/csvwmapandtransform/helpers.py:25
|
|
39
|
+
msgid "Not Uploaded Yet"
|
|
40
|
+
msgstr "Noch nicht Hochgeladen"
|
|
41
|
+
|
|
42
|
+
#: ckanext/csvwmapandtransform/views.py:29
|
|
43
|
+
#: ckanext/csvwmapandtransform/views.py:52
|
|
44
|
+
#: ckanext/csvwmapandtransform/views.py:89
|
|
45
|
+
#: ckanext/csvwmapandtransform/views.py:163
|
|
46
|
+
msgid "Not authorized to see this page"
|
|
47
|
+
msgstr "Sie sind nicht berechtigt dies Seite aufzurufen"
|
|
48
|
+
|
|
49
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/create_mapping.html:13
|
|
50
|
+
msgid "Map"
|
|
51
|
+
msgstr "Map"
|
|
52
|
+
|
|
53
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/create_mapping.html:19
|
|
54
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:24
|
|
55
|
+
msgid "View resource"
|
|
56
|
+
msgstr "Ressource Anzeigen"
|
|
57
|
+
|
|
58
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/create_mapping.html:28
|
|
59
|
+
msgid "Map resource"
|
|
60
|
+
msgstr "Ressource mappen"
|
|
61
|
+
|
|
62
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:18
|
|
63
|
+
#: ckanext/csvwmapandtransform/templates/package/resource_read.html:6
|
|
64
|
+
#: ckanext/csvwmapandtransform/templates/package/snippets/resource_item.html:17
|
|
65
|
+
msgid "Transform"
|
|
66
|
+
msgstr "Transformieren"
|
|
67
|
+
|
|
68
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:30
|
|
69
|
+
msgid "Edit resource"
|
|
70
|
+
msgstr "Ressource bearbeiten"
|
|
71
|
+
|
|
72
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:32
|
|
73
|
+
msgid "Views"
|
|
74
|
+
msgstr "Ansichten"
|
|
75
|
+
|
|
76
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:36
|
|
77
|
+
msgid "Transform Status"
|
|
78
|
+
msgstr "Transformationsstatus"
|
|
79
|
+
|
|
80
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:45
|
|
81
|
+
msgid "Run Transformation"
|
|
82
|
+
msgstr "Transformation ausführen"
|
|
83
|
+
|
|
84
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:48
|
|
85
|
+
msgid "Delete"
|
|
86
|
+
msgstr "Löschen"
|
|
87
|
+
|
|
88
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:63
|
|
89
|
+
msgid "The status of the service (Green means available, Red means unavailable)"
|
|
90
|
+
msgstr "Status des Service (Grün heißt verfügbar, rot nicht verfügbar)"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:78
|
|
94
|
+
msgid "Status"
|
|
95
|
+
msgstr "Status"
|
|
96
|
+
|
|
97
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:82
|
|
98
|
+
msgid "Last updated"
|
|
99
|
+
msgstr "Letztes Update"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:87
|
|
103
|
+
msgid "Never"
|
|
104
|
+
msgstr "Niemals"
|
|
105
|
+
|
|
106
|
+
#: ckanext/csvwmapandtransform/templates/csvwmapandtransform/transform.html:92
|
|
107
|
+
msgid "Graph Update Log"
|
|
108
|
+
msgstr "Graphbearbeitungsbericht"
|
|
109
|
+
|
|
110
|
+
#: ckanext/csvwmapandtransform/templates/package/snippets/resource_item.html:10
|
|
111
|
+
msgid "Create Mapping"
|
|
112
|
+
msgstr "Mapping erzeugen"
|
|
113
|
+
|