diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 5bad28e77..f3645959d 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -10,6 +10,16 @@ and this project adheres to `Semantic Versioning `_
***********
Unreleased_
***********
+Changed
+-------
+
+- Add a new list item "Deleted and purge source" in templates/source/new_source_form.html that can purge the harvest source
+
+
+Fixed
+-----
+
+- remove confirm action in list item "Deleted and clear source" because confirm action will make cause the delete view can not pass the "clear = true"
***********
1.4.1_ - 2022-09-20
diff --git a/ckanext/harvest/controllers/view.py b/ckanext/harvest/controllers/view.py
index 8d2842dc2..f7e1c087f 100644
--- a/ckanext/harvest/controllers/view.py
+++ b/ckanext/harvest/controllers/view.py
@@ -22,6 +22,9 @@ def refresh(self, id):
def clear(self, id):
return utils.clear_view(id)
+ def purge(id):
+ return utils.purge_view(id)
+
def show_object(self, id, ref_type='object'):
_, content = utils.object_show_view(id, ref_type, response)
return content
diff --git a/ckanext/harvest/logic/action/delete.py b/ckanext/harvest/logic/action/delete.py
index 70e8c0aee..89a245641 100644
--- a/ckanext/harvest/logic/action/delete.py
+++ b/ckanext/harvest/logic/action/delete.py
@@ -21,7 +21,13 @@ def harvest_source_delete(context, data_dict):
p.toolkit.get_action('package_delete')(context, data_dict)
- if context.get('clear_source', False):
+ if context.get('purge_resource', False):
+
+ # We need the id. The name won't work.
+ package_dict = p.toolkit.get_action('package_show')(context, data_dict)
+ p.toolkit.get_action('purge_harvest_source')(
+ context, {'id': package_dict['id']})
+ elif context.get('clear_source', False):
# We need the id. The name won't work.
package_dict = p.toolkit.get_action('package_show')(context, data_dict)
diff --git a/ckanext/harvest/logic/action/update.py b/ckanext/harvest/logic/action/update.py
index 090e6e155..bf8a98106 100644
--- a/ckanext/harvest/logic/action/update.py
+++ b/ckanext/harvest/logic/action/update.py
@@ -237,6 +237,39 @@ def harvest_source_clear(context, data_dict):
return {'id': harvest_source_id}
+def purge_harvest_source(context, data_dict):
+ '''
+ Clears all datasets, jobs and objects related to a harvest source, includes
+ the source itself. This is useful to clean history of long running
+ harvest sources to start again fresh.
+ :param id: the id of the harvest source to clear
+ :type id: string
+ '''
+
+ check_access('purge_harvest_source', context, data_dict)
+
+ harvest_source_id = data_dict.get('id')
+
+ source = HarvestSource.get(harvest_source_id)
+ if not source:
+ log.error('Harvest source %s does not exist', harvest_source_id)
+ raise NotFound('Harvest source %s does not exist' % harvest_source_id)
+
+ # Clears all datasets, jobs and objects related to a harvest source
+ get_action('harvest_source_clear')(context, data_dict)
+
+ harvest_source_id = source.id
+
+ # Delete harvest source itself
+ source.delete()
+ # Refresh the index for this source to update the status object
+ get_action('harvest_source_reindex')(context, {'id': harvest_source_id})
+ # Purge the dataset itself
+ get_action("dataset_purge")(context, {'id': harvest_source_id})
+
+ return {'id': harvest_source_id}
+
+
def harvest_abort_failed_jobs(context, data_dict):
session = context['session']
diff --git a/ckanext/harvest/logic/auth/update.py b/ckanext/harvest/logic/auth/update.py
index 419a1620a..dcdf79f55 100644
--- a/ckanext/harvest/logic/auth/update.py
+++ b/ckanext/harvest/logic/auth/update.py
@@ -49,6 +49,25 @@ def harvest_source_clear(context, data_dict):
return harvest_source_update(context, data_dict)
+def purge_harvest_sources(context, data_dict):
+ '''
+ Authorization check for purging for all harvest sources
+ Only sysadmins can do it
+ '''
+ if not user_is_sysadmin(context):
+ return {'success': False, 'msg': pt._('Only sysadmins can purge for all harvest source')}
+ else:
+ return {'success': True}
+
+
+def purge_harvest_source(context, data_dict):
+ '''
+ Authorization check for purging a harvest source
+ It forwards to harvest_source_update
+ '''
+ return harvest_source_update(context, data_dict)
+
+
def harvest_objects_import(context, data_dict):
'''
Authorization check reimporting all harvest objects
diff --git a/ckanext/harvest/plugin/__init__.py b/ckanext/harvest/plugin/__init__.py
index 3c22c6a83..06afe12c0 100644
--- a/ckanext/harvest/plugin/__init__.py
+++ b/ckanext/harvest/plugin/__init__.py
@@ -294,7 +294,7 @@ def update_config(self, config):
})
bp_routes = [
"delete", "refresh", "admin", "about",
- "clear", "job_list", "job_show_last", "job_show",
+ "clear", "purge", "job_list", "job_show_last", "job_show",
"job_abort", "object_show"
]
mappings.update({
diff --git a/ckanext/harvest/templates/source/new_source_form.html b/ckanext/harvest/templates/source/new_source_form.html
index 8a9df5169..ec3fb25a1 100644
--- a/ckanext/harvest/templates/source/new_source_form.html
+++ b/ckanext/harvest/templates/source/new_source_form.html
@@ -106,10 +106,15 @@
-
+
{{ _('Delete and clear source') }}
+
+
+ {{ _('Delete and purge source') }}
+
+
{% endif %}
diff --git a/ckanext/harvest/utils.py b/ckanext/harvest/utils.py
index 7acaaea59..1ccca0bee 100644
--- a/ckanext/harvest/utils.py
+++ b/ckanext/harvest/utils.py
@@ -232,6 +232,18 @@ def clear_harvest_source_history(source_id, keep_current):
len(cleared_sources_dicts))
+def purge_harvest_source(source_id_or_name):
+ context = {
+ "model": model,
+ "session": model.Session,
+ "user": _admin_user()["name"],
+ }
+ source = tk.get_action("harvest_source_show")(context, {
+ "id": source_id_or_name
+ })
+ tk.get_action("purge_harvest_source")(context, {"id": source["id"]})
+
+
def abort_failed_jobs(job_life_span, include, exclude):
context = {
"model": model,
@@ -694,6 +706,22 @@ def clear_view(id):
h.url_for('{0}_admin'.format(DATASET_TYPE_NAME), id=id))
+def purge_view(id):
+ try:
+ context = {'model': model, 'user': tk.c.user, 'session': model.Session}
+ tk.get_action('purge_harvest_source')(context, {'id': id})
+ h.flash_success(_('Harvest source purged'))
+ except tk.ObjectNotFound:
+ return tk.abort(404, _('Harvest source not found'))
+ except tk.NotAuthorized:
+ return tk.abort(401, _not_auth_message())
+ except Exception as e:
+ msg = 'An error occurred: [%s]' % str(e)
+ h.flash_error(msg)
+
+ return h.redirect_to('/harvest')
+
+
def delete_view(id):
try:
context = {'model': model, 'user': tk.c.user}
@@ -703,9 +731,18 @@ def delete_view(id):
u'true',
u'1',
)
+ context['purge_resource'] = tk.request.params.get('purge',
+ '').lower() in (
+ u'true',
+ u'1',
+ )
tk.get_action('harvest_source_delete')(context, {'id': id})
+ if context['purge_resource']:
+ h.flash_success(_('Harvesting source successfully purged'))
+ return h.redirect_to('/harvest')
+
if context['clear_source']:
h.flash_success(_('Harvesting source successfully cleared'))
else:
diff --git a/ckanext/harvest/views.py b/ckanext/harvest/views.py
index 6ac8eec5a..e016aa1ba 100644
--- a/ckanext/harvest/views.py
+++ b/ckanext/harvest/views.py
@@ -33,6 +33,10 @@ def clear(id):
return utils.clear_view(id)
+def purge(id):
+ return utils.purge_view(id)
+
+
def job_list(source):
return utils.job_list_view(source)
@@ -73,6 +77,9 @@ def object_show(id, ref_type):
harvester.add_url_rule("/" + utils.DATASET_TYPE_NAME + "/clear/",
view_func=clear,
methods=(u'POST', u'GET'))
+harvester.add_url_rule("/" + utils.DATASET_TYPE_NAME + "/purge/",
+ view_func=purge,
+ methods=(u'POST', u'GET'))
harvester.add_url_rule(
"/" + utils.DATASET_TYPE_NAME + "/