Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean Datastore Tables Job #67

Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions ckanext/xloader/config_declaration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,13 @@ groups:
to True.
type: bool
required: false
- key: ckanext.xloader.clean_datastore_tables
default: False
example: True
description: |
Enqueue jobs to remove Datastore tables from Resources that have a format
that is not in ckanext.xloader.formats after a Resource is updated.
type: bool
required: false


60 changes: 56 additions & 4 deletions ckanext/xloader/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from ckan import plugins
from ckan.plugins import toolkit
from ckan.model.domain_object import DomainObjectOperation
from ckan.model.resource import Resource

from . import action, auth, helpers as xloader_helpers, utils
from ckanext.xloader.utils import XLoaderFormats
Expand All @@ -23,7 +25,7 @@ def config_declarations(cls):
class xloaderPlugin(plugins.SingletonPlugin):
plugins.implements(plugins.IConfigurer)
plugins.implements(plugins.IConfigurable)
plugins.implements(plugins.IResourceUrlChange)
plugins.implements(plugins.IDomainObjectModification)
JVickery-TBS marked this conversation as resolved.
Show resolved Hide resolved
plugins.implements(plugins.IActions)
plugins.implements(plugins.IAuthFunctions)
plugins.implements(plugins.ITemplateHelpers)
Expand Down Expand Up @@ -64,18 +66,32 @@ def configure(self, config_):
)
)

# IResourceUrlChange
# IDomainObjectModification

def notify(self, entity, operation):
# type: (ckan.model.Package|ckan.model.Resource, DomainObjectOperation) -> None
"""
Runs before_commit to database for Packages and Resources.
We only want to check for changed Resources for this.
We want to check if values have changed, namely the url and the format.
See: ckan/model/modification.py.DomainObjectModificationExtension
"""
if operation != DomainObjectOperation.changed or not isinstance(entity, Resource):
return

def notify(self, resource):
context = {
"ignore_auth": True,
}
resource_dict = toolkit.get_action("resource_show")(
context,
{
"id": resource.id,
"id": entity.id,
},
)

if _should_remove_unsupported_resource_from_datastore(resource_dict):
toolkit.enqueue_job(fn=_remove_unsupported_resource_from_datastore, args=[entity.id])

self._submit_to_xloader(resource_dict)

# IResourceController
Expand Down Expand Up @@ -183,3 +199,39 @@ def get_helpers(self):
"xloader_status_description": xloader_helpers.xloader_status_description,
"is_resource_supported_by_xloader": xloader_helpers.is_resource_supported_by_xloader,
}


def _should_remove_unsupported_resource_from_datastore(res_dict):
JVickery-TBS marked this conversation as resolved.
Show resolved Hide resolved
if not toolkit.asbool(toolkit.config.get('ckanext.xloader.clean_datastore_tables', False)):
return False
return (not XLoaderFormats.is_it_an_xloader_format(res_dict.get('format', u''))
and (res_dict.get('url_type') == 'upload'
or res_dict.get('url_type') == '')
JVickery-TBS marked this conversation as resolved.
Show resolved Hide resolved
and (toolkit.asbool(res_dict.get('datastore_active', False))
or toolkit.asbool(res_dict.get('extras', {}).get('datastore_active', False))))


def _remove_unsupported_resource_from_datastore(resource_id):
"""
Callback to remove unsupported datastore tables.
Controlled by config value: ckanext.xloader.clean_datastore_tables.
Double check the resource format. Only supported Xloader formats should have datastore tables.
If the resource format is not supported, we should delete the datastore tables.
"""
context = {"ignore_auth": True}
try:
res = toolkit.get_action('resource_show')(context, {"id": resource_id})
except toolkit.ObjectNotFound:
log.error('Resource %s does not exist.', res['id'])
JVickery-TBS marked this conversation as resolved.
Show resolved Hide resolved
return

if _should_remove_unsupported_resource_from_datastore(res):
log.info('Unsupported resource format "%s". Deleting datastore tables for resource %s',
res.get(u'format', u'').lower(), res['id'])
try:
toolkit.get_action('datastore_delete')(context, {
"resource_id": res['id'],
"force": True})
log.info('Datastore table dropped for resource %s', res['id'])
except toolkit.ObjectNotFound:
log.error('Datastore table for resource %s does not exist', res['id'])
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ six>=1.12.0
tabulator==1.53.5
Unidecode==1.0.22
python-dateutil>=2.8.2
chardet==5.2.0
chardet==5.2.0