Migrate from IRoute to IBlueprint
This commit is contained in:
parent
c43c549539
commit
f1341686c0
|
@ -1,2 +1,3 @@
|
||||||
recursive-include ckanext/privatedatasets/templates *
|
recursive-include ckanext/privatedatasets/templates *
|
||||||
recursive-include ckanext/privatedatasets/fanstatic *
|
recursive-include ckanext/privatedatasets/templates_2.8 *
|
||||||
|
recursive-include ckanext/privatedatasets/fanstatic *
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Copyright (c) 2014 CoNWeT Lab., Universidad Politécnica de Madrid
|
|
||||||
|
|
||||||
# This file is part of CKAN Private Dataset Extension.
|
|
||||||
|
|
||||||
# CKAN Private Dataset Extension is free software: you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Affero General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
|
|
||||||
# CKAN Private Dataset Extension is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with CKAN Private Dataset Extension. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import ckanext.privatedatasets.constants as constants
|
|
||||||
import ckan.lib.base as base
|
|
||||||
import ckan.model as model
|
|
||||||
import ckan.plugins as plugins
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from ckan.common import _
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class AcquiredDatasetsControllerUI(base.BaseController):
|
|
||||||
|
|
||||||
def user_acquired_datasets(self):
|
|
||||||
|
|
||||||
c = plugins.toolkit.c
|
|
||||||
context = {
|
|
||||||
'model': model,
|
|
||||||
'session': model.Session,
|
|
||||||
'user': plugins.toolkit.c.user,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Get user information
|
|
||||||
try:
|
|
||||||
c.user_dict = plugins.toolkit.get_action('user_show')(context.copy(), {'user_obj': c.userobj})
|
|
||||||
c.user_dict['acquired_datasets'] = plugins.toolkit.get_action(constants.ACQUISITIONS_LIST)(context.copy(), None)
|
|
||||||
except plugins.toolkit.ObjectNotFound:
|
|
||||||
plugins.toolkit.abort(404, _('User not found'))
|
|
||||||
except plugins.toolkit.NotAuthorized:
|
|
||||||
plugins.toolkit.abort(401, _('Not authorized to see this page'))
|
|
||||||
|
|
||||||
return plugins.toolkit.render('user/dashboard_acquired.html')
|
|
|
@ -1,6 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2014 - 2017 CoNWeT Lab., Universidad Politécnica de Madrid
|
# Copyright (c) 2014 - 2017 CoNWeT Lab., Universidad Politécnica de Madrid
|
||||||
|
# Copyright (c) 2018 Future Internet Consulting and Development Solutions S.L.
|
||||||
|
|
||||||
# This file is part of CKAN Private Dataset Extension.
|
# This file is part of CKAN Private Dataset Extension.
|
||||||
|
|
||||||
|
@ -17,15 +18,16 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with CKAN Private Dataset Extension. If not, see <http://www.gnu.org/licenses/>.
|
# along with CKAN Private Dataset Extension. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
from ckan import model, plugins as p
|
from ckan import model, plugins as p
|
||||||
from ckan.lib import search
|
from ckan.lib import search
|
||||||
from ckan.lib.plugins import DefaultPermissionLabels
|
from ckan.lib.plugins import DefaultPermissionLabels
|
||||||
from ckan.plugins import toolkit as tk
|
from ckan.plugins import toolkit as tk
|
||||||
|
from flask import Blueprint
|
||||||
|
|
||||||
from ckanext.privatedatasets import auth, actions, constants, converters_validators as conv_val, db, helpers
|
from ckanext.privatedatasets import auth, actions, constants, converters_validators as conv_val, db, helpers
|
||||||
|
from ckanext.privatedatasets.views import acquired_datasets
|
||||||
|
|
||||||
HIDDEN_FIELDS = [constants.ALLOWED_USERS, constants.SEARCHABLE]
|
HIDDEN_FIELDS = [constants.ALLOWED_USERS, constants.SEARCHABLE]
|
||||||
|
|
||||||
|
@ -35,7 +37,7 @@ class PrivateDatasets(p.SingletonPlugin, tk.DefaultDatasetForm, DefaultPermissio
|
||||||
p.implements(p.IDatasetForm)
|
p.implements(p.IDatasetForm)
|
||||||
p.implements(p.IAuthFunctions)
|
p.implements(p.IAuthFunctions)
|
||||||
p.implements(p.IConfigurer)
|
p.implements(p.IConfigurer)
|
||||||
p.implements(p.IRoutes, inherit=True)
|
p.implements(p.IBlueprint)
|
||||||
p.implements(p.IActions)
|
p.implements(p.IActions)
|
||||||
p.implements(p.IPackageController, inherit=True)
|
p.implements(p.IPackageController, inherit=True)
|
||||||
p.implements(p.ITemplateHelpers)
|
p.implements(p.ITemplateHelpers)
|
||||||
|
@ -128,22 +130,22 @@ class PrivateDatasets(p.SingletonPlugin, tk.DefaultDatasetForm, DefaultPermissio
|
||||||
def update_config(self, config):
|
def update_config(self, config):
|
||||||
# Add this plugin's templates dir to CKAN's extra_template_paths, so
|
# Add this plugin's templates dir to CKAN's extra_template_paths, so
|
||||||
# that CKAN will use this plugin's custom templates.
|
# that CKAN will use this plugin's custom templates.
|
||||||
tk.add_template_directory(config, 'templates')
|
if p.toolkit.check_ckan_version(min_version='2.8'):
|
||||||
|
tk.add_template_directory(config, 'templates_2.8')
|
||||||
|
else:
|
||||||
|
tk.add_template_directory(config, 'templates')
|
||||||
|
|
||||||
# Register this plugin's fanstatic directory with CKAN.
|
# Register this plugin's fanstatic directory with CKAN.
|
||||||
tk.add_resource('fanstatic', 'privatedatasets')
|
tk.add_resource(b'fanstatic', b'privatedatasets')
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
############################## IROUTES ###############################
|
############################# IBLUEPRINT #############################
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def before_map(self, m):
|
def get_blueprint(self):
|
||||||
# DataSet acquired notification
|
blueprint = Blueprint('privatedatasets', self.__module__)
|
||||||
m.connect('user_acquired_datasets', '/dashboard/acquired', ckan_icon='shopping-cart',
|
blueprint.add_url_rule('/dashboard/acquired', 'acquired_datasets', acquired_datasets)
|
||||||
controller='ckanext.privatedatasets.controllers.ui_controller:AcquiredDatasetsControllerUI',
|
return blueprint
|
||||||
action='user_acquired_datasets', conditions=dict(method=['GET']))
|
|
||||||
|
|
||||||
return m
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
############################## IACTIONS ##############################
|
############################## IACTIONS ##############################
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs">
|
||||||
{{ h.build_nav_icon('user_dashboard', _('News feed')) }}
|
{{ h.build_nav_icon('user_dashboard', _('News feed')) }}
|
||||||
{{ h.build_nav_icon('user_dashboard_datasets', _('My Datasets')) }}
|
{{ h.build_nav_icon('user_dashboard_datasets', _('My Datasets')) }}
|
||||||
{{ h.build_nav_icon('user_acquired_datasets', _('Acquired Datasets')) }}
|
{{ h.build_nav_icon('privatedatasets.acquired_datasets', _('Acquired Datasets')) }}
|
||||||
{{ h.build_nav_icon('user_dashboard_organizations', _('My Organizations')) }}
|
{{ h.build_nav_icon('user_dashboard_organizations', _('My Organizations')) }}
|
||||||
{{ h.build_nav_icon('user_dashboard_groups', _('My Groups')) }}
|
{{ h.build_nav_icon('user_dashboard_groups', _('My Groups')) }}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -46,4 +46,4 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
|
|
||||||
{% block primary_content_inner %}
|
{% block primary_content_inner %}
|
||||||
<h2 class="hide-heading">{{ _('Acquired Datasets') }}</h2>
|
<h2 class="hide-heading">{{ _('Acquired Datasets') }}</h2>
|
||||||
{% if c.user_dict.acquired_datasets %}
|
{% if acquired_datasets %}
|
||||||
{% snippet 'snippets/package_list.html', packages=c.user_dict.acquired_datasets %}
|
{% snippet 'snippets/package_list.html', packages=acquired_datasets %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="empty">
|
<p class="empty">
|
||||||
{{ _('You haven\'t acquired any datasets.') }}
|
{{ _('You haven\'t acquired any datasets.') }}
|
||||||
{% link_for _('Acquire one now?'), controller='package', action='search' %}
|
{% link_for _('Acquire one now?'), controller='package', action='search' %}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
{% ckan_extends %}
|
||||||
|
|
||||||
|
{% block package_basic_fields_org %}
|
||||||
|
|
||||||
|
{% resource 'privatedatasets/allowed_users.js' %}
|
||||||
|
|
||||||
|
{# if we have a default group then this wants remembering #}
|
||||||
|
{% if data.group_id %}
|
||||||
|
<input type="hidden" name="groups__0__id" value="{{ data.group_id }}" />
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% set dataset_is_draft = data.get('state', 'draft').startswith('draft') or data.get('state', 'none') == 'none' %}
|
||||||
|
{% set dataset_has_organization = data.owner_org or data.group_id %}
|
||||||
|
{% set organizations_available = h.organizations_available('create_dataset') %}
|
||||||
|
{% set user_is_sysadmin = h.check_access('sysadmin') %}
|
||||||
|
{% set show_organizations_selector = organizations_available and (user_is_sysadmin or dataset_is_draft) %}
|
||||||
|
{% set editing = 'id' in data %}
|
||||||
|
|
||||||
|
{% if show_organizations_selector and show_visibility_selector %}
|
||||||
|
<div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if show_organizations_selector %}
|
||||||
|
{% set existing_org = data.owner_org or data.group_id %}
|
||||||
|
<div class="control-group">
|
||||||
|
<label for="field-organizations" class="control-label">{{ _('Organization') }}</label>
|
||||||
|
<div class="controls">
|
||||||
|
<select id="field-organizations" name="owner_org" data-module="autocomplete">
|
||||||
|
{% if h.check_config_permission('create_unowned_dataset') %}
|
||||||
|
<option value="" {% if not selected_org and data.id %} selected="selected" {% endif %}>{{ _('No organization') }}</option>
|
||||||
|
{% endif %}
|
||||||
|
{% for organization in organizations_available %}
|
||||||
|
{# get out first org from users list only if there is not an existing org #}
|
||||||
|
{% set selected_org = (existing_org and existing_org == organization.id) or (not existing_org and not data.id and organization.id == organizations_available[0].id) %}
|
||||||
|
<option value="{{ organization.id }}" {% if selected_org %} selected="selected" {% endif %}>{{ organization.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% block package_metadata_fields_visibility %}
|
||||||
|
<div class="control-group">
|
||||||
|
<label for="field-private" class="control-label">{{ _('Visibility') }}</label>
|
||||||
|
<div class="controls">
|
||||||
|
<select id="field-private" name="private" data-module="allowed-users">
|
||||||
|
{% for option in [('True', _('Private')), ('False', _('Public'))] %}
|
||||||
|
<option value="{{ option[0] }}" {% if option[0] == data.private|trim %}selected="selected"{% endif %}>{{ option[1] }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<span class="info-block info-inline">
|
||||||
|
<i class="icon-info-sign fa fa-info-circle"></i>
|
||||||
|
{% trans %}
|
||||||
|
Private datasets can only be accessed by certain users, while public datasets can be accessed by anyone.
|
||||||
|
{% endtrans %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block package_metadata_fields_protected %}
|
||||||
|
<div class="control-group">
|
||||||
|
<label for="field-searchable" class="control-label">{{ _('Searchable') }}</label>
|
||||||
|
<div class="controls">
|
||||||
|
<select id="field-searchable" name="searchable">
|
||||||
|
{% for option in [('True', _('True')), ('False', _('False'))] %}
|
||||||
|
<option value="{{ option[0] }}" {% if option[0] == data.searchable|trim %}selected="selected"{% endif %}>{{ option[1] }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<span class="info-block info-inline">
|
||||||
|
<i class="icon-info-sign fa fa-info-circle"></i>
|
||||||
|
{% trans %}
|
||||||
|
Searchable datasets can be searched by anyone, while not-searchable datasets can only be accessed by entering directly its URL.
|
||||||
|
{% endtrans %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% if show_organizations_selector and show_visibility_selector %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% set users_attrs = {'data-module': 'autocomplete', 'data-module-tags': '', 'data-module-source': '/api/2/util/user/autocomplete?q=?'} %}
|
||||||
|
{{ form.input('allowed_users_str', label=_('Allowed Users'), id='field-allowed_users_str', placeholder=_('Allowed Users'), value=h.get_allowed_users_str(data.allowed_users), error=errors.custom_text, classes=['control-full'], attrs=users_attrs) }}
|
||||||
|
|
||||||
|
|
||||||
|
{% if editing and h.show_acquire_url_on_edit() or not editing and h.show_acquire_url_on_create() %}
|
||||||
|
{{ form.input('acquire_url', label=_('Acquire URL'), id='field-acquire_url', placeholder=_('http://example.com/acquire/'), value=data.acquire_url, error=errors.custom_text, classes=['control-medium']) }}
|
||||||
|
{% else %}
|
||||||
|
<input type="hidden" name="acquire_url" id="acquire_url" value="{{ data.acquire_url }}" />
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if data.id and h.check_access('package_delete', {'id': data.id}) and data.state != 'active' %}
|
||||||
|
<div class="control-group">
|
||||||
|
<label for="field-state" class="control-label">{{ _('State') }}</label>
|
||||||
|
<div class="controls">
|
||||||
|
<select id="field-state" name="state">
|
||||||
|
<option value="active" {% if data.get('state', 'none') == 'active' %} selected="selected" {% endif %}>{{ _('Active') }}</option>
|
||||||
|
<option value="deleted" {% if data.get('state', 'none') == 'deleted' %} selected="selected" {% endif %}>{{ _('Deleted') }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,15 @@
|
||||||
|
{#
|
||||||
|
|
||||||
|
Displays a Get Access button to request access to a private dataset.
|
||||||
|
|
||||||
|
ulr_dest - target url
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
{% snippet 'snippets/acquire_button.html', url_dest=url %}
|
||||||
|
|
||||||
|
#}
|
||||||
|
<a href={{ url_dest }} class="btn btn-mini" target="_blank">
|
||||||
|
<i class="icon-shopping-cart fa fa-shopping-cart"></i>
|
||||||
|
{{ _('Acquire') }}
|
||||||
|
</a>
|
|
@ -0,0 +1,82 @@
|
||||||
|
{#
|
||||||
|
Displays a single of dataset.
|
||||||
|
|
||||||
|
package - A package to display.
|
||||||
|
item_class - The class name to use on the list item.
|
||||||
|
hide_resources - If true hides the resources (default: false).
|
||||||
|
banner - If true displays a popular banner (default: false).
|
||||||
|
truncate - The length to trucate the description to (default: 180)
|
||||||
|
truncate_title - The length to truncate the title to (default: 80).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
{% snippet 'snippets/package_item.html', package=c.datasets[0] %}
|
||||||
|
|
||||||
|
#}
|
||||||
|
{% set truncate = truncate or 180 %}
|
||||||
|
{% set truncate_title = truncate_title or 80 %}
|
||||||
|
{% set title = package.title or package.name %}
|
||||||
|
{% set notes = h.markdown_extract(package.notes, extract_length=truncate) %}
|
||||||
|
{% set acquired = h.is_dataset_acquired(package) %}
|
||||||
|
{% set owner = h.is_owner(package) %}
|
||||||
|
|
||||||
|
{% resource 'privatedatasets/custom.css' %}
|
||||||
|
|
||||||
|
<li class="{{ item_class or "dataset-item" }}">
|
||||||
|
{% block package_item_content %}
|
||||||
|
<div class="dataset-content">
|
||||||
|
<h3 class="dataset-heading">
|
||||||
|
{% if package.private and not h.can_read(package) %}
|
||||||
|
<span class="dataset-private label label-inverse">
|
||||||
|
<i class="icon-lock fa fa-lock"></i>
|
||||||
|
{{ _('Private') }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if acquired and not owner %}
|
||||||
|
<span class="dataset-private label label-acquired">
|
||||||
|
<i class="icon-shopping-cart fa fa-shopping-cart"></i>
|
||||||
|
{{ _('Acquired') }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if owner %}
|
||||||
|
<span class="dataset-private label label-owner">
|
||||||
|
<i class="icon-user fa fa-user"></i>
|
||||||
|
{{ _('Owner') }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Customizations Acquire Button -->
|
||||||
|
{% if package.private and not h.can_read(package) %}
|
||||||
|
{{ _(h.truncate(title, truncate_title)) }}
|
||||||
|
<div class="divider"/>
|
||||||
|
{{ h.acquire_button(package) }}
|
||||||
|
{% else %}
|
||||||
|
{{ h.link_to(h.truncate(title, truncate_title), h.url_for(controller='package', action='read', id=package.name)) }}
|
||||||
|
{% endif %}
|
||||||
|
<!-- End of customizations Acquire Button -->
|
||||||
|
|
||||||
|
{% if package.get('state', '').startswith('draft') %}
|
||||||
|
<span class="label label-info">{{ _('Draft') }}</span>
|
||||||
|
{% elif package.get('state', '').startswith('deleted') %}
|
||||||
|
<span class="label label-important">{{ _('Deleted') }}</span>
|
||||||
|
{% endif %}
|
||||||
|
{{ h.popular('recent views', package.tracking_summary.recent, min=10) if package.tracking_summary }}
|
||||||
|
</h3>
|
||||||
|
{% if banner %}
|
||||||
|
<span class="banner">{{ _('Popular') }}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if notes %}
|
||||||
|
<div>{{ notes|urlize }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% if package.resources and not hide_resources %}
|
||||||
|
<ul class="dataset-resources unstyled">
|
||||||
|
{% for resource in h.dict_list_reduce(package.resources, 'format') %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ h.url_for(controller='package', action='read', id=package.name) }}" class="label" data-format="{{ resource.lower() }}">{{ resource }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
</li>
|
|
@ -0,0 +1,49 @@
|
||||||
|
{% extends "user/edit_base.html" %}
|
||||||
|
|
||||||
|
{% set user = g.userobj %}
|
||||||
|
|
||||||
|
{% block breadcrumb_content %}
|
||||||
|
<li class="active"><a href="{{ h.url_for('dashboard.index') }}">{{ _('Dashboard') }}</a></li>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block secondary %}{% endblock %}
|
||||||
|
|
||||||
|
{% block primary %}
|
||||||
|
<article class="module">
|
||||||
|
{% block page_header %}
|
||||||
|
<header class="module-content page-header hug">
|
||||||
|
<div class="content_action">
|
||||||
|
{% link_for _('Edit settings'), named_route='user.edit', id=user.name, class_='btn btn-default', icon='cog' %}
|
||||||
|
</div>
|
||||||
|
<ul class="nav nav-tabs">
|
||||||
|
{{ h.build_nav_icon('dashboard.index', _('News feed')) }}
|
||||||
|
{{ h.build_nav_icon('dashboard.datasets', _('My Datasets')) }}
|
||||||
|
{{ h.build_nav_icon('privatedatasets.acquired_datasets', _('Acquired Datasets')) }}
|
||||||
|
{{ h.build_nav_icon('dashboard.organizations', _('My Organizations')) }}
|
||||||
|
{{ h.build_nav_icon('dashboard.groups', _('My Groups')) }}
|
||||||
|
</ul>
|
||||||
|
</header>
|
||||||
|
{% endblock %}
|
||||||
|
<div class="module-content">
|
||||||
|
{% if self.page_primary_action() | trim %}
|
||||||
|
<div class="page_primary_action">
|
||||||
|
{% block page_primary_action %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% block primary_content_inner %}
|
||||||
|
<div data-module="dashboard">
|
||||||
|
{% snippet 'user/snippets/followee_dropdown.html', context=dashboard_activity_stream_context, followees=followee_list %}
|
||||||
|
<h2 class="page-heading">
|
||||||
|
{% block page_heading %}
|
||||||
|
{{ _('News feed') }}
|
||||||
|
{% endblock %}
|
||||||
|
<small>{{ _("Activity from items that I'm following") }}</small>
|
||||||
|
</h2>
|
||||||
|
{% block activity_stream %}
|
||||||
|
{{ dashboard_activity_stream|safe }}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,19 @@
|
||||||
|
{% extends "user/dashboard.html" %}
|
||||||
|
|
||||||
|
{% block dashboard_activity_stream_context %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_primary_action %}
|
||||||
|
{% link_for _('Acquire Dataset'), controller='package', action='search', class_="btn btn-primary", icon="shopping-cart" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block primary_content_inner %}
|
||||||
|
<h2 class="hide-heading">{{ _('Acquired Datasets') }}</h2>
|
||||||
|
{% if acquired_datasets %}
|
||||||
|
{% snippet 'snippets/package_list.html', packages=acquired_datasets %}
|
||||||
|
{% else %}
|
||||||
|
<p class="empty">
|
||||||
|
{{ _('You haven\'t acquired any datasets.') }}
|
||||||
|
{% link_for _('Acquire one now?'), controller='package', action='search' %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
|
@ -1,110 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Copyright (c) 2014 CoNWeT Lab., Universidad Politécnica de Madrid
|
|
||||||
|
|
||||||
# This file is part of CKAN Private Dataset Extension.
|
|
||||||
|
|
||||||
# CKAN Private Dataset Extension is free software: you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Affero General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
|
|
||||||
# CKAN Private Dataset Extension is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with CKAN Private Dataset Extension. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import ckanext.privatedatasets.controllers.ui_controller as controller
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
from mock import MagicMock, ANY
|
|
||||||
from parameterized import parameterized
|
|
||||||
|
|
||||||
|
|
||||||
class UIControllerTest(unittest.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
|
|
||||||
# Get the instance
|
|
||||||
self.instanceUI = controller.AcquiredDatasetsControllerUI()
|
|
||||||
|
|
||||||
# Load the mocks
|
|
||||||
self._plugins = controller.plugins
|
|
||||||
controller.plugins = MagicMock()
|
|
||||||
|
|
||||||
self._model = controller.model
|
|
||||||
controller.model = MagicMock()
|
|
||||||
|
|
||||||
# Set exceptions
|
|
||||||
controller.plugins.toolkit.ObjectNotFound = self._plugins.toolkit.ObjectNotFound
|
|
||||||
controller.plugins.toolkit.NotAuthorized = self._plugins.toolkit.NotAuthorized
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
# Unmock
|
|
||||||
controller.plugins = self._plugins
|
|
||||||
controller.model = self._model
|
|
||||||
|
|
||||||
@parameterized.expand([
|
|
||||||
(controller.plugins.toolkit.ObjectNotFound, 404),
|
|
||||||
(controller.plugins.toolkit.NotAuthorized, 401)
|
|
||||||
])
|
|
||||||
def test_exceptions_loading_users(self, exception, expected_status):
|
|
||||||
|
|
||||||
# Configure the mock
|
|
||||||
user_show = MagicMock(side_effect=exception)
|
|
||||||
controller.plugins.toolkit.get_action = MagicMock(return_value=user_show)
|
|
||||||
|
|
||||||
# Call the function
|
|
||||||
self.instanceUI.user_acquired_datasets()
|
|
||||||
|
|
||||||
# Assertations
|
|
||||||
expected_context = {
|
|
||||||
'model': controller.model,
|
|
||||||
'session': controller.model.Session,
|
|
||||||
'user': controller.plugins.toolkit.c.user
|
|
||||||
}
|
|
||||||
|
|
||||||
user_show.assert_called_once_with(expected_context, {'user_obj': controller.plugins.toolkit.c.userobj})
|
|
||||||
controller.plugins.toolkit.abort.assert_called_once_with(expected_status, ANY)
|
|
||||||
|
|
||||||
def test_no_error_loading_users(self):
|
|
||||||
|
|
||||||
user = 'example_user_test'
|
|
||||||
controller.plugins.toolkit.c.user = user
|
|
||||||
|
|
||||||
# actions
|
|
||||||
default_user = {'user_name': 'test', 'another_val': 'example value'}
|
|
||||||
user_show = MagicMock(return_value=default_user)
|
|
||||||
acquisitions_list = MagicMock()
|
|
||||||
def _get_action(action):
|
|
||||||
if action == 'user_show':
|
|
||||||
return user_show
|
|
||||||
else:
|
|
||||||
return acquisitions_list
|
|
||||||
|
|
||||||
controller.plugins.toolkit.get_action = MagicMock(side_effect=_get_action)
|
|
||||||
|
|
||||||
# Call the function
|
|
||||||
returned = self.instanceUI.user_acquired_datasets()
|
|
||||||
|
|
||||||
# User_show called correctly
|
|
||||||
expected_context = {
|
|
||||||
'model': controller.model,
|
|
||||||
'session': controller.model.Session,
|
|
||||||
'user': controller.plugins.toolkit.c.user
|
|
||||||
}
|
|
||||||
|
|
||||||
user_show.assert_called_once_with(expected_context, {'user_obj': controller.plugins.toolkit.c.userobj})
|
|
||||||
|
|
||||||
# Query called correctry
|
|
||||||
expected_user = default_user.copy()
|
|
||||||
expected_user['acquired_datasets'] = acquisitions_list.return_value
|
|
||||||
acquisitions_list.assert_called_with(expected_context, None)
|
|
||||||
self.assertEquals(expected_user, controller.plugins.toolkit.c.user_dict)
|
|
||||||
|
|
||||||
# Check that the render method has been called and that its result has been returned
|
|
||||||
self.assertEquals(controller.plugins.toolkit.render.return_value, returned)
|
|
||||||
controller.plugins.toolkit.render.assert_called_once_with('user/dashboard_acquired.html')
|
|
|
@ -19,11 +19,13 @@
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import copy
|
import copy
|
||||||
import ckanext.privatedatasets.plugin as plugin
|
|
||||||
|
|
||||||
|
from flask import Blueprint
|
||||||
from mock import MagicMock
|
from mock import MagicMock
|
||||||
from parameterized import parameterized
|
from parameterized import parameterized
|
||||||
|
|
||||||
|
import ckanext.privatedatasets.plugin as plugin
|
||||||
|
|
||||||
|
|
||||||
class PluginTest(unittest.TestCase):
|
class PluginTest(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -51,7 +53,7 @@ class PluginTest(unittest.TestCase):
|
||||||
(plugin.p.IDatasetForm,),
|
(plugin.p.IDatasetForm,),
|
||||||
(plugin.p.IAuthFunctions,),
|
(plugin.p.IAuthFunctions,),
|
||||||
(plugin.p.IConfigurer,),
|
(plugin.p.IConfigurer,),
|
||||||
(plugin.p.IRoutes,),
|
(plugin.p.IBlueprint,),
|
||||||
(plugin.p.IActions,),
|
(plugin.p.IActions,),
|
||||||
(plugin.p.IPackageController,),
|
(plugin.p.IPackageController,),
|
||||||
(plugin.p.ITemplateHelpers,)
|
(plugin.p.ITemplateHelpers,)
|
||||||
|
@ -83,18 +85,15 @@ class PluginTest(unittest.TestCase):
|
||||||
self.privateDatasets.update_config(config)
|
self.privateDatasets.update_config(config)
|
||||||
|
|
||||||
# Test that functions are called as expected
|
# Test that functions are called as expected
|
||||||
plugin.tk.add_template_directory.assert_called_once_with(config, 'templates')
|
if self._tk.check_ckan_version(min_version='2.8'):
|
||||||
|
plugin.tk.add_template_directory.assert_called_once_with(config, 'templates_2.8')
|
||||||
|
else:
|
||||||
|
plugin.tk.add_template_directory.assert_called_once_with(config, 'templates')
|
||||||
plugin.tk.add_resource('fanstatic', 'privatedatasets')
|
plugin.tk.add_resource('fanstatic', 'privatedatasets')
|
||||||
|
|
||||||
def test_map(self):
|
def test_get_blueprint(self):
|
||||||
# Call the method
|
# Call the method
|
||||||
m = MagicMock()
|
self.assertIsInstance(self.privateDatasets.get_blueprint(), Blueprint)
|
||||||
self.privateDatasets.before_map(m)
|
|
||||||
|
|
||||||
# Test that the connect method has been called
|
|
||||||
m.connect.assert_any_call('user_acquired_datasets', '/dashboard/acquired', ckan_icon='shopping-cart',
|
|
||||||
controller='ckanext.privatedatasets.controllers.ui_controller:AcquiredDatasetsControllerUI',
|
|
||||||
action='user_acquired_datasets', conditions=dict(method=['GET']))
|
|
||||||
|
|
||||||
@parameterized.expand([
|
@parameterized.expand([
|
||||||
('package_acquired', plugin.actions.package_acquired),
|
('package_acquired', plugin.actions.package_acquired),
|
||||||
|
|
|
@ -47,7 +47,7 @@ class TestSelenium(unittest.TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env['DEBUG'] = 'True'
|
env['DEBUG'] = 'False'
|
||||||
cls._process = Popen(['paster', 'serve', 'test.ini'], env=env)
|
cls._process = Popen(['paster', 'serve', 'test.ini'], env=env)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -260,7 +260,7 @@ class TestSelenium(unittest.TestCase):
|
||||||
def check_acquired(self, dataset, dataset_url, acquired, private):
|
def check_acquired(self, dataset, dataset_url, acquired, private):
|
||||||
driver = self.driver
|
driver = self.driver
|
||||||
driver.get(self.base_url + 'dashboard')
|
driver.get(self.base_url + 'dashboard')
|
||||||
driver.find_element_by_link_text('Acquired Datasets').click()
|
WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.LINK_TEXT, 'Acquired Datasets'))).click()
|
||||||
|
|
||||||
if acquired and private:
|
if acquired and private:
|
||||||
# This message could not be shown when the user has acquired at least one dataset
|
# This message could not be shown when the user has acquired at least one dataset
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2018 Future Internet Consulting and Development Solutions S.L.
|
||||||
|
|
||||||
|
# This file is part of CKAN Private Dataset Extension.
|
||||||
|
|
||||||
|
# CKAN Private Dataset Extension is free software: you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
# CKAN Private Dataset Extension is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with CKAN Private Dataset Extension. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
|
from ckan import logic
|
||||||
|
from ckan.common import _, g
|
||||||
|
from ckan.lib import base
|
||||||
|
from ckan.plugins import toolkit
|
||||||
|
|
||||||
|
from ckanext.privatedatasets import constants
|
||||||
|
|
||||||
|
|
||||||
|
def acquired_datasets():
|
||||||
|
context = {'for_view': True, 'user': g.user, 'auth_user_obj': g.userobj}
|
||||||
|
data_dict = {'user_obj': g.userobj}
|
||||||
|
try:
|
||||||
|
user_dict = logic.get_action('user_show')(context, data_dict)
|
||||||
|
acquired_datasets = toolkit.get_action(constants.ACQUISITIONS_LIST)(context, None)
|
||||||
|
except logic.NotFound:
|
||||||
|
base.abort(404, _('User not found'))
|
||||||
|
except logic.NotAuthorized:
|
||||||
|
base.abort(403, _('Not authorized to see this page'))
|
||||||
|
|
||||||
|
extra_vars = {
|
||||||
|
'user_dict': user_dict,
|
||||||
|
'acquired_datasets': acquired_datasets,
|
||||||
|
}
|
||||||
|
return base.render('user/dashboard_acquired.html', extra_vars)
|
Loading…
Reference in New Issue