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

Feature/package approve #3

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
27 changes: 22 additions & 5 deletions ckanext/ed/actions.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from ckan.plugins import toolkit
from logging import getLogger
import os
import requests
import uuid
from ckanext.ed import helpers
import zipfile
import os

from ckan.controllers.admin import get_sysadmins
import requests
from logging import getLogger
from ckan.logic.action.get import package_show as core_package_show
from ckan.plugins import toolkit

from ckanext.ed import helpers

SUPPORTED_RESOURCE_MIMETYPES = [
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
Expand Down Expand Up @@ -136,3 +138,18 @@ def prepare_zip_resources(context, data_dict):
os.remove(file_path)

return {'zip_id': None}


@toolkit.side_effect_free
def package_show(context, data_dict):
package = core_package_show(context, data_dict)
# User with less perms then creator should not be able to access pending dataset
approval_pending = package.get('approval_state') == 'approval_pending'
try:
toolkit.check_access('package_update', context, data_dict)
can_edit = True
except toolkit.NotAuthorized:
can_edit = False
if not can_edit and approval_pending:
raise toolkit.ObjectNotFound
return package
45 changes: 30 additions & 15 deletions ckanext/ed/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,38 +29,39 @@ def get_recently_updated_datasets(limit=5):
Returns recent created or updated datasets.
:param limit: Limit of the datasets to be returned. Default is 5.
:type limit: integer
:param user: user name
:type user: string

:returns: a list of recently created or updated datasets
:rtype: list
'''
try:
pkg_search_results = toolkit.get_action('package_search')(data_dict={
'sort': 'metadata_modified desc',
'rows': limit,
})['results']
pkg_search_results = toolkit.get_action('package_search')(
data_dict={
'sort': 'metadata_modified desc',
'rows': limit
})['results']
return pkg_search_results

except toolkit.ValidationError, search.SearchError:
return []
else:
pkgs = []
for pkg in pkg_search_results:
package = toolkit.get_action('package_show')(
data_dict={'id': pkg['id']})
modified = datetime.strptime(
package['metadata_modified'].split('T')[0], '%Y-%m-%d')
package['days_ago_modified'] = ((datetime.now() - modified).days)
pkgs.append(package)
return pkgs

log.warning('Unexpected Error occured while searching')
return []

def get_most_popular_datasets(limit=5):
'''
Returns most popular datasets based on total views.
:param limit: Limit of the datasets to be returned. Default is 5.
:type limit: integer
:param user: user name
:type user: string

:returns: a list of most popular datasets
:rtype: list
'''
data = pkg_search_results = toolkit.get_action('package_search')(data_dict={
data = pkg_search_results = toolkit.get_action('package_search')(
data_dict={
'sort': 'views_total desc',
'rows': limit,
})['results']
Expand Down Expand Up @@ -105,3 +106,17 @@ def get_total_views_for_dataset(id):
return dataset.get('tracking_summary').get('total')
except Exception:
return 0


def is_admin(user):
"""
Returns True if user is admin of any organisation

:param user: user name
:type user: string

:returns: True/False
:rtype: boolean
"""
user_orgs = _get_action('organization_list_for_user', {'user': user}, {'user': user})
return any([i.get('capacity') == 'admin' for i in user_orgs])
27 changes: 20 additions & 7 deletions ckanext/ed/plugin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from ckan.lib.plugins import DefaultTranslation
import ckan.plugins as plugins
import ckan.plugins.toolkit as toolkit
from ckanext.ed import helpers
from ckanext.ed import actions
from ckan.lib.plugins import DefaultTranslation

from ckanext.ed import actions, helpers, validators


class EDPlugin(plugins.SingletonPlugin, DefaultTranslation):
Expand All @@ -11,33 +11,40 @@ class EDPlugin(plugins.SingletonPlugin, DefaultTranslation):
plugins.implements(plugins.ITranslation)
plugins.implements(plugins.IActions)
plugins.implements(plugins.IRoutes, inherit=True)
plugins.implements(plugins.IValidators)
plugins.implements(plugins.IPackageController, inherit=True)

# ITemplateHelpers

def get_helpers(self):
return {
'ed_get_groups': helpers.get_groups,
'ed_is_admin': helpers.is_admin,
'ed_get_recently_updated_datasets': helpers.get_recently_updated_datasets,
'ed_get_most_popular_datasets': helpers.get_most_popular_datasets,
'ed_get_total_views_for_dataset': helpers.get_total_views_for_dataset,
}

# IActions

def get_actions(self):
return {
'ed_prepare_zip_resources': actions.prepare_zip_resources,
'package_show': actions.package_show
}

# IConfigurer
# IPackageController
def before_search(self, search_params):
search_params.update({
'fq': '!(approval_state:approval_pending) ' + search_params.get('fq', '')
})
return search_params

# IConfigurer
def update_config(self, config_):
toolkit.add_template_directory(config_, 'templates')
toolkit.add_public_directory(config_, 'public')
toolkit.add_resource('fanstatic', 'ed')

# IRoutes

def before_map(self, map):
map.connect(
'download_zip',
Expand All @@ -47,3 +54,9 @@ def before_map(self, map):
)

return map

# IValidators
def get_validators(self):
return {
'state_validator': validators.state_validator
}
5 changes: 5 additions & 0 deletions ckanext/ed/schemas/dataset.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@
"label": "Temporal",
"form_placeholder": "eg. 2000-01-15T00:45:00Z/2010-01-15T00:06:00Z",
"help_text": "The range of temporal applicability of a dataset (i.e., a start and end date of applicability for the data)."
},
{
"field_name": "approval_state",
"form_snippet": null,
"validators": "state_validator"
}
],
"resource_fields": [
Expand Down
34 changes: 34 additions & 0 deletions ckanext/ed/templates/package/new_package_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{% extends 'package/snippets/package_form.html' %}

{% block stages %}
{% if form_style != 'edit' %}
{% if not h.ed_is_admin(c.user) %}
<div class="alert alert-warning" role="alert">
<p>
{% trans %}<strong>Note:</strong> This dataset will be submited for an administrator approval!{% endtrans %}
</p>
</div>
{% endif %}
{{ super() }}
{% endif %}
{% endblock %}

{% block save_button_text %}
{% if form_style != 'edit' %}
{{ super() }}
{% else %}
{{ _('Update Dataset') }}
{% endif %}
{% endblock %}

{% block cancel_button %}
{% if form_style != 'edit' %}
{{ super() }}
{% endif %}
{% endblock %}

{% block delete_button %}
{% if form_style == 'edit' and h.check_access('package_delete', {'id': pkg_dict.id}) %}
{{ super() }}
{% endif %}
{% endblock %}
48 changes: 48 additions & 0 deletions ckanext/ed/templates/package/snippets/stages.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{#
Inserts a stepped progress indicator for the new package form. Each stage can
have one of three states, "uncomplete", "complete" and "active".

stages - A list of states for each of the three stages. Missing stages default
to "uncomplete".

Example:

{% snippet 'package/snippets/stages.html', stages=['active'] %}
{% snippet 'package/snippets/stages.html', stages=['complete', 'active'] %}
{% snippet 'package/snippets/stages.html', stages=['active', 'complete'] %}

#}
{% set s1 = stages[0] or 'active' %}
{% set s2 = stages[1] or 'uncomplete' %}
{% if s1 != 'uncomplete' %}{% set class = 'stage-1' %}{% endif %}
{% if s2 != 'uncomplete' %}{% set class = 'stage-2' %}{% endif %}

<ol class="stages {{ class }}">
<li class="first {{ s1 }}">
{% if s1 != 'complete' %}
{% if h.ed_is_admin(c.user) %}
<span class="highlight">{{ _('Create dataset') }}</span>
{% else %}
<span class="highlight">{{ _('Request dataset') }}</span>
{% endif %}
{% else %}
{% if h.ed_is_admin(c.user) %}
<button class="highlight" name="save" value="go-dataset" type="submit">{{ _('Create dataset') }}</button>
{% else %}
<button class="highlight" name="save" value="go-dataset" type="submit">{{ _('Request dataset') }}</button>
{% endif %}
{% endif %}
</li>
<li class="last {{ s2 }}">
{% if s2 != 'complete' %}
<span class="highlight">{{ _('Add data') }}</span>
{% else %}
{% if s1 == 'active' %}
{# stage 1 #}
<button class="highlight" name="save" value="go-resources" type="submit">{{ _('Add data') }}</button>
{% else %}
{% link_for _('Add data'), named_route='dataset.new', class_="highlight" %}
{% endif %}
{% endif %}
</li>
</ol>
49 changes: 44 additions & 5 deletions ckanext/ed/tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,37 @@

class TestHelpers(test_helpers.FunctionalTestBase):
def test_get_recently_updated_datasets(self):
factories.Dataset()
factories.Dataset()
factories.Dataset()
dataset = factories.Dataset()
user = core_factories.User()
org = core_factories.Organization(
users=[{'name': user['name'], 'capacity': 'admin'}]
)
factories.Dataset(owner_org=org['id'])
factories.Dataset(owner_org=org['id'])
factories.Dataset(owner_org=org['id'])
dataset = factories.Dataset(owner_org=org['id'])

result = helpers.get_recently_updated_datasets()
assert len(result) == 4
assert len(result) == 4, 'Epextec 4 but got %s' % len(result)
assert result[0]['id'] == dataset['id']

result = helpers.get_recently_updated_datasets(limit=2)
assert len(result) == 2
assert result[0]['id'] == dataset['id']

def test_get_recently_updated_datasets_lists_only_approved(self):
user = core_factories.User()
org = core_factories.Organization(
users=[{'name': user['name'], 'capacity': 'admin'}]
)
factories.Dataset(owner_org=org['id'], approval_state='approval_pending')
factories.Dataset(owner_org=org['id'], approval_state='approval_pending')
factories.Dataset(owner_org=org['id'])
dataset = factories.Dataset(owner_org=org['id'])

result = helpers.get_recently_updated_datasets()
assert len(result) == 2, 'Epextec 2 but got %s' % len(result)
assert result[0]['id'] == dataset['id']

def test_get_groups(self):
group1 = core_factories.Group()

Expand All @@ -31,3 +49,24 @@ def test_get_groups(self):
result = helpers.get_groups()
assert result[0]['id'] == group1['id']
assert len(result) == 4

def test_is_admin(self):
core_factories.User(name='george')
core_factories.User(name='john')
core_factories.User(name='paul')
core_factories.Organization(
users=[
{'name': 'george', 'capacity': 'admin'},
{'name': 'john', 'capacity': 'editor'},
{'name': 'paul', 'capacity': 'reader'}
]
)

result = helpers.is_admin('george')
assert result, '%s is not True' % result
result = helpers.is_admin('john')
assert not result, '%s is not False' % result
result = helpers.is_admin('paul')
assert not result, '%s is not False' % result
result = helpers.is_admin('ringo')
assert not result, '%s is not False' % result
Loading