Commit d8c4b644 authored by David Read's avatar David Read
Browse files

Merge branch 'master' into spatial-ol3-integration

parents 5b8cec6b de79e795
......@@ -18,8 +18,15 @@ ds_stats = Stats()
UPDATE_FORMATS = {
'CSV / ZIP': 'CSV', # legacy - we now drop mention of the zip
'XML': 'WFS', # previously we set UKLP WFS resources as XML but we can detect WFS now
'XML': 'Atom Feed',
'XML': set((
'WFS', # previously we set UKLP WFS resources as XML but we can detect WFS now
'Atom Feed',
'SHP',
'WCS',
'WMTS',
)),
'DBASE': 'SHP',
'ZIP': 'SHP',
}
......@@ -88,7 +95,9 @@ class SetResourceFormatsCommand(object):
res_updated = self.update_resource_dict(
resource, qa_info, res_nice_name)
elif format_.upper() in UPDATE_FORMATS and \
qa_info['format'] == UPDATE_FORMATS[format_.upper()]:
(qa_info['format'] == UPDATE_FORMATS[format_.upper()]
or
qa_info['format'] in UPDATE_FORMATS[format_.upper()]):
res_updated = self.update_resource_dict(
resource, qa_info, res_nice_name)
else:
......
......@@ -1018,7 +1018,7 @@ def get_licenses(pkg):
# pkg.license value as a License.id value.
if pkg.license:
licenses.append((pkg.license.title.split('::')[-1], pkg.license.url, pkg.license.isopen(), pkg.license.id == 'uk-ogl'))
elif pkg.license_id:
elif pkg.license_id and pkg.license_id != 'None':
# However if the user selects 'free text' in the form, that is stored in
# the same pkg.license field.
licenses.append((pkg.license_id, None, None, pkg.license_id.startswith('Open Government Licen')))
......
......@@ -675,3 +675,96 @@ la_schemas_info = {
'generate': la_schemas,
'template': 'report/la_schemas.html',
}
# Licence report
def licence_report(organization=None, include_sub_organizations=False):
'''
Returns a dictionary detailing licences for datasets in the
organisation specified, and optionally sub organizations.
'''
import json
# Get packages
if organization:
top_org = model.Group.by_name(organization)
if not top_org:
raise p.toolkit.ObjectNotFound('Publisher not found')
if include_sub_organizations:
orgs = lib.go_down_tree(top_org)
else:
orgs = [top_org]
pkgs = set()
for org in orgs:
org_pkgs = model.Session.query(model.Package)\
.filter_by(state='active')
org_pkgs = lib.filter_by_organizations(
org_pkgs, organization,
include_sub_organizations=False)\
.all()
pkgs |= set(org_pkgs)
else:
pkgs = model.Session.query(model.Package)\
.filter_by(state='active')\
.all()
# Get their licences
packages_by_licence = collections.defaultdict(list)
rows = []
for pkg in pkgs:
licence = None
if pkg.license:
licence = pkg.license.title
elif pkg.license_id and pkg.license_id != 'None':
licence = pkg.license_id
elif 'licence' in pkg.extras:
licence = pkg.extras['licence']
# UKLP datasets have this as a list that gets json encoded
try:
licence = '; '.join(json.loads(pkg.extras['licence']))
except ValueError:
pass
licence_url = pkg.extras.get('licence_url')
if licence_url:
if licence:
licence += ' <%s>' % licence_url
else:
licence = licence_url
packages_by_licence[licence].append((pkg.name, pkg.title))
for licence, dataset_tuples in sorted(packages_by_licence.items(),
key=lambda x: -len(x[1])):
dataset_tuples.sort(key=lambda x: x[0])
dataset_names, dataset_titles = zip(*dataset_tuples)
licence_dict = OrderedDict((
('licence', licence),
('dataset_titles', '|'.join(t for t in dataset_titles)),
('dataset_names', ' '.join(dataset_names)),
))
rows.append(licence_dict)
return {
'num_datasets': len(pkgs),
'num_licences': len(rows),
'table': rows,
}
def licence_combinations():
for organization in lib.all_organizations(include_none=True):
for include_sub_organizations in (False, True):
yield {'organization': organization,
'include_sub_organizations': include_sub_organizations}
licence_report_info = {
'name': 'licence',
'title': 'Licences',
'description': 'Licenses for datasets, reported by publisher.',
'option_defaults': OrderedDict((('organization', None),
('include_sub_organizations', False))),
'option_combinations': licence_combinations,
'generate': licence_report,
'template': 'report/licence_report.html',
}
......@@ -378,6 +378,7 @@ class PublisherPlugin(p.SingletonPlugin):
reports.app_dataset_theme_report_info,
reports.app_dataset_report_info,
reports.admin_editor_info,
reports.licence_report_info,
]
......
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:i18n="http://genshi.edgewall.org/i18n"
xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip=""
>
<!--! Herein can be found generic helper methods for a whole bunch of common
templating issues -->
<py:def function="paginator(pageobj)">
<py:with vars="
page=pageobj.page;
numpages=pageobj.page_count;
url_for_page=lambda x:pageobj._url_generator(page=x)
">
<div class="dgu-pagination" py:if="numpages>1">
<ul class="pagination">
<li>
<a py:if="page>1" href="${url_for_page(page-1)}">&laquo;</a>
<span py:if="page==1">&laquo;</span>
</li>
<li py:for="(text,url) in h.pagination_links(page,numpages,url_for_page)">
<a py:if="url" href="${url}">${text}</a>
<span py:if="not url">${text}</span>
</li>
<li>
<a py:if="numpages-page>0" href="${url_for_page(page+1)}">&raquo;</a>
<span py:if="page==numpages">&raquo;</span>
</li>
</ul>
</div>
</py:with>
<div class="clearfix clearfix-ie7"></div>
</py:def>
<py:def function="breadcrumbs(kvlist)">
<div class="col-md-12">
<ul id="breadcrumbs">
<li><a href="/"><i class="icon-home"></i></a></li>
<py:for each="k,v in kvlist">
<li class="spacer">&nbsp;/&nbsp;</li>
<li><a href="${v}">${k}</a></li>
</py:for>
</ul>
</div>
</py:def>
<!-- pure one-liner to avoid whitespace glitches -->
<py:def function="if_(testValue,stringIfTrue,stringIfFalse='')"><py:if test="testValue">${stringIfTrue}</py:if><py:if test="not testValue">${stringIfFalse}</py:if></py:def>
<div py:def="search_form(mini=False, placeholder='Search for data...', set_fields=None, extra_options=None)" class="search-area">
<div class="clearfix dgu-equal-height" data-selector=".auto-height">
<div class="${if_(mini,'mini','left')}">
<div class="left-inner auto-height">
<form class="form-search" action="${h.url_for(controller='package', action='search')}" method="GET">
<div class="input-group">
<input class="form-control" type="text" name="q" value="${c.q}" results="0" placeholder="${placeholder}" />
<span class="input-group-btn">
<button type="submit" class="btn btn-default">
<i class="icon-search"></i>
</button>
</span>
</div>
<py:if test="c.fields">
<py:for each="(k, v) in c.fields">
<input type="hidden" name="${k}" value="${v}"/>
</py:for>
</py:if>
<py:if test="set_fields">
<py:for each="(k, v) in set_fields.items()">
<input type="hidden" name="${k}" value="${v}" />
</py:for>
</py:if>
<py:if test="request.params.get('ext_bbox','')">
<input type="hidden" id="ext_bbox" name="ext_bbox" value="${request.params.get('ext_bbox','')}" />
</py:if>
</form>
<py:if test="extra_options">
${extra_options()}
</py:if>
</div>
</div>
<div class="right" py:if="not mini">
<div class="right-inner auto-height">
<div class="chevron"></div>
<py:if test="not c.query_error" py:with="count = c.page.item_count if c.page not in (None, '') else c.package_count or 0">
<div class="result-count">${count}</div>
<div class="result-count-footer">Dataset${if_(count!=1,'s')}</div>
</py:if>
<py:if test="c.query_error">
<div class="result-count-footer">Search Error</div>
</py:if>
</div>
</div>
</div>
</div>
<py:def function="map_preview_button_direct(pkg_dict,small=True)">
<a href="/data/map-preview?${h.get_wms_info_urls(pkg_dict)}${'&amp;n=%s&amp;w=%s&amp;e=%s&amp;s=%s' % h.get_wms_info_extent(pkg_dict) if h.get_wms_info_extent(pkg_dict) else ''}" class="btn btn-default ${if_(small,'btn-xs','')} btn-info btn-preview preview-now"><i class="icon-map-marker"></i>&nbsp; Preview on Map</a>
</py:def>
<div py:def="package_list_from_dict(packages,mini=False)" class="common-dataset-list">
<div class="${if_(mini,'row')}">
<py:for each="i in range(len(packages))">
<div class="clearfix visible-lg" py:if="i%4==0"></div>
<div class="clearfix visible-md clearfix-ie7" py:if="i%3==0"></div>
<div class="clearfix visible-sm" py:if="i%2==0"></div>
<py:with vars="
package=packages[i];
unpublished=h.is_unpublished_item(packages[i]);
title=packages[i].get('title') or packages[i].get('name');
primary_theme=h.get_primary_theme(packages[i])">
<div class="${if_(mini,'col-lg-3 col-md-4 col-sm-6')}">
<div class="dataset dataset-summary theme-${primary_theme or 'none'} ${if_(mini,'mini')} ${if_(unpublished,'unpublished')}">
<a class="dataset-header" href="${h.url_for(controller='package', action='read', id=package.get('name'))}">
<div class="theme-name">${primary_theme or '(Uncategorised)'}</div>
<div class="underlined">${title} <span class="text-unpublished" py:if="unpublished">(unpublished)</span></div>
</a>
<div class="dataset-body">
<div class="left">
<a class="dataset-publisher" href="${h.url_for(controller='ckanext.dgu.controllers.publisher:PublisherController', action='read', id=h.package_publisher_dict(package).get('name', ''))}">
${h.package_publisher_dict(package).get('title', '')}
</a>
<div class="dataset-description">
${h.markdown_extract(package.notes)}
</div>
</div>
<div class="right">
<py:if test="h.is_core_dataset(package)">
<div title="This dataset is part of the National Information Infrastructure" class="js-tooltip format-box" style='background-color: #8BC658;'>NII</div>
</py:if>
<py:for each="format in h.formats_for_package(package)">
${format_box(format.lower())}
</py:for>
<py:if test="not mini and h.get_wms_info_urls(package)">
<div class="map-buttons">
<span style="display: none;" class="js-data-id">${package.id}</span>
<span style="display: none;" class="js-data-title">${package.get('title')}</span>
<span style="display: none;" class="js-data-querystring">${h.get_wms_info_urls(package)}</span>
<span style="display: none;" class="js-data-extent">${','.join(h.get_wms_info_extent(package))}</span>
${map_preview_button_direct(package)}
<py:with vars="in_basket=package.id in session.get('preview_list',[])">
<span
class="preview-add js-dataset-${package.id}-add"
style="${if_(in_basket,'display: none;')}">
<button data-id="${package.id}" class="btn btn-default btn-xs btn-info btn-preview btn-basket"><i class="icon-shopping-cart"></i>&nbsp; Add to Preview List</button>
</span>
<span
class="preview-remove js-dataset-${package.id}-remove"
style="${if_(not in_basket,'display: none;')}">
<button data-id="${package.id}" class="btn btn-danger btn-xs btn-preview btn-basket"><i class="icon-shopping-cart"></i>&nbsp; Remove from List</button>
</span>
</py:with>
</div>
</py:if>
</div>
<div class="clearfix clearfix-ie7"> &nbsp;</div>
<a class="view-data-link" href="${h.url_for(controller='package', action='read', id=package.get('name'))}">
View Data
</a>
</div>
</div>
</div>
</py:with>
</py:for>
</div>
</div>
<py:def function="facet_box(title, unselected, selected, if_empty, more_button=None)">
<div class="facet-box-unboxed">
<h4 class="facet-title">${title}</h4>
<div class="facet-options">
<py:for each="(link,text,tooltip) in selected">
<div class="facet-option facet-option-selected">
<a href="${link}">
<div class="facet-kill pull-right">
<i class="icon-large icon-remove-sign"></i>
</div>
<span class="${if_(tooltip is not None,'js-tooltip')}" data-original-title="${tooltip}" data-placement="right">
${h.literal(text)}
</span>
</a>
</div>
</py:for>
<py:for each="i in range(len(unselected))">
<py:with vars=" (link,text,tooltip)=unselected[i]; overflow=i>5 and (more_button is not None) ">
<div class="facet-option ${if_(overflow,'more-%s'%more_button)}" style="${if_(overflow,'display:none;')}">
<a href="${link}">
<span class="${if_(tooltip is not None,'js-tooltip')}" data-original-title="${tooltip}" data-placement="right">
${h.literal(text)}
</span>
</a>
</div>
</py:with>
</py:for>
<py:if test="more_button is not None and len(unselected)>5">
<a id="${more_button}" class="facet-expand-collapse" href="#">
<div class="expander">
<i class="icon-double-angle-down"></i>&nbsp; more &nbsp;<i class="icon-double-angle-down"></i>
</div>
<div class="collapser">
<i class="icon-double-angle-up"></i>&nbsp; less &nbsp;<i class="icon-double-angle-up"></i>
</div>
</a>
</py:if>
<div class="facet-option" py:if="not len(selected) and not len(unselected)"><em>${if_empty}</em></div>
</div>
</div>
</py:def>
<div py:def="facet_filters()" class="datasets">
<div class="facet-filters">
<div class="visible-xs visible-sm">
<a href="#" class="hide-facets">
<i class="icon-remove-circle icon-4x"></i>
</a>
</div>
${facet_box(
'Show only...',
h.search_facets_unselected(['unpublished']),
h.search_facets_selected(['unpublished']),
'No further filters to apply.'
)}
<div class="facet-divider"></div>
${facet_box(
'NII datasets',
h.search_facets_unselected(['core_dataset']),
h.search_facets_selected(['core_dataset']),
'No further filters to apply.'
)}
<div class="facet-divider"></div>
${facet_box(
'Licence',
h.search_facets_unselected(['license_id-is-ogl']),
h.search_facets_selected(['license_id-is-ogl']),
'No further licence filters to apply.'
)}
<div class="facet-divider"></div>
<!--
<label class="checkbox pull-right search-theme-checkbox">
<input type="checkbox" id="search-theme-mode" py:attrs="h.search_theme_mode_attrs()"></input>
Only primary theme
</label>
<div class="facets-theme-primary ${if_(not h.search_theme_mode_secondary(),'enabled','disabled')}">
-->
<div class="facets-theme-primary">
${facet_box(
'Theme',
h.search_facets_unselected(['theme-primary']),
h.search_facets_selected(['theme-primary']),
'No further theme filters to apply.',
more_button='more-prithemes-button'
)}
</div>
<!--
<div class="facets-theme-all ${if_(h.search_theme_mode_secondary(),'enabled','disabled')}">
${facet_box(
'Themes',
h.search_facets_unselected(['all_themes']),
h.search_facets_selected(['all_themes']),
'No further theme filters to apply.',
more_button='more-themes-button'
)}
</div>
-->
<div class="facet-divider"></div>
${facet_box(
'Resource Format',
h.search_facets_unselected(['res_format']),
h.search_facets_selected(['res_format']),
'No further format filters to apply.',
more_button='more-formats-button'
)}
<div class="facet-divider"></div>
<py:if test="request.params.get('parent_publishers','')">
${facet_box(
'Publisher',
h.search_facets_unselected(['parent_publishers']),
h.search_facets_selected(['parent_publishers']),
'No further publisher filters to apply.',
more_button='more-publishers-button'
)}
</py:if>
<py:if test="not request.params.get('parent_publishers','')">
${facet_box(
'Publisher',
h.search_facets_unselected(['publisher']),
h.search_facets_selected(['publisher']),
'No further publisher filters to apply.',
more_button='more-publishers-button'
)}
</py:if>
<div class="facet-divider"></div>
${facet_box(
'Openness Score (beta)',
h.search_facets_unselected(['openness_score'],'name'),
h.search_facets_selected(['openness_score']),
'No further openness filters to apply.',
)}
<div class="facet-divider"></div>
${facet_box(
'Broken links',
h.search_facets_unselected(['broken_links']),
h.search_facets_selected(['broken_links']),
'No further broken link filters to apply.'
)}
<div class="facet-divider"></div>
${facet_box(
'UK Location Dataset Type',
h.search_facets_unselected(['UKLP','resource-type','spatial-data-service-type']),
h.search_facets_selected(['UKLP','resource-type','spatial-data-service-type']),
'No further type filters to apply.'
)}
</div><!-- /facet-filters -->
</div>
<!--! Contact details -->
<py:def function="contact_details(name, email, phone, web_url, web_name)">
<py:choose test="">
<li py:when="email and '@' in email">Email:
<a href="mailto:${email}">${email}</a>
</li>
<li py:when="email and 'http' in email">Web contact form:
<a href="${email}">${email}</a>
</li>
<li py:when="email">Email:
${email}
</li>
</py:choose>
<li py:if="phone">Phone:
${phone}
</li>
<li py:if="web_url">Web:
<a href="${web_url}">${h.truncate(web_name or web_url, 32)}</a>
</li>
<p py:if="not (email or phone or web_url)"><em>No details supplied</em></p>
</py:def>
<py:def function="format_box(format_name)">
<div class="format-box">
<span py:if="format_name" property="dc:format">${h.dgu_format_name(format_name)}</span>
</div>
</py:def>
<!--! Form input for primary/secondary themes -->
<py:def function="primary_theme_input(data, errors)">
<py:for each="theme, theme_dict in sorted(h.themes().iteritems())">
<label class="radio js-tooltip" data-original-title="${theme_dict['description'].replace('£', '&pound;')}">
<input type="radio" name="theme-primary" value="${theme}" py:attrs="{'checked': 'checked' if data.get('theme-primary', '') == theme else None}" />
${theme_dict['title']}
</label>
</py:for>
<p class="field_error" py:if="errors.get('theme-primary', '')">${errors.get('theme-primary', '')}</p>
</py:def>
<py:def function="secondary_theme_input(data, errors)">
<py:for each="theme, theme_dict in sorted(h.themes().iteritems())">
<label class="checkbox js-tooltip" data-original-title="${theme_dict['description'].replace('£', '&pound;')}">
<input type="checkbox" name="theme-secondary" value="${theme}" py:attrs="{'checked': 'checked' if theme in h.secondary_themes(data) else None}"/>
${theme_dict['title']}
</label>
</py:for>
<p class="field_error" py:if="errors.get('theme-secondary', '')">${errors.get('theme-secondary', '')}</p>
</py:def>
</html>
......@@ -46,7 +46,7 @@
<tr>
<td colspan="3">
<a href="javascript:0" class="addrow btn btn-info">Add row</a>
<a id="add1" href="javascript:0" class="addrow btn btn-info">Add row</a>
</td>
</tr>
......@@ -81,7 +81,7 @@
<tr>
<td colspan="3">
<a href="javascript:0" class="addrow btn btn-info">Add row</a>
<a id="add2" href="javascript:0" class="addrow btn btn-info">Add row</a>
</td>
</tr>
......@@ -119,7 +119,7 @@
<tr>
<td colspan="3">
<a href="javascript:0" class="addrow btn btn-info">Add row</a>
<a id="add3" href="javascript:0" class="addrow btn btn-info">Add row</a>
</td>
</tr>
</tbody>
......@@ -147,7 +147,15 @@
{% block optional_head %}
<script type="text/javascript">
$(document).ready(function(){
console.log( $('.addrow').length )
var clones = {};
$('.addrow').each(function(index) {
clones[$(this).id] = $(this).closest('tr').prev().clone(true, true);
});
// Only add chosen to selects after cloning
// https://stackoverflow.com/questions/26995336/jquery-chosen-not-working-for-cloned-row
$('.commitment-chzn-select').chosen();
$('.addrow').on('click',function (e) {
e.preventDefault();
......@@ -161,7 +169,7 @@
var previousId = currentCount - 1;
var prev = $(this).closest('tr').prev();
var tr_new = prev.clone(true, true);
var tr_new = clones[$(this).id].clone(true, true);
$(tr_new).find(':input', 'select', 'textarea').each(function(){
// Reset the value and update the name attributes on all of the new
// fields
......@@ -176,14 +184,6 @@
}
});
$(tr_new).find('select').each(function(){
// Remove all of the chosen info.
$(this).removeClass("chzn-done");
$(this).removeAttr("id");
$(this).css("display", "block");
$(this).next().remove();
});
$(tr_new).insertAfter($(prev));
// Must only activate chosen AFTER it is back in the DOM.
......
......@@ -19,7 +19,7 @@
<textarea name="{{src}}__{{idx}}__notes" class="form-control" rows='12'>{{commitment.notes if commitment else ''}}</textarea>
</td>
<td style="width:20%">
<select class="chzn-select" style="width:200px;" name="{{src}}__{{idx}}__dataset">
<select class="commitment-chzn-select" style="width:200px;" name="{{src}}__{{idx}}__dataset">
<option value="">Please select</option>
{% for name,title in c.packages %}
<option value="{{name}}" {% if name == dataset %}selected="selected"{% endif %}>{{title}}</option>
......@@ -32,4 +32,4 @@
</td>
</tr>
{% endwith %}
{% endmacro %}
\ No newline at end of file
{% endmacro %}
<html xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip="">
<py:def function="page_title">Edit - ${c.group.display_name}</py:def>
<py:def function="page_heading">Edit - ${c.group.display_name}</py:def>
<div py:match="content" class="group-edit-form">
<div class="boxed">