Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into pytest
Browse files Browse the repository at this point in the history
  • Loading branch information
smotornyuk committed Oct 8, 2019
2 parents 06d0a3f + 42596a0 commit b33a29d
Show file tree
Hide file tree
Showing 11 changed files with 163 additions and 112 deletions.
8 changes: 6 additions & 2 deletions ckan/lib/cli.py
Expand Up @@ -689,8 +689,10 @@ class Sysadmin(CkanCommand):
(prompts for password and email if not
supplied).
Field can be: apikey
password
email
fullname
name (this will be the username)
password
sysadmin remove USERNAME - removes user from sysadmins
'''

Expand Down Expand Up @@ -776,8 +778,10 @@ class UserCmd(CkanCommand):
- add a user (prompts for email and
password if not supplied).
Field can be: apikey
password
email
fullname
name (this will be the username)
password
user setpass USERNAME - set user password (prompts)
user remove USERNAME - removes user from users
user search QUERY - searches for a user name
Expand Down
71 changes: 71 additions & 0 deletions ckanext/datapusher/blueprint.py
@@ -0,0 +1,71 @@
# encoding: utf-8

from flask import Blueprint
from flask.views import MethodView

import ckan.plugins.toolkit as toolkit
import ckan.logic as logic
import ckan.lib.helpers as core_helpers
import ckan.lib.base as base

from ckan.common import _

datapusher = Blueprint(u'datapusher', __name__)


class ResourceDataView(MethodView):

def post(self, id, resource_id):
try:
toolkit.get_action(u'datapusher_submit')(
None, {
u'resource_id': resource_id
}
)
except logic.ValidationError:
pass

return core_helpers.redirect_to(
u'datapusher.resource_data', id=id, resource_id=resource_id
)

def get(self, id, resource_id):
try:
pkg_dict = toolkit.get_action(u'package_show')(None, {u'id': id})
resource = toolkit.get_action(u'resource_show'
)(None, {
u'id': resource_id
})

# backward compatibility with old templates
toolkit.c.pkg_dict = pkg_dict
toolkit.c.resource = resource

except (logic.NotFound, logic.NotAuthorized):
base.abort(404, _(u'Resource not found'))

try:
datapusher_status = toolkit.get_action(u'datapusher_status')(
None, {
u'resource_id': resource_id
}
)
except logic.NotFound:
datapusher_status = {}
except logic.NotAuthorized:
base.abort(403, _(u'Not authorized to see this page'))

return base.render(
u'datapusher/resource_data.html',
extra_vars={
u'status': datapusher_status,
u'pkg_dict': pkg_dict,
u'resource': resource,
}
)


datapusher.add_url_rule(
u'/dataset/<id>/resource_data/<resource_id>',
view_func=ResourceDataView.as_view(str(u'resource_data'))
)
178 changes: 77 additions & 101 deletions ckanext/datapusher/plugin.py
Expand Up @@ -2,79 +2,35 @@

import logging

import ckan.plugins as p
import ckan.lib.base as base
import ckan.lib.helpers as core_helpers
import ckanext.datapusher.logic.action as action
import ckanext.datapusher.logic.auth as auth
import ckanext.datapusher.helpers as helpers
import ckan.logic as logic
import ckan.model as model
import ckan.plugins as p
import ckan.plugins.toolkit as toolkit

from ckan.common import _
import ckanext.datapusher.blueprint as blueprint
import ckanext.datapusher.helpers as helpers
import ckanext.datapusher.logic.action as action
import ckanext.datapusher.logic.auth as auth

log = logging.getLogger(__name__)
_get_or_bust = logic.get_or_bust

DEFAULT_FORMATS = [
'csv', 'xls', 'xlsx', 'tsv', 'application/csv',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'ods', 'application/vnd.oasis.opendocument.spreadsheet',
u'csv',
u'xls',
u'xlsx',
u'tsv',
u'application/csv',
u'application/vnd.ms-excel',
u'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
u'ods',
u'application/vnd.oasis.opendocument.spreadsheet',
]


class DatastoreException(Exception):
pass


class ResourceDataController(base.BaseController):

def resource_data(self, id, resource_id):

if toolkit.request.method == 'POST':
try:
toolkit.c.pkg_dict = p.toolkit.get_action('datapusher_submit')(
None, {'resource_id': resource_id}
)
except logic.ValidationError:
pass

core_helpers.redirect_to(
controller='ckanext.datapusher.plugin:ResourceDataController',
action='resource_data',
id=id,
resource_id=resource_id
)

try:
toolkit.c.pkg_dict = p.toolkit.get_action('package_show')(
None, {'id': id}
)
toolkit.c.resource = p.toolkit.get_action('resource_show')(
None, {'id': resource_id}
)
except (logic.NotFound, logic.NotAuthorized):
base.abort(404, _('Resource not found'))

try:
datapusher_status = p.toolkit.get_action('datapusher_status')(
None, {'resource_id': resource_id}
)
except logic.NotFound:
datapusher_status = {}
except logic.NotAuthorized:
base.abort(403, _('Not authorized to see this page'))

return base.render('datapusher/resource_data.html',
extra_vars={
'status': datapusher_status,
'pkg_dict': toolkit.c.pkg_dict,
'resource': toolkit.c.resource,
})


class DatapusherPlugin(p.SingletonPlugin):
p.implements(p.IConfigurer, inherit=True)
p.implements(p.IConfigurable, inherit=True)
Expand All @@ -83,88 +39,108 @@ class DatapusherPlugin(p.SingletonPlugin):
p.implements(p.IResourceUrlChange)
p.implements(p.IDomainObjectModification, inherit=True)
p.implements(p.ITemplateHelpers)
p.implements(p.IRoutes, inherit=True)
p.implements(p.IBlueprint)

legacy_mode = False
resource_show_action = None

def update_config(self, config):
templates_base = config.get('ckan.base_templates_folder')
p.toolkit.add_template_directory(config, templates_base)
templates_base = config.get(u'ckan.base_templates_folder')
toolkit.add_template_directory(config, templates_base)

def configure(self, config):
self.config = config

datapusher_formats = config.get('ckan.datapusher.formats', '').lower()
datapusher_formats = config.get(u'ckan.datapusher.formats',
u'').lower()
self.datapusher_formats = datapusher_formats.split() or DEFAULT_FORMATS

for config_option in ('ckan.site_url', 'ckan.datapusher.url',):
for config_option in (
u'ckan.site_url',
u'ckan.datapusher.url',
):
if not config.get(config_option):
raise Exception(
'Config option `{0}` must be set to use the DataPusher.'
.format(config_option))
u'Config option `{0}` must be set to use the DataPusher.'.
format(config_option)
)

def notify(self, entity, operation=None):
if isinstance(entity, model.Resource):
if (operation == model.domain_object.DomainObjectOperation.new or
not operation):
if (
operation == model.domain_object.DomainObjectOperation.new
or not operation
):
# if operation is None, resource URL has been changed, as
# the notify function in IResourceUrlChange only takes
# 1 parameter
context = {'model': model, 'ignore_auth': True,
'defer_commit': True}
if (entity.format and
entity.format.lower() in self.datapusher_formats and
entity.url_type != 'datapusher'):
context = {
u'model': model,
u'ignore_auth': True,
u'defer_commit': True
}
if (
entity.format
and entity.format.lower() in self.datapusher_formats
and entity.url_type != u'datapusher'
):

try:
task = p.toolkit.get_action('task_status_show')(
task = toolkit.get_action(u'task_status_show')(
context, {
'entity_id': entity.id,
'task_type': 'datapusher',
'key': 'datapusher'}
u'entity_id': entity.id,
u'task_type': u'datapusher',
u'key': u'datapusher'
}
)
if task.get('state') == 'pending':
if task.get(u'state') == u'pending':
# There already is a pending DataPusher submission,
# skip this one ...
log.debug(
'Skipping DataPusher submission for '
'resource {0}'.format(entity.id))
u'Skipping DataPusher submission for '
u'resource {0}'.format(entity.id)
)
return
except p.toolkit.ObjectNotFound:
except toolkit.ObjectNotFound:
pass

try:
log.debug('Submitting resource {0}'.format(entity.id) +
' to DataPusher')
p.toolkit.get_action('datapusher_submit')(context, {
'resource_id': entity.id
})
except p.toolkit.ValidationError as e:
log.debug(
u'Submitting resource {0}'.format(entity.id) +
u' to DataPusher'
)
toolkit.get_action(u'datapusher_submit')(
context, {
u'resource_id': entity.id
}
)
except toolkit.ValidationError as e:
# If datapusher is offline want to catch error instead
# of raising otherwise resource save will fail with 500
log.critical(e)
pass

def before_map(self, m):
m.connect(
'resource_data', '/dataset/{id}/resource_data/{resource_id}',
controller='ckanext.datapusher.plugin:ResourceDataController',
action='resource_data', ckan_icon='cloud-upload')
return m

def get_actions(self):
return {'datapusher_submit': action.datapusher_submit,
'datapusher_hook': action.datapusher_hook,
'datapusher_status': action.datapusher_status}
return {
u'datapusher_submit': action.datapusher_submit,
u'datapusher_hook': action.datapusher_hook,
u'datapusher_status': action.datapusher_status
}

def get_auth_functions(self):
return {'datapusher_submit': auth.datapusher_submit,
'datapusher_status': auth.datapusher_status}
return {
u'datapusher_submit': auth.datapusher_submit,
u'datapusher_status': auth.datapusher_status
}

def get_helpers(self):
return {
'datapusher_status': helpers.datapusher_status,
'datapusher_status_description':
helpers.datapusher_status_description,
u'datapusher_status': helpers.datapusher_status,
u'datapusher_status_description': helpers.
datapusher_status_description,
}

# IBlueprint

def get_blueprint(self):
return blueprint.datapusher
Expand Up @@ -4,7 +4,7 @@

{% block primary_content_inner %}

{% set action = h.url_for(controller='ckanext.datapusher.plugin:ResourceDataController', action='resource_data', id=pkg.name, resource_id=res.id) %}
{% set action = h.url_for('datapusher.resource_data', id=pkg.name, resource_id=res.id) %}
{% set show_table = true %}

<form method="post" action="{{ action }}">
Expand Down
Expand Up @@ -2,5 +2,5 @@

{% block inner_primary_nav %}
{{ super() }}
{{ h.build_nav_icon('resource_data', _('DataStore'), id=pkg.name, resource_id=res.id) }}
{{ h.build_nav_icon('datapusher.resource_data', _('DataStore'), id=pkg.name, resource_id=res.id) }}
{% endblock %}
2 changes: 1 addition & 1 deletion ckanext/datapusher/templates/datapusher/resource_data.html
Expand Up @@ -4,7 +4,7 @@

{% block primary_content_inner %}

{% set action = h.url_for(controller='ckanext.datapusher.plugin:ResourceDataController', action='resource_data', id=pkg.name, resource_id=res.id) %}
{% set action = h.url_for('datapusher.resource_data', id=pkg.name, resource_id=res.id) %}
{% set show_table = true %}

<form method="post" action="{{ action }}" class="datapusher-form">
Expand Down
Expand Up @@ -2,5 +2,5 @@

{% block inner_primary_nav %}
{{ super() }}
{{ h.build_nav_icon('resource_data', _('DataStore'), id=pkg.name, resource_id=res.id) }}
{{ h.build_nav_icon('datapusher.resource_data', _('DataStore'), id=pkg.name, resource_id=res.id) }}
{% endblock %}
6 changes: 3 additions & 3 deletions ckanext/datapusher/tests/test_controller.py
Expand Up @@ -3,22 +3,22 @@
import nose

import ckan.tests.legacy as tests
from ckan.tests.helpers import FunctionalTestBase
from ckanext.datastore.tests.helpers import DatastoreFunctionalTestBase
import ckan.tests.factories as factories


class TestController(FunctionalTestBase):
class TestController(DatastoreFunctionalTestBase):
sysadmin_user = None
normal_user = None

_load_plugins = [u'datastore', u'datapusher']

@classmethod
def setup_class(cls):
cls.app = cls._get_test_app()
if not tests.is_datastore_supported():
raise nose.SkipTest(u'Datastore not supported')
super(TestController, cls).setup_class()
cls.app = cls._get_test_app()

def test_resource_data(self):
user = factories.User()
Expand Down

0 comments on commit b33a29d

Please sign in to comment.