[ckan-changes] commit/ckanextiati: 13 new changesets
Bitbucket
commits-noreply at bitbucket.org
Wed Sep 14 17:34:51 UTC 2011
13 new changesets in ckanextiati:
http://bitbucket.org/okfn/ckanextiati/changeset/3f5b0b038046/
changeset: 3f5b0b038046
branch: new-forms
user: amercader
date: 2011-09-12 17:48:18
summary: [new forms] Add new package form, with custom template, schema and validators. Existing authz management is not affected
affected #: 7 files (25.7 KB)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/controllers/__init__.py Mon Sep 12 16:48:18 2011 +0100
@@ -0,0 +1,1 @@
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/controllers/countries.py Mon Sep 12 16:48:18 2011 +0100
@@ -0,0 +1,6 @@
+# -*- coding: UTF-8 -*-
+
+# This Python file uses the following encoding: utf-8
+# Country and regions names and codes sent by Bill Anderson on 2011-06-28
+
+COUNTRIES = (("", u"(No country assigned)"), ("AF",u"Afghanistan"),("AX",u"Ã
land Islands"),("AL",u"Albania"),("DZ",u"Algeria"),("AS",u"American Samoa"),("AD",u"Andorra"),("AO",u"Angola"),("AI",u"Anguilla"),("AQ",u"Antarctica"),("AG",u"Antigua And Barbuda"),("AR",u"Argentina"),("AM",u"Armenia"),("AW",u"Aruba"),("AU",u"Australia"),("AT",u"Austria"),("AZ",u"Azerbaijan"),("BS",u"Bahamas"),("BH",u"Bahrain"),("BD",u"Bangladesh"),("BB",u"Barbados"),("BY",u"Belarus"),("BE",u"Belgium"),("BZ",u"Belize"),("BJ",u"Benin"),("BM",u"Bermuda"),("BT",u"Bhutan"),("BO",u"Bolivia, Plurinational State Of"),("BQ",u"Bonaire, Sint Eustatius And Saba"),("BA",u"Bosnia And Herzegovina"),("BW",u"Botswana"),("BV",u"Bouvet Island"),("BR",u"Brazil"),("IO",u"British Indian Ocean Territory"),("BN",u"Brunei Darussalam"),("BG",u"Bulgaria"),("BF",u"Burkina Faso"),("BI",u"Burundi"),("KH",u"Cambodia"),("CM",u"Cameroon"),("CA",u"Canada"),("CV",u"Cape Verde"),("KY",u"Cayman Islands"),("CF",u"Central African Republic"),("TD",u"Chad"),("CL",u"Chile"),("CN",u"China"),("CX",u"Christmas Island"),("CC",u"Cocos (Keeling) Islands"),("CO",u"Colombia"),("KM",u"Comoros"),("CG",u"Congo"),("CD",u"Congo, The Democratic Republic Of The"),("CK",u"Cook Islands"),("CR",u"Costa Rica"),("CI",u"Côte D'Ivoire"),("HR",u"Croatia"),("CU",u"Cuba"),("CW",u"Curaçao"),("CY",u"Cyprus"),("CZ",u"Czech Republic"),("DK",u"Denmark"),("DJ",u"Djibouti"),("DM",u"Dominica"),("DO",u"Dominican Republic"),("EC",u"Ecuador"),("EG",u"Egypt"),("SV",u"El Salvador"),("GQ",u"Equatorial Guinea"),("ER",u"Eritrea"),("EE",u"Estonia"),("ET",u"Ethiopia"),("FK",u"Falkland Islands (Malvinas)"),("FO",u"Faroe Islands"),("FJ",u"Fiji"),("FI",u"Finland"),("FR",u"France"),("GF",u"French Guiana"),("PF",u"French Polynesia"),("TF",u"French Southern Territories"),("GA",u"Gabon"),("GM",u"Gambia"),("GE",u"Georgia"),("DE",u"Germany"),("GH",u"Ghana"),("GI",u"Gibraltar"),("GR",u"Greece"),("GL",u"Greenland"),("GD",u"Grenada"),("GP",u"Guadeloupe"),("GU",u"Guam"),("GT",u"Guatemala"),("GG",u"Guernsey"),("GN",u"Guinea"),("GW",u"Guinea-Bissau"),("GY",u"Guyana"),("HT",u"Haiti"),("HM",u"Heard Island And Mcdonald Islands"),("VA",u"Holy See (Vatican City State)"),("HN",u"Honduras"),("HK",u"Hong Kong"),("HU",u"Hungary"),("IS",u"Iceland"),("IN",u"India"),("ID",u"Indonesia"),("IR",u"Iran, Islamic Republic Of"),("IQ",u"Iraq"),("IE",u"Ireland"),("IM",u"Isle Of Man"),("IL",u"Israel"),("IT",u"Italy"),("JM",u"Jamaica"),("JP",u"Japan"),("JE",u"Jersey"),("JO",u"Jordan"),("KZ",u"Kazakhstan"),("KE",u"Kenya"),("KI",u"Kiribati"),("KP",u"Korea, Democratic People's Republic Of"),("KR",u"Korea, Republic Of"),("XK",u"Kosovo"),("KW",u"Kuwait"),("KG",u"Kyrgyzstan"),("LA",u"Lao People's Democratic Republic"),("LV",u"Latvia"),("LB",u"Lebanon"),("LS",u"Lesotho"),("LR",u"Liberia"),("LY",u"Libyan Arab Jamahiriya"),("LI",u"Liechtenstein"),("LT",u"Lithuania"),("LU",u"Luxembourg"),("MO",u"Macao"),("MK",u"Macedonia, The Former Yugoslav Republic Of"),("MG",u"Madagascar"),("MW",u"Malawi"),("MY",u"Malaysia"),("MV",u"Maldives"),("ML",u"Mali"),("MT",u"Malta"),("MH",u"Marshall Islands"),("MQ",u"Martinique"),("MR",u"Mauritania"),("MU",u"Mauritius"),("YT",u"Mayotte"),("MX",u"Mexico"),("FM",u"Micronesia, Federated States Of"),("MD",u"Moldova, Republic Of"),("MC",u"Monaco"),("MN",u"Mongolia"),("ME",u"Montenegro"),("MS",u"Montserrat"),("MA",u"Morocco"),("MZ",u"Mozambique"),("MM",u"Myanmar"),("NA",u"Namibia"),("NR",u"Nauru"),("NP",u"Nepal"),("NL",u"Netherlands"),("NC",u"New Caledonia"),("NZ",u"New Zealand"),("NI",u"Nicaragua"),("NE",u"Niger"),("NG",u"Nigeria"),("NU",u"Niue"),("NF",u"Norfolk Island"),("MP",u"Northern Mariana Islands"),("NO",u"Norway"),("OM",u"Oman"),("PK",u"Pakistan"),("PW",u"Palau"),("PS",u"Palestinian Territory, Occupied"),("PA",u"Panama"),("PG",u"Papua New Guinea"),("PY",u"Paraguay"),("PE",u"Peru"),("PH",u"Philippines"),("PN",u"Pitcairn"),("PL",u"Poland"),("PT",u"Portugal"),("PR",u"Puerto Rico"),("QA",u"Qatar"),("RE",u"Réunion"),("RO",u"Romania"),("RU",u"Russian Federation"),("RW",u"Rwanda"),("BL",u"Saint Barthélemy"),("SH",u"Saint Helena, Ascension And Tristan Da Cunha"),("KN",u"Saint Kitts And Nevis"),("LC",u"Saint Lucia"),("MF",u"Saint Martin (French Part)"),("PM",u"Saint Pierre And Miquelon"),("VC",u"Saint Vincent And The Grenadines"),("WS",u"Samoa"),("SM",u"San Marino"),("ST",u"Sao Tome And Principe"),("SA",u"Saudi Arabia"),("SN",u"Senegal"),("RS",u"Serbia"),("SC",u"Seychelles"),("SL",u"Sierra Leone"),("SG",u"Singapore"),("SX",u"Sint Maarten (Dutch Part)"),("SK",u"Slovakia"),("SI",u"Slovenia"),("SB",u"Solomon Islands"),("SO",u"Somalia"),("ZA",u"South Africa"),("GS",u"South Georgia And The South Sandwich Islands"),("ES",u"Spain"),("LK",u"Sri Lanka"),("SD",u"Sudan"),("SR",u"Suriname"),("SJ",u"Svalbard And Jan Mayen"),("SZ",u"Swaziland"),("SE",u"Sweden"),("CH",u"Switzerland"),("SY",u"Syrian Arab Republic"),("TW",u"Taiwan, Province Of China"),("TJ",u"Tajikistan"),("TZ",u"Tanzania, United Republic Of"),("TH",u"Thailand"),("TL",u"Timor-Leste"),("TG",u"Togo"),("TK",u"Tokelau"),("TO",u"Tonga"),("TT",u"Trinidad And Tobago"),("TN",u"Tunisia"),("TR",u"Turkey"),("TM",u"Turkmenistan"),("TC",u"Turks And Caicos Islands"),("TV",u"Tuvalu"),("UG",u"Uganda"),("UA",u"Ukraine"),("AE",u"United Arab Emirates"),("GB",u"United Kingdom"),("US",u"United States"),("UM",u"United States Minor Outlying Islands"),("UY",u"Uruguay"),("UZ",u"Uzbekistan"),("VU",u"Vanuatu"),("VE",u"Venezuela, Bolivarian Republic Of"),("VN",u"Viet Nam"),("VG",u"Virgin Islands, British"),("VI",u"Virgin Islands, U.S."),("WF",u"Wallis And Futuna"),("EH",u"Western Sahara"),("YE",u"Yemen"),("ZM",u"Zambia"),("ZW",u"Zimbabwe"),("298",u"Africa"),("189",u"Africa - North"),("289",u"Africa - Sub-Saharan"),("089",u"Europe"),("498",u"America"),("389",u"America - North & Central"),("489",u"America - South"),("380",u"West Indies"),("589",u"Middle East"),("798",u"Asia"),("619",u"Asia - Central"),("679",u"Asia - South"),("689",u"Asia - South & Central"),("789",u"Asia - Far East"),("889",u"Oceania"),("998",u"Unspecified"),)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/controllers/package_iati.py Mon Sep 12 16:48:18 2011 +0100
@@ -0,0 +1,136 @@
+from ckan.lib.base import c
+from ckan.lib.helpers import json
+from ckan import model
+from ckan.controllers.package import PackageController
+from ckan.authz import Authorizer
+
+from ckan.logic.schema import package_form_schema
+from ckan.lib.navl.validators import (ignore_missing,
+ not_empty,
+ empty,
+ ignore,
+ keep_extras,
+ )
+from ckan.lib.navl.dictization_functions import Missing, Invalid
+from ckan.lib.field_types import DateType, DateConvertError
+
+from countries import COUNTRIES
+
+class PackageIatiController(PackageController):
+
+ package_form = 'package/form_iati.html'
+
+ def _setup_template_variables(self, context, data_dict=None):
+
+ super(PackageIatiController,self)._setup_template_variables(context,data_dict)
+
+ c.groups_authz = self.get_groups()
+ c.groups_available = self.get_groups(available_only=True)
+
+ c.countries = [(v, k) for k, v in COUNTRIES]
+
+ def _form_to_db_schema(self):
+ schema = package_form_schema()
+ schema.update({
+ 'department': [unicode,convert_to_extras,ignore_missing],
+ 'country': [convert_to_extras, ignore_missing],
+ 'donors': [unicode, convert_from_comma_list, convert_to_extras, ignore_missing],
+ 'donors_type': [unicode, convert_from_comma_list, convert_to_extras, ignore_missing],
+ 'donors_country': [unicode, convert_from_comma_list, convert_to_extras, ignore_missing],
+ 'record_updated': [date_to_db, convert_to_extras,ignore_missing],
+ 'data_updated': [date_to_db, convert_to_extras,ignore_missing],
+ 'activity_period-from': [date_to_db, convert_to_extras,ignore_missing],
+ 'activity_period-to': [date_to_db, convert_to_extras,ignore_missing],
+ 'activity_count': [integer,convert_to_extras,ignore_missing],
+ 'archive_file': [checkbox_value, convert_to_extras,ignore_missing],
+ 'verified': [checkbox_value, convert_to_extras,ignore_missing],
+ })
+
+ return schema
+
+ def _db_to_form_schema(self):
+ schema = package_form_schema()
+ schema.update({
+ 'department': [convert_from_extras,ignore_missing],
+ 'country': [convert_from_extras, ignore_missing],
+ 'donors': [convert_from_extras, convert_to_comma_list, ignore_missing],
+ 'donors_type': [convert_from_extras, convert_to_comma_list, ignore_missing],
+ 'donors_country': [convert_from_extras, convert_to_comma_list, ignore_missing],
+ 'record_updated': [convert_from_extras,ignore_missing, date_to_form],
+ 'data_updated': [convert_from_extras,ignore_missing, date_to_form],
+ 'activity_period-from': [convert_from_extras,ignore_missing, date_to_form],
+ 'activity_period-to': [convert_from_extras,ignore_missing, date_to_form],
+ 'activity_count': [convert_from_extras,ignore_missing],
+ 'archive_file': [convert_from_extras,ignore_missing],
+ 'verified': [convert_from_extras,ignore_missing],
+ })
+
+ return schema
+
+ def _check_data_dict(self, data_dict):
+ return
+
+ # End hooks
+
+ def get_groups(self,available_only=False):
+
+ query = Authorizer().authorized_query(c.user, model.Group, model.Action.EDIT)
+ groups = set(query.all())
+
+ if available_only:
+ package = c.pkg
+ if package:
+ groups = groups - set(package.groups)
+
+ return [{'id':group.id,'name':group.name, 'title':group.title} for group in groups if group.state==model.State.ACTIVE]
+
+
+def convert_to_extras(key, data, errors, context):
+
+ extras = data.get(('extras',), [])
+ if not extras:
+ data[('extras',)] = extras
+
+ extras.append({'key': key[-1], 'value': data[key]})
+
+def convert_from_extras(key, data, errors, context):
+
+ for data_key, data_value in data.iteritems():
+ if (data_key[0] == 'extras'
+ and data_key[-1] == 'key'
+ and data_value == key[-1]):
+ data[key] = data[('extras', data_key[1], 'value')]
+
+def date_to_db(value, context):
+ try:
+ value = DateType.form_to_db(value)
+ except DateConvertError, e:
+ raise Invalid(str(e))
+ return value
+
+def date_to_form(value, context):
+ try:
+ value = DateType.db_to_form(value)
+ except DateConvertError, e:
+ raise Invalid(str(e))
+ return value
+
+def convert_to_comma_list(value, context):
+
+ return ', '.join(json.loads(value))
+
+def convert_from_comma_list(value, context):
+
+ return [x.strip() for x in value.split(',') if len(x)]
+
+def checkbox_value(value,context):
+
+ return 'yes' if not isinstance(value, Missing) else 'no'
+
+def integer(value,context):
+ try:
+ value = int(value)
+ except ValueError,e:
+ raise Invalid(str(e))
+ return value
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/plugin.py Mon Sep 12 16:48:18 2011 +0100
@@ -0,0 +1,51 @@
+import os
+
+from logging import getLogger
+
+from ckan.plugins import implements, SingletonPlugin
+from ckan.plugins import IRoutes
+from ckan.plugins import IConfigurer
+
+import ckanext.iati
+
+log = getLogger(__name__)
+
+def configure_template_directory(config, relative_path):
+ configure_served_directory(config, relative_path, 'extra_template_paths')
+
+def configure_public_directory(config, relative_path):
+ configure_served_directory(config, relative_path, 'extra_public_paths')
+
+def configure_served_directory(config, relative_path, config_var):
+ 'Configure serving of public/template directories.'
+ assert config_var in ('extra_template_paths', 'extra_public_paths')
+ this_dir = os.path.dirname(ckanext.iati.__file__)
+ absolute_path = os.path.join(this_dir, relative_path)
+ if absolute_path not in config.get(config_var, ''):
+ if config.get(config_var):
+ config[config_var] += ',' + absolute_path
+ else:
+ config[config_var] = absolute_path
+
+class IatiForms(SingletonPlugin):
+
+ implements(IRoutes)
+ implements(IConfigurer)
+
+ def before_map(self, map):
+ package_controller = 'ckanext.iati.controllers.package_iati:PackageIatiController'
+ group_controller = 'ckanext.iati.controllers.group_iati:GroupIatiController'
+
+ map.redirect('/package/new','/dataset/new')
+ map.redirect('/package/edit/{id}','/dataset/edit/{id}')
+ map.connect('/dataset/new', controller=package_controller, action='new')
+ map.connect('/dataset/edit/{id}', controller=package_controller, action='edit')
+
+ return map
+
+ def after_map(self, map):
+ return map
+
+ def update_config(self, config):
+ configure_template_directory(config, 'templates')
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/templates/package/form_iati.html Mon Sep 12 16:48:18 2011 +0100
@@ -0,0 +1,221 @@
+<form id="package-edit" class="package_create_form ckan" method="post"
+ py:attrs="{'class':'has-errors'} if errors else {}"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <div class="error-explanation" py:if="error_summary">
+ <h2>Errors in form</h2>
+ <p>The form contains invalid entries:</p>
+ <ul>
+ <li py:for="key, error in error_summary.items()">${"%s: %s" % (key, error)}</li>
+ </ul>
+ </div>
+
+ <fieldset>
+ <legend>Basic information </legend>
+ <dl>
+ <dt><label class="field_req" for="name">Name *</label></dt>
+ <dd><input id="name" maxlength="100" name="name" type="text" value="${data.get('name', '')}" /></dd>
+ <dd class="field_error" py:if="errors.get('name', '')">${errors.get('name', '')}</dd>
+ <dd class="instructions basic">A unique identifier for the activity record.</dd>
+ <dd class="instructions further">It should be broadly humanly readable, in the spirit of Semantic Web URIs. Only use an acronym if it is widely recognised. Renaming is possible but discouraged.</dd>
+ <dd class="hints">2+ characters, lowercase, using only 'a-z0-9' and '-_'</dd>
+ <script type="text/javascript">
+ //<![CDATA[
+ $(document).ready(function () { if (!$('#preview').length) {$("#name").focus(); } });
+ //]]>
+ </script>
+
+ <dt><label class="field_opt" for="title">Title </label></dt>
+ <dd><input id="title" name="title" type="text" value="${data.get('title', '')}" /></dd>
+ <dd class="field_error" py:if="errors.get('title', '')">${errors.get('title', '')}</dd>
+ <dd class="instructions basic">A short descriptive title for the data set.</dd>
+ <dd class="instructions further">It should not be a description though - save that for the Notes field. Do not give a trailing full stop.</dd>
+
+ <dt><label class="field_opt" for="author">Contact</label></dt>
+ <dd><input id="author" name="author" type="text" value="${data.get('author', '')}" /></dd>
+ <dd class="instructions basic">The name of the main contact, for enquiries about this particular dataset, using the e-mail address in the following field.</dd>
+
+ <dt><label class="field_opt" for="author_email">Contact e-mail</label></dt>
+ <dd><input id="author_email" name="author_email" type="text" value="${data.get('author_email', '')}" /></dd>
+
+ <dt><label class="field_opt" for="department">Department</label></dt>
+ <dd><input id="department" name="department" size="40" type="text" value="${data.get('department', '')}" /></dd>
+ </dl>
+ </fieldset>
+
+ <fieldset id="groups">
+ <legend>Publisher</legend>
+ <dl>
+ <py:for each="num, group in enumerate(data.get('groups', []))">
+ <?python
+ authorized_group = [group_authz for group_authz in c.groups_authz if group_authz['id'] == group['id']]
+ authorized_group = authorized_group[0] if authorized_group else None
+ ?>
+
+ <dt py:if="'id' in group">
+ <input type="${'checkbox' if authorized_group else 'hidden'}" name="groups__${num}__id" checked="checked" value="${group['id']}" />
+ <input type="hidden" name="groups__${num}__name" value="${group.get('name', authorized_group['name'] if authorized_group else '')}" />
+ </dt>
+ <dd py:if="'id' in group"><label for="groups__${num}__checked">${group.get('name', authorized_group['name'] if authorized_group else '')}</label></dd>
+ </py:for>
+
+ <dt>Publisher</dt>
+ <dd py:if="c.groups_available">
+ <select id="groups__${len(data.get('groups', []))}__id" name="groups__${len(data.get('groups', []))}__id">
+ <option value="" >(None)</option>
+ <py:for each="group in c.groups_available">
+ <option value="${group['id']}" >${group['title']}</option>
+ </py:for>
+ </select>
+ </dd>
+ <dd py:if="not c.groups_available">Cannot add any publisher.</dd>
+ </dl>
+
+ </fieldset>
+
+ <fieldset>
+ <legend>Details</legend>
+ <dl>
+ <dt><label class="field_opt" for="country">Recipient country</label></dt>
+ <dd>
+ <py:with vars="country = data.get('country','')">
+ <select id="country" name="country">
+ <py:for each="name,id in c.countries">
+ <option value="${id}" py:attrs="{'selected': 'selected' if country == id else None}">${name}</option>
+ </py:for>
+ </select>
+ </py:with>
+ </dd>
+
+ <dt><label class="field_opt" for="donors">Donors</label></dt>
+ <dd><input id="donors" name="donors" type="text" value="${data.get('donors', '')}" /></dd>
+ <dd class="instructions basic">Separate multiple entries using commas.</dd>
+
+ <dt><label class="field_opt" for="donors_type">Donor type</label></dt>
+ <dd><input id="donors_type" name="donors_type" type="text" value="${data.get('donors_type', '')}" /></dd>
+ <dd class="instructions basic">Separate multiple entries using commas.</dd>
+
+ <dt><label class="field_opt" for="donors_country">Donor country</label></dt>
+ <dd><input id="donors_country" name="donors_country" type="text" value="${data.get('donors_country', '')}" /></dd>
+ <dd class="instructions basic">Separate multiple entries using commas.</dd>
+
+ <dt><label class="field_opt" for="record_updated">Record updated</label></dt>
+ <dd><input id="record_updated" name="record_updated" size="40" type="text" value="${data.get('record_updated', '')}" /></dd>
+ <dd class="instructions basic">Acceptable formats: 'DD/MM/YYYY HH:MM', 'DD/MM/YYYY', 'MM/YYYY', 'YYYY'.</dd>
+
+ <dt><label class="field_opt" for="data_updated">Data updated</label></dt>
+ <dd><input id="data_updated" name="data_updated" size="40" type="text" value="${data.get('data_updated', '')}"/></dd>
+ <dd class="instructions basic">Acceptable formats: 'DD/MM/YYYY HH:MM', 'DD/MM/YYYY', 'MM/YYYY', 'YYYY'.</dd>
+
+ <dt><label class="field_opt" for="license_id">License</label></dt>
+ <dd>
+ <select id="license_id" name="license_id">
+ <py:for each="licence_desc, licence_id in c.licences">
+ <option value="${licence_id}" py:attrs="{'selected': 'selected' if data.get('license_id', '') == licence_id else None}" >${licence_desc}</option>
+ </py:for>
+ </select>
+ </dd>
+ <dd class="instructions basic">The licence under which the dataset is released.</dd>
+
+ <dt><label class="field_opt" for="tags">Tags</label></dt>
+ <dd>
+ <input class="autocomplete-tag" id="tag_string" name="tag_string" size="40" type="text"
+ value="${data.get('tag_string') or ' '.join([tag['name'] for tag in data.get('tags', [])])}" />
+ </dd>
+ <dd class="field_error" py:if="errors.get('tag_string', '')">${errors.get('tag_string', '')}</dd>
+ <dd class="instructions basic">Terms that may link this dataset to similar ones. For more information on conventions, see <a href="http://wiki.okfn.org/ckan/doc/faq#TagConventions">this wiki page</a>.</dd>
+ <dd class="hints">e.g. pollution rivers water-quality</dd>
+
+ <dt><label class="field_opt" for="notes">Notes</label></dt>
+ <dd><textarea cols="60" id="notes" name="notes" rows="15">${data.get('notes', '')}</textarea></dd>
+ <dd class="instructions basic">The main description of the dataset</dd>
+ <dd class="instructions further">It is often displayed with the record title. In particular, it should start with a short sentence that describes the data set succinctly, because the first few words alone may be used in some views of the data sets.</dd>
+ <dd class="hints">You can use <a href="http://daringfireball.net/projects/markdown/syntax">Markdown formatting</a> here.</dd>
+ </dl>
+ </fieldset>
+
+ <fieldset id="resources">
+ <legend>Resources</legend>
+ <table class="flexitable">
+ <thead>
+ <tr>
+ <th class="field_req resource-url">URL*</th>
+ <th class="field_opt resource-format">Format</th>
+ <th class="field_opt resource-description">Description</th>
+ <th class="field_opt resource-hash">Hash</th>
+ </tr>
+ </thead>
+ <tbody>
+ <py:for each="num, res in enumerate(data.get('resources', []) + [{}])">
+ <tr>
+ <py:for each="col in c.resource_columns">
+ <td py:choose="" class="resource-${col}">
+ <input py:when="col == 'format'" name="resources__${num}__${col}" type="text" value="${res.get(col, '')}" class="autocomplete-format short" />
+
+ <input py:otherwise="" name="resources__${num}__${col}" type="text" value="${res.get(col, '')}" class="${'medium-width' if col == 'url' else 'short'}" />
+ </td>
+ </py:for>
+ <td class="resource-id"><input name="resources__${num}__id" type="hidden" value="${res.get('id', '')}" /></td>
+ </tr>
+ </py:for>
+ </tbody>
+ </table>
+
+ <div class="instructions basic">The files containing the data or address of the APIs for accessing it.</div>
+ <div class="instructions further"><br /><b>URL:</b> This is the Internet link directly to the data - by selecting this link in a web browser, the user will immediately download the full dataset. Note that datasets are not hosted on this site, but by the publisher of the data.<br /><b>Format:</b> This should give the file format in which the data is supplied. (i.e. IATI-XML)<br /><b>Description</b> Any information you want to add to describe the resource.<br /></div>
+ <div class="field_error" py:if="errors.get('resources', '')">Dataset resource(s) incomplete.</div>
+ </fieldset>
+
+ <fieldset>
+ <legend>Verification and Analysis </legend>
+ <dl>
+ <dt><label class="field_opt" for="activity_period">Activitiy Period</label></dt>
+ <dd>
+ <input class="short" id="activity_period-from" name="activity_period-from" type="text" value="${data.get('activity_period-from', '')}" /> -
+ <input class="short" id="activity_period-to" name="activity_period-to" type="text" value="${data.get('activity_period-to', '')}" />
+ </dd>
+ <dd class="instructions basic">Acceptable formats: 'DD/MM/YYYY HH:MM', 'DD/MM/YYYY', 'MM/YYYY', 'YYYY'.</dd>
+
+ <dt><label class="field_opt" for="activity_count">Num. Activities</label></dt>
+ <dd><input id="activity_count" name="activity_count" size="40" type="text" value="${data.get('activity_count', '')}"/></dd>
+
+ <dt><label class="field_opt" for="archive_file">Archive</label></dt>
+ <dd><input id="archive_file" name="archive_file" size="40" type="checkbox" py:attrs="{'checked': 'checked' if data.get('archive_file','') == 'yes' else None}" /></dd>
+ <py:choose>
+ <py:when test="c.is_sysadmin">
+ <dt><label class="field_opt" for="verified">Verification</label></dt>
+ <dd><input id="verified" name="verified" size="40" type="checkbox" py:attrs="{'checked': 'checked' if data.get('verified','') == 'yes' else None}" /></dd>
+
+ <dt><label class="field_opt" for="state">State</label></dt>
+ <dd>
+ <select id="state" name="state">
+ <option py:attrs="{'selected': 'selected' if data.get('state') == 'active' else None}" value="active">active</option>
+ <option py:attrs="{'selected': 'selected' if data.get('state') == 'deleted' else None}" value="deleted">deleted</option>
+ <option py:attrs="{'selected': 'selected' if data.get('state') == 'pending' else None}" value="pending">pending</option>
+ </select>
+ </dd>
+ </py:when>
+ </py:choose>
+
+ </dl>
+ </fieldset>
+
+ <hr />
+ <label for="log_message">Edit summary (briefly describe the changes you have made)</label>
+ <textarea id="log_message" name="log_message" class="short wide"></textarea>
+
+ <div class="ckan-logged-in">
+ <p>Author: ${c.author}</p>
+ </div>
+
+ <div class="submit">
+ <input id="save" name="save" type="submit" value="Save" />
+ </div>
+ <p class="hints">
+ <strong>Important:</strong> By submitting content, you agree to release your contributions
+ under the open license specified on the <a href="/license">license page</a>. Please <strong>refrain</strong> from editing this page if you are <strong>not</strong> happy to do this.
+ </p>
+
+</form>
--- a/ckanext/iati/templates/package/read_core.html Thu Sep 01 13:59:28 2011 +0100
+++ b/ckanext/iati/templates/package/read_core.html Mon Sep 12 16:48:18 2011 +0100
@@ -34,7 +34,7 @@
<div class="notes" py:if="str(c.pkg_notes_formatted).strip()">
${c.pkg_notes_formatted}
</div>
-
+
<py:choose test=""><table py:when="c.pkg.resources" width="100%"><tr><th>URL</th><th>Format</th><th>Preview</th></tr>
@@ -50,7 +50,7 @@
</table><table py:otherwise=""><tr><th>Resources</th><td>None given for this package.</td></tr></table></py:choose>
-
+
<py:def function="details_item(label, value)"><tr py:if="value is not None and len(value) > 0"><td class="package-label">
@@ -61,18 +61,18 @@
</td></tr></py:def>
-
+
<py:def function="details_asbool(label, value)"><tr><td class="package-label">
${label}
</td><td class="package-details">
- ${'yes' if value else 'no'}
+ ${'yes' if value == 'yes' else 'no'}
</td></tr></py:def>
-
+
<py:def function="details_list(label, values)"><tr py:if="values is not None and len(values) > 0"><td class="package-label" valign="top">
@@ -95,14 +95,14 @@
${details_list('Donor types', c.pkg.extras.get('donors_type', []))}
${details_list('Donor countries', [h.country_name(x) for x in c.pkg.extras.get('donors_country', [])])}
${details_item('Recipient Country', h.country_name(c.pkg.extras.get('country', '(Unknown)')))}
-
+
${details_asbool('Verified', c.pkg.extras.get('verified', False))}
${details_asbool('Archive File', c.pkg.extras.get('archive_file', False))}
${details_item('Department', c.pkg.extras.get('department', '-'))}
-
+
${details_item('Data updated', c.pkg.extras.get('data_updated', '-'))}
${details_item('Record updated', c.pkg.extras.get('record_updated', '-'))}
-
+
<tr><td class="package-label">
License
@@ -122,14 +122,18 @@
</tr></tbody></table>
-
-
-
+
+
+
<h4>Contents</h4><table width="100%"><tbody>
- ${details_item('# of Activities', c.pkg.extras.get('activity_count', '-'))}
-
+ <tr>
+ <td class="package-label"># of Activities</td>
+ <td class="package-details">
+ ${c.pkg.extras.get('activity_count', '-')}</td>
+ </tr>
+
<tr><td class="package-label">Activity Period</td><td class="package-details">
--- a/setup.py Thu Sep 01 13:59:28 2011 +0100
+++ b/setup.py Mon Sep 12 16:48:18 2011 +0100
@@ -31,7 +31,8 @@
iati_approval = ckanext.iati.approval:IatiGroupApprovalExtension
iati_group_authz = ckanext.iati.authz:IatiGroupAuthzExtension
iati_package_authz = ckanext.iati.authz:IatiPackageAuthzExtension
-
+ iati_forms = ckanext.iati.plugin:IatiForms
+
[ckan.forms]
iati_package = ckanext.iati.forms:get_iati_package_fieldset
iati_group = ckanext.iati.forms:get_iati_group_fieldset
http://bitbucket.org/okfn/ckanextiati/changeset/816a476c85c2/
changeset: 816a476c85c2
branch: new-forms
user: amercader
date: 2011-09-13 12:08:00
summary: [new forms] Move converters to ckan core
affected #: 1 file (716 bytes)
--- a/ckanext/iati/controllers/package_iati.py Mon Sep 12 16:48:18 2011 +0100
+++ b/ckanext/iati/controllers/package_iati.py Tue Sep 13 11:08:00 2011 +0100
@@ -11,6 +11,7 @@
ignore,
keep_extras,
)
+from ckan.logic.converters import convert_from_extras, convert_to_extras, date_to_db, date_to_form
from ckan.lib.navl.dictization_functions import Missing, Invalid
from ckan.lib.field_types import DateType, DateConvertError
@@ -85,36 +86,6 @@
return [{'id':group.id,'name':group.name, 'title':group.title} for group in groups if group.state==model.State.ACTIVE]
-def convert_to_extras(key, data, errors, context):
-
- extras = data.get(('extras',), [])
- if not extras:
- data[('extras',)] = extras
-
- extras.append({'key': key[-1], 'value': data[key]})
-
-def convert_from_extras(key, data, errors, context):
-
- for data_key, data_value in data.iteritems():
- if (data_key[0] == 'extras'
- and data_key[-1] == 'key'
- and data_value == key[-1]):
- data[key] = data[('extras', data_key[1], 'value')]
-
-def date_to_db(value, context):
- try:
- value = DateType.form_to_db(value)
- except DateConvertError, e:
- raise Invalid(str(e))
- return value
-
-def date_to_form(value, context):
- try:
- value = DateType.db_to_form(value)
- except DateConvertError, e:
- raise Invalid(str(e))
- return value
-
def convert_to_comma_list(value, context):
return ', '.join(json.loads(value))
http://bitbucket.org/okfn/ckanextiati/changeset/b73e7df7b245/
changeset: b73e7df7b245
branch: new-forms
user: amercader
date: 2011-09-13 12:08:26
summary: [new forms] Minor adjustments in package form
affected #: 2 files (122 bytes)
--- a/ckanext/iati/controllers/package_iati.py Tue Sep 13 11:08:00 2011 +0100
+++ b/ckanext/iati/controllers/package_iati.py Tue Sep 13 11:08:26 2011 +0100
@@ -99,9 +99,11 @@
return 'yes' if not isinstance(value, Missing) else 'no'
def integer(value,context):
- try:
- value = int(value)
- except ValueError,e:
- raise Invalid(str(e))
- return value
+ if not value == '':
+ try:
+ value = int(value)
+ except ValueError,e:
+ raise Invalid(str(e))
+ return value
+
--- a/ckanext/iati/templates/package/form_iati.html Tue Sep 13 11:08:00 2011 +0100
+++ b/ckanext/iati/templates/package/form_iati.html Tue Sep 13 11:08:26 2011 +0100
@@ -64,7 +64,9 @@
<dt>Publisher</dt><dd py:if="c.groups_available"><select id="groups__${len(data.get('groups', []))}__id" name="groups__${len(data.get('groups', []))}__id">
- <option value="" >(None)</option>
+ <dd py:if="data.get('groups',[])">
+ <option value="" >(None)</option>
+ </dd><py:for each="group in c.groups_available"><option value="${group['id']}" >${group['title']}</option></py:for>
http://bitbucket.org/okfn/ckanextiati/changeset/b966e7deb66d/
changeset: b966e7deb66d
branch: new-forms
user: amercader
date: 2011-09-14 14:12:21
summary: [new forms] Change order of validators
affected #: 1 file (10 bytes)
--- a/ckanext/iati/controllers/package_iati.py Tue Sep 13 11:08:26 2011 +0100
+++ b/ckanext/iati/controllers/package_iati.py Wed Sep 14 13:12:21 2011 +0100
@@ -54,9 +54,9 @@
schema.update({
'department': [convert_from_extras,ignore_missing],
'country': [convert_from_extras, ignore_missing],
- 'donors': [convert_from_extras, convert_to_comma_list, ignore_missing],
- 'donors_type': [convert_from_extras, convert_to_comma_list, ignore_missing],
- 'donors_country': [convert_from_extras, convert_to_comma_list, ignore_missing],
+ 'donors': [ignore_missing, convert_from_extras, convert_to_comma_list],
+ 'donors_type': [ignore_missing, convert_from_extras, convert_to_comma_list],
+ 'donors_country': [ignore_missing, convert_from_extras, convert_to_comma_list],
'record_updated': [convert_from_extras,ignore_missing, date_to_form],
'data_updated': [convert_from_extras,ignore_missing, date_to_form],
'activity_period-from': [convert_from_extras,ignore_missing, date_to_form],
@@ -87,11 +87,11 @@
def convert_to_comma_list(value, context):
-
+
return ', '.join(json.loads(value))
def convert_from_comma_list(value, context):
-
+
return [x.strip() for x in value.split(',') if len(x)]
def checkbox_value(value,context):
http://bitbucket.org/okfn/ckanextiati/changeset/c2b5d5745b08/
changeset: c2b5d5745b08
branch: new-forms
user: amercader
date: 2011-09-14 14:27:10
summary: [new forms] Add new group form
affected #: 3 files (12.6 KB)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/controllers/group_iati.py Wed Sep 14 13:27:10 2011 +0100
@@ -0,0 +1,76 @@
+from ckan.lib.base import c
+from ckan import model
+
+from ckan.lib.navl.validators import ignore_missing, not_empty
+
+from ckan.logic.schema import group_form_schema
+from ckan.logic.converters import convert_from_extras, convert_to_extras
+from ckan.controllers.group import GroupController
+
+PUBLISHER_TYPES = ['Primary source', 'Secondary source']
+
+
+class GroupIatiController(GroupController):
+
+ group_form = 'group/form_iati.html'
+
+ def _setup_template_variables(self, context):
+
+ super(GroupIatiController,self)._setup_template_variables(context)
+
+ c.licences = [('', '')] + model.Package.get_license_options()
+
+ def _form_to_db_schema(self):
+ schema = group_form_schema()
+ schema.update({
+ 'type': [not_empty, publisher_type_validator, convert_to_extras],
+ 'license_id': [convert_to_extras],
+ 'publisher_segmentation': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_ui': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_frequency': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_thresholds': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_units': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_contact': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_agencies': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_field_exclusions': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_description': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_record_exclusions': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_timeliness': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_refs': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_constraints': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_data_quality': [unicode, convert_to_extras, ignore_missing],
+ })
+
+ return schema
+
+ def _db_to_form_schema(self):
+ schema = group_form_schema()
+ schema.update({
+ 'type': [convert_from_extras],
+ 'license_id': [convert_from_extras],
+ 'publisher_segmentation': [convert_from_extras],
+ 'publisher_ui': [convert_from_extras],
+ 'publisher_frequency': [convert_from_extras],
+ 'publisher_thresholds': [convert_from_extras],
+ 'publisher_units': [convert_from_extras],
+ 'publisher_contact': [convert_from_extras],
+ 'publisher_agencies': [convert_from_extras],
+ 'publisher_field_exclusions': [convert_from_extras],
+ 'publisher_description': [convert_from_extras],
+ 'publisher_record_exclusions': [convert_from_extras],
+ 'publisher_timeliness': [convert_from_extras],
+ 'publisher_refs': [convert_from_extras],
+ 'publisher_constraints': [convert_from_extras],
+ 'publisher_data_quality': [convert_from_extras],
+ })
+
+ return schema
+
+ def _check_data_dict(self, data_dict):
+ return
+
+
+def publisher_type_validator(value,context):
+ if not value in PUBLISHER_TYPES:
+ raise Invalid('Unknown publisher type, allowed values: [%s]' % ', '.join(PUBLISHER_TYPES))
+ return value
--- a/ckanext/iati/plugin.py Wed Sep 14 13:12:21 2011 +0100
+++ b/ckanext/iati/plugin.py Wed Sep 14 13:27:10 2011 +0100
@@ -41,6 +41,9 @@
map.connect('/dataset/new', controller=package_controller, action='new')
map.connect('/dataset/edit/{id}', controller=package_controller, action='edit')
+ map.connect('/group/new', controller=group_controller, action='new')
+ map.connect('/group/edit/{id}', controller=group_controller, action='edit')
+
return map
def after_map(self, map):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/templates/group/form_iati.html Wed Sep 14 13:27:10 2011 +0100
@@ -0,0 +1,151 @@
+<form id="group-edit" action="" method="post"
+ py:attrs="{'class':'has-errors'} if errors else {}"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <div class="error-explanation" py:if="error_summary">
+ <h2>Errors in form</h2>
+ <p>The form contains invalid entries:</p>
+ <ul>
+ <li py:for="key, error in error_summary.items()">${"%s: %s" % (key, error)}</li>
+ </ul>
+ </div>
+
+ <fieldset>
+ <legend>Basic information</legend>
+ <dl>
+ <dt><label class="field_req" for="name">Unique Name (required) *</label></dt>
+ <dd><input id="name" name="name" type="text" value="${data.get('name', '')}" /></dd>
+ <dd class="field_error" py:if="errors.get('name', '')">${errors.get('name', '')}</dd>
+ <dd class="instructions basic"><strong>Unique identifier</strong> for group.<br/>2+ chars, lowercase, using only 'a-z0-9' and '-_'</dd>
+ <script type="text/javascript">
+ //<![CDATA[
+ $(document).ready(function () { if (!$('#preview').length) { $("#name").focus();}});
+ //]]>
+ </script>
+
+ <dt><label class="field_opt" for="title">Title</label></dt>
+ <dd><input id="title" name="title" type="text" value="${data.get('title', '')}" /></dd>
+ <dd class="field_error" py:if="errors.get('title', '')">${errors.get('title', '')}</dd>
+
+ <dt><label class="field_req" for="type">Source</label></dt>
+ <dd>
+ <select id="type" name="type">
+ <option value="Primary source" py:attrs="{'selected': 'selected' if data.get('type', '') == 'Primary source' else None}">Primary source</option>
+ <option value="Secondary source" py:attrs="{'selected': 'selected' if data.get('type', '') == 'Secondary source' else None}">Secondary source</option>
+ </select>
+ </dd>
+
+ <dt><label class="field_opt" for="license_id">License</label></dt>
+ <dd>
+ <select id="license_id" name="license_id">
+ <py:for each="licence_desc, licence_id in c.licences">
+ <option value="${licence_id}" py:attrs="{'selected': 'selected' if data.get('license_id', '') == licence_id else None}" >${licence_desc}</option>
+ </py:for>
+
+ </select>
+ </dd>
+
+ <py:choose>
+ <py:when test="c.is_sysadmin">
+ <dt><label class="field_opt" for="state">State</label></dt>
+ <dd>
+ <select id="state" name="state">
+ <option py:attrs="{'selected': 'selected' if data.get('state') == 'active' else None}" value="active">active</option>
+ <option py:attrs="{'selected': 'selected' if data.get('state') == 'deleted' else None}" value="deleted">deleted</option>
+ <option py:attrs="{'selected': 'selected' if data.get('state') == 'pending' else None}" value="pending">pending</option>
+ </select>
+ </dd>
+ </py:when>
+ </py:choose>
+
+ </dl>
+ </fieldset>
+
+ <fieldset>
+ <legend>Details</legend>
+ <dl>
+
+ <dt><label class="field_opt" for="publisher_contact">Contact</label></dt>
+ <dd><textarea id="publisher_contact" name="publisher_contact">${data.get('publisher_contact', '')}</textarea></dd>
+ <dd class="instructions basic">Contact details for publisher</dd>
+
+ <dt><label class="field_opt" for="publisher_description">Description</label></dt>
+ <dd><textarea id="publisher_description" name="publisher_description">${data.get('publisher_description', '')}</textarea></dd>
+ <dd class="instructions basic">General description of publisher's role and activities</dd>
+
+ <dt><label class="field_opt" for="publisher_agencies">Organisations / agencies covered</label></dt>
+ <dd><textarea id="publisher_agencies" name="publisher_agencies">${data.get('publisher_agencies', '')}</textarea></dd>
+ <dd class="instructions basic">Whose activities does this publisher publish?</dd>
+
+ <dt><label class="field_opt" for="publisher_timeliness">Timeliness of Data</label></dt>
+ <dd><textarea id="publisher_timeliness" name="publisher_timeliness">${data.get('publisher_timeliness','')}</textarea></dd>
+ <dd class="instructions basic">How up do date is the data when published?</dd>
+
+ <dt><label class="field_opt" for="publisher_frequency">Frequency of publication</label></dt>
+ <dd><textarea id="publisher_frequency" name="publisher_frequency">${data.get('publisher_frequency','')}</textarea></dd>
+ <dd class="instructions basic">How often is IATI data refreshed? Monthly/Quarterly?</dd>
+
+ <dt><label class="field_opt" for="publisher_units">Units of Aid</label></dt>
+ <dd><textarea id="publisher_units" name="publisher_units">${data.get('publisher_units','')}</textarea></dd>
+ <dd class="instructions basic">A description of any hierarchical reporting units used and how they are applied</dd>
+
+ <dt><label class="field_opt" for="publisher_segmentation">Segmentation of Published Data</label></dt>
+ <dd><textarea id="publisher_segmentation" name="publisher_segmentation">${data.get('publisher_segmentation','')}</textarea></dd>
+ <dd class="instructions basic">Is IATI data published by country, regions?</dd>
+
+ <dt><label class="field_opt" for="publisher_refs">Data Definitions and References</label></dt>
+ <dd><textarea id="publisher_refs" name="publisher_refs">${data.get('publisher_refs','')}</textarea></dd>
+ <dd class="instructions basic">Links to guides, explanations, codelists on the publisher's own site that clarify their data</dd>
+
+ <dt><label class="field_opt" for="publisher_field_exclusions">Field Exclusions</label></dt>
+ <dd><textarea id="publisher_field_exclusions" name="publisher_field_exclusions">${data.get('publisher_field_exclusions','')}</textarea></dd>
+ <dd class="instructions basic">What fields does the publisher never use - and for what reason</dd>
+
+ <dt><label class="field_opt" for="publisher_record_exclusions">Record Exclusions</label></dt>
+ <dd><textarea id="publisher_record_exclusions" name="publisher_record_exclusions">${data.get('publisher_record_exclusions','')}</textarea></dd>
+ <dd class="instructions basic">What are the policies for excluding particular activities, or parts of an activity's data?</dd>
+
+ <dt><label class="field_opt" for="publisher_thresholds">Thresholds</label></dt>
+ <dd><textarea id="publisher_thresholds" name="publisher_thresholds">${data.get('publisher_thresholds','')}</textarea></dd>
+ <dd class="instructions basic">What are the thresholds below which data or whole activities are not published?</dd>
+
+ <dt><label class="field_opt" for="publisher_constraints">Other Constraints</label></dt>
+ <dd><textarea id="publisher_constraints" name="publisher_constraints">${data.get('publisher_constraints','')}</textarea></dd>
+ <dd class="instructions basic">Other policies that restrict full compliance with the standard</dd>
+
+ <dt><label class="field_opt" for="publisher_data_quality">Data Quality</label></dt>
+ <dd><textarea id="publisher_data_quality" name="publisher_data_quality">${data.get('publisher_data_quality','')}</textarea></dd>
+ <dd class="instructions basic">Publisher's comment on the status and accuracyof the data - audited/verified, operational/sub to change, etc</dd>
+
+ <dt><label class="field_opt" for="publisher_ui">User Interface</label></dt>
+ <dd><textarea id="publisher_ui" name="publisher_ui">${data.get('publisher_ui','')}</textarea></dd>
+ <dd class="instructions basic">Link to publisher's own public user activity interface</dd>
+ </dl>
+ </fieldset>
+
+ <fieldset>
+ <legend>Records</legend>
+ <dl py:if="data.get('packages')">
+ <py:for each="num, package in enumerate(data.get('packages'))">
+ <dt><input checked="checked" id="datasets__${num}__name" name="packages__${num}__name" type="checkbox" value="${package['name']}"/></dt>
+ <dd><label for="packages__${num}__name">${package['name']}</label></dd>
+ </py:for>
+ </dl>
+ <p py:if="not data.get('packages')">There are no records currently in this group.</p>
+ </fieldset>
+
+ <fieldset>
+ <legend>Add records</legend>
+ <dl>
+ <dt><label class="field_opt" for="packages__${len(data.get('packages', []))}__name">Dataset</label></dt>
+ <dd><input class="autocomplete-dataset" id="datasets__${len(data.get('packages', []))}__name" name="packages__${len(data.get('packages', []))}__name" type="text" /></dd>
+ </dl>
+ </fieldset>
+
+ <div class="submit">
+ <input id="save" name="save" type="submit" value="Save" />
+ </div>
+
+</form>
http://bitbucket.org/okfn/ckanextiati/changeset/54b195a61bab/
changeset: 54b195a61bab
branch: new-forms
user: amercader
date: 2011-09-14 14:52:49
summary: [new forms] Remove old forms
affected #: 6 files (12 bytes)
--- a/ckanext/iati/forms/__init__.py Wed Sep 14 13:27:10 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-
-from package import get_package_fieldset as get_iati_package_fieldset
-from group import get_group_fieldset as get_iati_group_fieldset
--- a/ckanext/iati/forms/countries.py Wed Sep 14 13:27:10 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-# -*- coding: UTF-8 -*-
-
-# This Python file uses the following encoding: utf-8
-# Country and regions names and codes sent by Bill Anderson on 2011-06-28
-
-COUNTRIES = (("", u"(No country assigned)"), ("AF",u"Afghanistan"),("AX",u"Ã
land Islands"),("AL",u"Albania"),("DZ",u"Algeria"),("AS",u"American Samoa"),("AD",u"Andorra"),("AO",u"Angola"),("AI",u"Anguilla"),("AQ",u"Antarctica"),("AG",u"Antigua And Barbuda"),("AR",u"Argentina"),("AM",u"Armenia"),("AW",u"Aruba"),("AU",u"Australia"),("AT",u"Austria"),("AZ",u"Azerbaijan"),("BS",u"Bahamas"),("BH",u"Bahrain"),("BD",u"Bangladesh"),("BB",u"Barbados"),("BY",u"Belarus"),("BE",u"Belgium"),("BZ",u"Belize"),("BJ",u"Benin"),("BM",u"Bermuda"),("BT",u"Bhutan"),("BO",u"Bolivia, Plurinational State Of"),("BQ",u"Bonaire, Sint Eustatius And Saba"),("BA",u"Bosnia And Herzegovina"),("BW",u"Botswana"),("BV",u"Bouvet Island"),("BR",u"Brazil"),("IO",u"British Indian Ocean Territory"),("BN",u"Brunei Darussalam"),("BG",u"Bulgaria"),("BF",u"Burkina Faso"),("BI",u"Burundi"),("KH",u"Cambodia"),("CM",u"Cameroon"),("CA",u"Canada"),("CV",u"Cape Verde"),("KY",u"Cayman Islands"),("CF",u"Central African Republic"),("TD",u"Chad"),("CL",u"Chile"),("CN",u"China"),("CX",u"Christmas Island"),("CC",u"Cocos (Keeling) Islands"),("CO",u"Colombia"),("KM",u"Comoros"),("CG",u"Congo"),("CD",u"Congo, The Democratic Republic Of The"),("CK",u"Cook Islands"),("CR",u"Costa Rica"),("CI",u"Côte D'Ivoire"),("HR",u"Croatia"),("CU",u"Cuba"),("CW",u"Curaçao"),("CY",u"Cyprus"),("CZ",u"Czech Republic"),("DK",u"Denmark"),("DJ",u"Djibouti"),("DM",u"Dominica"),("DO",u"Dominican Republic"),("EC",u"Ecuador"),("EG",u"Egypt"),("SV",u"El Salvador"),("GQ",u"Equatorial Guinea"),("ER",u"Eritrea"),("EE",u"Estonia"),("ET",u"Ethiopia"),("FK",u"Falkland Islands (Malvinas)"),("FO",u"Faroe Islands"),("FJ",u"Fiji"),("FI",u"Finland"),("FR",u"France"),("GF",u"French Guiana"),("PF",u"French Polynesia"),("TF",u"French Southern Territories"),("GA",u"Gabon"),("GM",u"Gambia"),("GE",u"Georgia"),("DE",u"Germany"),("GH",u"Ghana"),("GI",u"Gibraltar"),("GR",u"Greece"),("GL",u"Greenland"),("GD",u"Grenada"),("GP",u"Guadeloupe"),("GU",u"Guam"),("GT",u"Guatemala"),("GG",u"Guernsey"),("GN",u"Guinea"),("GW",u"Guinea-Bissau"),("GY",u"Guyana"),("HT",u"Haiti"),("HM",u"Heard Island And Mcdonald Islands"),("VA",u"Holy See (Vatican City State)"),("HN",u"Honduras"),("HK",u"Hong Kong"),("HU",u"Hungary"),("IS",u"Iceland"),("IN",u"India"),("ID",u"Indonesia"),("IR",u"Iran, Islamic Republic Of"),("IQ",u"Iraq"),("IE",u"Ireland"),("IM",u"Isle Of Man"),("IL",u"Israel"),("IT",u"Italy"),("JM",u"Jamaica"),("JP",u"Japan"),("JE",u"Jersey"),("JO",u"Jordan"),("KZ",u"Kazakhstan"),("KE",u"Kenya"),("KI",u"Kiribati"),("KP",u"Korea, Democratic People's Republic Of"),("KR",u"Korea, Republic Of"),("XK",u"Kosovo"),("KW",u"Kuwait"),("KG",u"Kyrgyzstan"),("LA",u"Lao People's Democratic Republic"),("LV",u"Latvia"),("LB",u"Lebanon"),("LS",u"Lesotho"),("LR",u"Liberia"),("LY",u"Libyan Arab Jamahiriya"),("LI",u"Liechtenstein"),("LT",u"Lithuania"),("LU",u"Luxembourg"),("MO",u"Macao"),("MK",u"Macedonia, The Former Yugoslav Republic Of"),("MG",u"Madagascar"),("MW",u"Malawi"),("MY",u"Malaysia"),("MV",u"Maldives"),("ML",u"Mali"),("MT",u"Malta"),("MH",u"Marshall Islands"),("MQ",u"Martinique"),("MR",u"Mauritania"),("MU",u"Mauritius"),("YT",u"Mayotte"),("MX",u"Mexico"),("FM",u"Micronesia, Federated States Of"),("MD",u"Moldova, Republic Of"),("MC",u"Monaco"),("MN",u"Mongolia"),("ME",u"Montenegro"),("MS",u"Montserrat"),("MA",u"Morocco"),("MZ",u"Mozambique"),("MM",u"Myanmar"),("NA",u"Namibia"),("NR",u"Nauru"),("NP",u"Nepal"),("NL",u"Netherlands"),("NC",u"New Caledonia"),("NZ",u"New Zealand"),("NI",u"Nicaragua"),("NE",u"Niger"),("NG",u"Nigeria"),("NU",u"Niue"),("NF",u"Norfolk Island"),("MP",u"Northern Mariana Islands"),("NO",u"Norway"),("OM",u"Oman"),("PK",u"Pakistan"),("PW",u"Palau"),("PS",u"Palestinian Territory, Occupied"),("PA",u"Panama"),("PG",u"Papua New Guinea"),("PY",u"Paraguay"),("PE",u"Peru"),("PH",u"Philippines"),("PN",u"Pitcairn"),("PL",u"Poland"),("PT",u"Portugal"),("PR",u"Puerto Rico"),("QA",u"Qatar"),("RE",u"Réunion"),("RO",u"Romania"),("RU",u"Russian Federation"),("RW",u"Rwanda"),("BL",u"Saint Barthélemy"),("SH",u"Saint Helena, Ascension And Tristan Da Cunha"),("KN",u"Saint Kitts And Nevis"),("LC",u"Saint Lucia"),("MF",u"Saint Martin (French Part)"),("PM",u"Saint Pierre And Miquelon"),("VC",u"Saint Vincent And The Grenadines"),("WS",u"Samoa"),("SM",u"San Marino"),("ST",u"Sao Tome And Principe"),("SA",u"Saudi Arabia"),("SN",u"Senegal"),("RS",u"Serbia"),("SC",u"Seychelles"),("SL",u"Sierra Leone"),("SG",u"Singapore"),("SX",u"Sint Maarten (Dutch Part)"),("SK",u"Slovakia"),("SI",u"Slovenia"),("SB",u"Solomon Islands"),("SO",u"Somalia"),("ZA",u"South Africa"),("GS",u"South Georgia And The South Sandwich Islands"),("ES",u"Spain"),("LK",u"Sri Lanka"),("SD",u"Sudan"),("SR",u"Suriname"),("SJ",u"Svalbard And Jan Mayen"),("SZ",u"Swaziland"),("SE",u"Sweden"),("CH",u"Switzerland"),("SY",u"Syrian Arab Republic"),("TW",u"Taiwan, Province Of China"),("TJ",u"Tajikistan"),("TZ",u"Tanzania, United Republic Of"),("TH",u"Thailand"),("TL",u"Timor-Leste"),("TG",u"Togo"),("TK",u"Tokelau"),("TO",u"Tonga"),("TT",u"Trinidad And Tobago"),("TN",u"Tunisia"),("TR",u"Turkey"),("TM",u"Turkmenistan"),("TC",u"Turks And Caicos Islands"),("TV",u"Tuvalu"),("UG",u"Uganda"),("UA",u"Ukraine"),("AE",u"United Arab Emirates"),("GB",u"United Kingdom"),("US",u"United States"),("UM",u"United States Minor Outlying Islands"),("UY",u"Uruguay"),("UZ",u"Uzbekistan"),("VU",u"Vanuatu"),("VE",u"Venezuela, Bolivarian Republic Of"),("VN",u"Viet Nam"),("VG",u"Virgin Islands, British"),("VI",u"Virgin Islands, U.S."),("WF",u"Wallis And Futuna"),("EH",u"Western Sahara"),("YE",u"Yemen"),("ZM",u"Zambia"),("ZW",u"Zimbabwe"),("298",u"Africa"),("189",u"Africa - North"),("289",u"Africa - Sub-Saharan"),("089",u"Europe"),("498",u"America"),("389",u"America - North & Central"),("489",u"America - South"),("380",u"West Indies"),("589",u"Middle East"),("798",u"Asia"),("619",u"Asia - Central"),("679",u"Asia - South"),("689",u"Asia - South & Central"),("789",u"Asia - Far East"),("889",u"Oceania"),("998",u"Unspecified"),)
--- a/ckanext/iati/forms/group.py Wed Sep 14 13:27:10 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-import formalchemy
-from formalchemy import helpers as fa_h
-import ckan.lib.helpers as h
-
-from ckan.forms.builder import FormBuilder
-from sqlalchemy.util import OrderedDict
-from pylons.i18n import _, ungettext, N_, gettext
-import ckan.model as model
-import ckan.forms.common as common
-import ckan.forms.group as group
-from ckan.forms.common import ExtrasField, PackageNameField, SelectExtraField
-from ckan.forms.common import TextAreaExtraField
-from ckan.lib.helpers import literal
-
-from group_schema import fields
-
-
-__all__ = ['get_group_dict', 'edit_group_dict']
-
-
-def build_group_form(is_admin=False, with_packages=False):
- PUBLISHER_TYPES = [_("Primary source"),
- _("Secondary source")
- ]
- publisher_record_fields = fields
- builder = FormBuilder(model.Group)
- builder.set_field_text('name', 'Unique Name (required)',
- literal("<br/><strong>Unique identifier</strong> for group.<br/>2+ chars, lowercase, using only 'a-z0-9' and '-_'"))
- builder.set_field_option('name', 'validate', common.group_name_validator)
- builder.set_field_option('state', 'dropdown', {'options': model.State.all})
- builder.add_field(SelectExtraField('type',
- options=PUBLISHER_TYPES,
- allow_empty=False))
- builder.set_field_text('type', 'Source')
-
- builder.add_field(SelectExtraField('license_id',
- options=[('', None)] + model.Package.get_license_options()))
- builder.set_field_text('license_id', _('License'))
-
- for name, title, description in publisher_record_fields:
- builder.add_field(TextAreaExtraField(name))
- builder.set_field_text(name, title, description)
- displayed_fields = ['name', 'title', 'type', 'license_id'] +\
- [x[0] for x in publisher_record_fields]
- from ckan.authz import Authorizer
- from ckan.lib.base import c
- if Authorizer.is_sysadmin(c.user):
- displayed_fields.append('state')
-
- if with_packages:
- builder.add_field(group.PackagesField('packages'))
- displayed_fields.append('packages')
- builder.set_displayed_fields(OrderedDict([('Details', displayed_fields)]))
- builder.set_label_prettifier(common.prettify)
- return builder
-
-
-def get_group_fieldset(is_admin=False, combined=False):
- return build_group_form(is_admin=is_admin,
- with_packages=combined).get_fieldset()
-
--- a/ckanext/iati/forms/group_schema.py Wed Sep 14 13:27:10 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-fields = (('publisher_contact',
- 'Contact',
- 'Email or URL for publisher'),
- ('publisher_description',
- 'Description',
- "General description of Publisher's role and activities"),
- ('publisher_agencies',
- 'Organisations / agencies covered',
- 'Whose activities does this publisher publish?'),
- ('publisher_timeliness',
- 'Timeliness of Data',
- 'How up do date is the data when published?'),
- ('publisher_frequency',
- 'Frequency of publication',
- 'How often is IATI data refreshed? Monthly/Quarterly?'),
- ('publisher_units',
- 'Units of Aid',
- 'A description of any hierarchical reporting units used and how they are applied'),
- ('publisher_segmentation',
- 'Segmentation of Published Data',
- 'Is IATI data published by country, regions?'),
- ('publisher_refs',
- 'Data Definitions and References',
- "Links to guides, explanations, codelists on the publisher's own site that clarify their data"),
- ('publisher_field_exclusions',
- 'Field Exclusions',
- 'What fields does the publisher never use - and for what reason'),
- ('publisher_record_exclusions',
- 'Record Exclusions',
- "What are the policies for excluding particular activities, or parts of an activity's data?"),
- ('publisher_thresholds',
- 'Thresholds',
- 'What are the thresholds below which data or whole activities are not published?'),
- ('publisher_constraints',
- 'Other Constraints',
- 'Other policies that restrict full compliance with the standard'),
- ('publisher_data_quality',
- 'Data Quality',
- "Publisher's comment on the status and accuracyof the data - audited/verified, operational/sub to change, etc"),
- ('publisher_ui',
- 'User Interface',
- "Link to publisher's own public user activity interface"),
- )
-publisher_record_fields = fields
--- a/ckanext/iati/forms/package.py Wed Sep 14 13:27:10 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,226 +0,0 @@
-import formalchemy
-from formalchemy import helpers as h
-from sqlalchemy.util import OrderedDict
-from pylons.i18n import _, ungettext, N_, gettext
-
-from ckan.lib.helpers import literal
-import ckan.forms.common as common
-from ckan.forms.common import fa_h, TextExtraField, RegExRangeValidatingField, GroupSelectField
-import ckan.model as model
-import ckan.forms.package as package
-from ckan.lib import field_types
-
-from countries import COUNTRIES
-
-__all__ = ['get_iati_fieldset']
-
-class CommaListExtraField(RegExRangeValidatingField):
- '''A form field for two TextType fields, representing a range,
- stored in 'extra' fields.'''
- def get_configured(self):
- field = self.CommaListField(self.name).with_renderer(self.CommaListRenderer)
- return RegExRangeValidatingField.get_configured(self, field)
-
- class CommaListField(formalchemy.Field):
- def sync(self):
- if not self.is_readonly():
- pkg = self.model
- vals = self._deserialize() or []
- #vals = [v.strip()for v in vals.split(',') if len(v.strip())]
- pkg.extras[self.name] = vals
-
- class CommaListRenderer(formalchemy.fields.FieldRenderer):
- def _get_value(self):
- if self.value:
- return self.value
- extras = self.field.parent.model.extras
- return extras.get(self.field.name, [])
-
- def render(self, **kwargs):
- values = self._get_value()
- html = fa_h.text_field(self.name, value=', '.join(values), **kwargs)
- return html
-
- def render_readonly(self, **kwargs):
- val = ', '.join(self._get_value())
- return field_readonly_renderer(self.field.key, val_str)
-
- def _serialized_value(self):
- param_val = self.params.get(self.name, u'')
- return [v.strip()for v in param_val.split(',') if len(v.strip())]
-
- def deserialize(self):
- return self._serialized_value()
-
-
-class SelectExtraField(TextExtraField):
- '''A form field for text from from a list of options, that is
- stored in an "extras" field.'''
- def __init__(self, name, options):
- self.options = options[:]
- # ensure options have key and value, not just a value
- for i, option in enumerate(self.options):
- if not isinstance(option, (tuple, list)):
- self.options[i] = (option, option)
- super(SelectExtraField, self).__init__(name)
-
- def get_configured(self):
- return self.TextExtraField(self.name, options=self.options).with_renderer(self.SelectRenderer)
-
- class SelectRenderer(formalchemy.fields.FieldRenderer):
- def _get_value(self, **kwargs):
- extras = self.field.parent.model.extras
- return unicode(kwargs.get('selected', '') or self.value or extras.get(self.field.name, ''))
-
- def render(self, options, **kwargs):
- selected = self._get_value()
- options = [('', '')] + options
- option_keys = [key for value, key in options]
- if selected in option_keys:
- select_field_selected = selected
- else:
- select_field_selected = u''
- fa_version_nums = formalchemy.__version__.split('.')
- # Requires FA 1.3.2 onwards for this select i/f
- html = literal(fa_h.select(self.name, select_field_selected, options, **kwargs))
-
- return html
-
- def render_readonly(self, **kwargs):
- return field_readonly_renderer(self.field.key, self._get_value())
-
- def _serialized_value(self):
- main_value = self.params.get(self.name, u'')
- return main_value
-
-class AtLeastOneGroupSelectField(GroupSelectField):
-
- def get_configured(self):
- field = self.GroupSelectionField(self.name, self.allow_empty).with_renderer(self.GroupSelectEditRenderer)
- field.set(multiple=self.multiple)
- field = field.validate(self.validate_groups)
- field.user_editable_groups = self.user_editable_groups
- return field
-
- def validate_groups(self, val, field):
- if len(val) < 1:
- raise formalchemy.ValidationError(_("Need at least one publishing entity assigned"))
-
-
-# Setup the fieldset
-def build_package_iati_form(is_admin=False, user_editable_groups=None, **kwargs):
- builder = package.build_package_form(is_admin=is_admin,
- user_editable_groups=user_editable_groups, **kwargs)
-
- # IATI specifics
-
- #Publishing Entity:
- builder.set_field_text('groups', _('Publisher'))
- builder.add_field(AtLeastOneGroupSelectField('groups', allow_empty=False,
- user_editable_groups=user_editable_groups))
-
- #builder.add_field(common.TextExtraField('publisher'))
- #builder.set_field_text('publisher', _('Publishing entity'))
-
- #Publishing Entity Type: (Donor, Recipient, Community Data..)
- #builder.add_field(SelectExtraField('publisher_type', options=PUBLISHER_TYPES))
- #builder.set_field_text('publisher_type', _('Publishing entity type'))
-
- #Donor (TODO: Generate from crawler)
- # Editable List, CSV?
- builder.add_field(CommaListExtraField('donors'))
- builder.set_field_text('donors', _('Donors'), "Separate multiple entries using commas.")
-
- builder.add_field(CommaListExtraField('donors_type'))
- builder.set_field_text('donors_type', _('Donor type'), "Separate multiple entries using commas.")
-
- builder.add_field(CommaListExtraField('donors_country'))
- builder.set_field_text('donors_country', _('Donor country'), "Separate multiple entries using commas.")
-
- # TODO: Enforce validation
- countries = [(v, k) for k, v in COUNTRIES]
- builder.add_field(SelectExtraField('country', options=countries))
- builder.set_field_text('country', _('Recipient country'))
-
- #Verification status: enumeration of statuses (checked, not checked etc)
- # TODO: Enforce validation, can probably only be set by admins
- builder.add_field(common.CheckboxExtraField('verified'))
- builder.set_field_text('verified', _('Verification'))
-
- builder.add_field(common.CheckboxExtraField('archive_file'))
- builder.set_field_text('archive_file', _('Archive'))
-
- #Activity period: (Generate from crawler)
- builder.add_field(common.DateRangeExtraField('activity_period'))
- builder.set_field_text('activity_period', _('Activitiy Period'))
-
- #Resource links: to the actual IATI record
- #Number of activities: (Generate from crawler)
- builder.add_field(common.TextExtraField('activity_count'))
- builder.set_field_text('activity_count', _('Num. Activities'))
-
- #Date record updated:
- builder.add_field(common.TextExtraField('record_updated'))
- builder.set_field_text('record_updated', _('Record updated'))
-
- #Date data updated:
- builder.add_field(common.TextExtraField('data_updated'))
- builder.set_field_text('data_updated', _('Data updated'))
-
-
- #License: Need this field even if it may be a standard license
- builder.add_field(common.TextExtraField('license'))
- builder.set_field_text('license', _('License'))
-
- #Department
- # TODO: Make this a group property instead?
- builder.add_field(common.TextExtraField('department'))
- builder.set_field_text('department', _('Department'))
-
- #Contact
- builder.set_field_text('author', _('Contact'))
-
- #Contact e-mail
- builder.set_field_text('author_email', _('Contact e-mail'))
-
- #Licence
- builder.set_field_text('license_id', _('License'))
-
- #Resource format
- #Resource URL
- #Resource ID
- # -- do we have an ID?
-
- # Layout
- field_groups = OrderedDict([
- (_('Basic information'), ['name', 'title',
- 'author', 'author_email', 'department',]),
- (_('Publisher'), ['groups']),
- (_('Details'), ['country', 'donors', 'donors_type', 'donors_country',
- 'record_updated', 'data_updated',
- 'license_id', 'tags', 'notes']),
- (_('Resources'), ['resources']),
- (_('Verification and Analysis'), [
- 'activity_period',
- 'activity_count', 'archive_file',
- ]),
- ])
- if is_admin:
- field_groups[_('Verification and Analysis')].append('verified')
- field_groups[_('Verification and Analysis')].append('state')
-
- builder.set_displayed_fields(field_groups)
-
- return builder
- # Strings for i18n:
- [_('External reference'), _('Date released'), _('Date updated'),
- _('Update frequency'), _('Geographic granularity'),
- _('Geographic coverage'), _('Temporal granularity'),
- _('Temporal coverage'), _('Categories'), _('National Statistic'),
- _('Precision'), _('Taxonomy URL'), _('Department'), _('Agency'),
- ]
-
-def get_package_fieldset(is_admin=False, user_editable_groups=None, **kwargs):
- return build_package_iati_form(is_admin=is_admin,
- user_editable_groups=user_editable_groups, **kwargs).get_fieldset()
-
--- a/ckanext/iati/patch.py Wed Sep 14 13:27:10 2011 +0100
+++ b/ckanext/iati/patch.py Wed Sep 14 13:52:49 2011 +0100
@@ -1,13 +1,13 @@
import logging
import re
-from forms.countries import COUNTRIES
+from controllers.countries import COUNTRIES
import ckan.lib.helpers as h
import ckan.authz as authz
from ckan.lib.base import *
from ckan.model import Package
-from ckanext.iati.forms.group_schema import fields
+from ckanext.iati.controllers.group_schema import fields
log = logging.getLogger(__name__)
http://bitbucket.org/okfn/ckanextiati/changeset/ab4c12e22ceb/
changeset: ab4c12e22ceb
branch: new-forms
user: amercader
date: 2011-09-14 16:42:33
summary: Update i18n
affected #: 1 file (5 bytes)
--- a/i18n/en/ckan.po Wed Sep 14 13:52:49 2011 +0100
+++ b/i18n/en/ckan.po Wed Sep 14 15:42:33 2011 +0100
@@ -930,7 +930,7 @@
#: ckan/templates/layout_base.html:99
#: ckan/templates/package/search.html:14
-msgid "Add a package"
+msgid "Add a Dataset"
msgstr "Add a record"
#: ckan/templates/layout_base.html:101
@@ -1186,7 +1186,7 @@
msgstr "Publishers History"
#: ckan/templates/group/index.html:6
-msgid "Groups of Data Packages"
+msgid "Groups of Datasets"
msgstr "Publishers"
#: ckan/templates/group/index.html:11
http://bitbucket.org/okfn/ckanextiati/changeset/0bacf6bba669/
changeset: 0bacf6bba669
branch: new-forms
user: amercader
date: 2011-09-14 16:43:57
summary: [new forms] Add missing file
affected #: 1 file (2.1 KB)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/controllers/group_schema.py Wed Sep 14 15:43:57 2011 +0100
@@ -0,0 +1,44 @@
+fields = (('publisher_contact',
+ 'Contact',
+ 'Email or URL for publisher'),
+ ('publisher_description',
+ 'Description',
+ "General description of Publisher's role and activities"),
+ ('publisher_agencies',
+ 'Organisations / agencies covered',
+ 'Whose activities does this publisher publish?'),
+ ('publisher_timeliness',
+ 'Timeliness of Data',
+ 'How up do date is the data when published?'),
+ ('publisher_frequency',
+ 'Frequency of publication',
+ 'How often is IATI data refreshed? Monthly/Quarterly?'),
+ ('publisher_units',
+ 'Units of Aid',
+ 'A description of any hierarchical reporting units used and how they are applied'),
+ ('publisher_segmentation',
+ 'Segmentation of Published Data',
+ 'Is IATI data published by country, regions?'),
+ ('publisher_refs',
+ 'Data Definitions and References',
+ "Links to guides, explanations, codelists on the publisher's own site that clarify their data"),
+ ('publisher_field_exclusions',
+ 'Field Exclusions',
+ 'What fields does the publisher never use - and for what reason'),
+ ('publisher_record_exclusions',
+ 'Record Exclusions',
+ "What are the policies for excluding particular activities, or parts of an activity's data?"),
+ ('publisher_thresholds',
+ 'Thresholds',
+ 'What are the thresholds below which data or whole activities are not published?'),
+ ('publisher_constraints',
+ 'Other Constraints',
+ 'Other policies that restrict full compliance with the standard'),
+ ('publisher_data_quality',
+ 'Data Quality',
+ "Publisher's comment on the status and accuracyof the data - audited/verified, operational/sub to change, etc"),
+ ('publisher_ui',
+ 'User Interface',
+ "Link to publisher's own public user activity interface"),
+ )
+publisher_record_fields = fields
http://bitbucket.org/okfn/ckanextiati/changeset/9c3782833010/
changeset: 9c3782833010
branch: new-forms
user: amercader
date: 2011-09-14 16:44:31
summary: [new forms] Style changes in forms
affected #: 4 files (325 bytes)
--- a/ckanext/iati/public/css/overrides.css Wed Sep 14 15:43:57 2011 +0100
+++ b/ckanext/iati/public/css/overrides.css Wed Sep 14 15:44:31 2011 +0100
@@ -560,6 +560,21 @@
color:#536FA1;
}
+/*-------- Form errors --------*/
+
+.error-explanation {
+ border: 1px solid red;
+ background-color: #FFE0E0;
+ padding: 0.5em;
+ margin-bottom: 1em;
+}
+
+.field_error{
+ margin-top: 0;
+ color: red
+}
+
+
/*-------- Flash messages --------*/
/*-------- Wordpress Specific --------*/
--- a/ckanext/iati/templates/group/form_iati.html Wed Sep 14 15:43:57 2011 +0100
+++ b/ckanext/iati/templates/group/form_iati.html Wed Sep 14 15:44:31 2011 +0100
@@ -5,7 +5,7 @@
xmlns:xi="http://www.w3.org/2001/XInclude"><div class="error-explanation" py:if="error_summary">
- <h2>Errors in form</h2>
+ <h3>Errors in form</h3><p>The form contains invalid entries:</p><ul><li py:for="key, error in error_summary.items()">${"%s: %s" % (key, error)}</li>
--- a/ckanext/iati/templates/layout_base.html Wed Sep 14 15:43:57 2011 +0100
+++ b/ckanext/iati/templates/layout_base.html Wed Sep 14 15:44:31 2011 +0100
@@ -149,7 +149,8 @@
<div id="minornavigation"><minornavigation></minornavigation></div>
- <!-- support both options for defining content -->
+ <h2 py:if="defined('page_heading')">${page_heading()}</h2>
+ <!-- support both options for defining content --><py:if test="defined('content')">
${content()}
</py:if>
--- a/ckanext/iati/templates/package/form_iati.html Wed Sep 14 15:43:57 2011 +0100
+++ b/ckanext/iati/templates/package/form_iati.html Wed Sep 14 15:44:31 2011 +0100
@@ -1,11 +1,11 @@
-<form id="package-edit" class="package_create_form ckan" method="post"
+<form id="package-edit" method="post"
py:attrs="{'class':'has-errors'} if errors else {}"
xmlns:i18n="http://genshi.edgewall.org/i18n"
xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude">
-
+
<div class="error-explanation" py:if="error_summary">
- <h2>Errors in form</h2>
+ <h3>Errors in form</h3><p>The form contains invalid entries:</p><ul><li py:for="key, error in error_summary.items()">${"%s: %s" % (key, error)}</li>
@@ -16,7 +16,7 @@
<legend>Basic information </legend><dl><dt><label class="field_req" for="name">Name *</label></dt>
- <dd><input id="name" maxlength="100" name="name" type="text" value="${data.get('name', '')}" /></dd>
+ <dd><input id="name" name="name" type="text" value="${data.get('name', '')}" /></dd><dd class="field_error" py:if="errors.get('name', '')">${errors.get('name', '')}</dd><dd class="instructions basic">A unique identifier for the activity record.</dd><dd class="instructions further">It should be broadly humanly readable, in the spirit of Semantic Web URIs. Only use an acronym if it is widely recognised. Renaming is possible but discouraged.</dd>
http://bitbucket.org/okfn/ckanextiati/changeset/2068b94a30b1/
changeset: 2068b94a30b1
user: amercader
date: 2011-09-14 18:22:37
summary: [merge] from new-forms
affected #: 19 files (40.1 KB)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/controllers/__init__.py Wed Sep 14 17:22:37 2011 +0100
@@ -0,0 +1,1 @@
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/controllers/countries.py Wed Sep 14 17:22:37 2011 +0100
@@ -0,0 +1,6 @@
+# -*- coding: UTF-8 -*-
+
+# This Python file uses the following encoding: utf-8
+# Country and regions names and codes sent by Bill Anderson on 2011-06-28
+
+COUNTRIES = (("", u"(No country assigned)"), ("AF",u"Afghanistan"),("AX",u"Ã
land Islands"),("AL",u"Albania"),("DZ",u"Algeria"),("AS",u"American Samoa"),("AD",u"Andorra"),("AO",u"Angola"),("AI",u"Anguilla"),("AQ",u"Antarctica"),("AG",u"Antigua And Barbuda"),("AR",u"Argentina"),("AM",u"Armenia"),("AW",u"Aruba"),("AU",u"Australia"),("AT",u"Austria"),("AZ",u"Azerbaijan"),("BS",u"Bahamas"),("BH",u"Bahrain"),("BD",u"Bangladesh"),("BB",u"Barbados"),("BY",u"Belarus"),("BE",u"Belgium"),("BZ",u"Belize"),("BJ",u"Benin"),("BM",u"Bermuda"),("BT",u"Bhutan"),("BO",u"Bolivia, Plurinational State Of"),("BQ",u"Bonaire, Sint Eustatius And Saba"),("BA",u"Bosnia And Herzegovina"),("BW",u"Botswana"),("BV",u"Bouvet Island"),("BR",u"Brazil"),("IO",u"British Indian Ocean Territory"),("BN",u"Brunei Darussalam"),("BG",u"Bulgaria"),("BF",u"Burkina Faso"),("BI",u"Burundi"),("KH",u"Cambodia"),("CM",u"Cameroon"),("CA",u"Canada"),("CV",u"Cape Verde"),("KY",u"Cayman Islands"),("CF",u"Central African Republic"),("TD",u"Chad"),("CL",u"Chile"),("CN",u"China"),("CX",u"Christmas Island"),("CC",u"Cocos (Keeling) Islands"),("CO",u"Colombia"),("KM",u"Comoros"),("CG",u"Congo"),("CD",u"Congo, The Democratic Republic Of The"),("CK",u"Cook Islands"),("CR",u"Costa Rica"),("CI",u"Côte D'Ivoire"),("HR",u"Croatia"),("CU",u"Cuba"),("CW",u"Curaçao"),("CY",u"Cyprus"),("CZ",u"Czech Republic"),("DK",u"Denmark"),("DJ",u"Djibouti"),("DM",u"Dominica"),("DO",u"Dominican Republic"),("EC",u"Ecuador"),("EG",u"Egypt"),("SV",u"El Salvador"),("GQ",u"Equatorial Guinea"),("ER",u"Eritrea"),("EE",u"Estonia"),("ET",u"Ethiopia"),("FK",u"Falkland Islands (Malvinas)"),("FO",u"Faroe Islands"),("FJ",u"Fiji"),("FI",u"Finland"),("FR",u"France"),("GF",u"French Guiana"),("PF",u"French Polynesia"),("TF",u"French Southern Territories"),("GA",u"Gabon"),("GM",u"Gambia"),("GE",u"Georgia"),("DE",u"Germany"),("GH",u"Ghana"),("GI",u"Gibraltar"),("GR",u"Greece"),("GL",u"Greenland"),("GD",u"Grenada"),("GP",u"Guadeloupe"),("GU",u"Guam"),("GT",u"Guatemala"),("GG",u"Guernsey"),("GN",u"Guinea"),("GW",u"Guinea-Bissau"),("GY",u"Guyana"),("HT",u"Haiti"),("HM",u"Heard Island And Mcdonald Islands"),("VA",u"Holy See (Vatican City State)"),("HN",u"Honduras"),("HK",u"Hong Kong"),("HU",u"Hungary"),("IS",u"Iceland"),("IN",u"India"),("ID",u"Indonesia"),("IR",u"Iran, Islamic Republic Of"),("IQ",u"Iraq"),("IE",u"Ireland"),("IM",u"Isle Of Man"),("IL",u"Israel"),("IT",u"Italy"),("JM",u"Jamaica"),("JP",u"Japan"),("JE",u"Jersey"),("JO",u"Jordan"),("KZ",u"Kazakhstan"),("KE",u"Kenya"),("KI",u"Kiribati"),("KP",u"Korea, Democratic People's Republic Of"),("KR",u"Korea, Republic Of"),("XK",u"Kosovo"),("KW",u"Kuwait"),("KG",u"Kyrgyzstan"),("LA",u"Lao People's Democratic Republic"),("LV",u"Latvia"),("LB",u"Lebanon"),("LS",u"Lesotho"),("LR",u"Liberia"),("LY",u"Libyan Arab Jamahiriya"),("LI",u"Liechtenstein"),("LT",u"Lithuania"),("LU",u"Luxembourg"),("MO",u"Macao"),("MK",u"Macedonia, The Former Yugoslav Republic Of"),("MG",u"Madagascar"),("MW",u"Malawi"),("MY",u"Malaysia"),("MV",u"Maldives"),("ML",u"Mali"),("MT",u"Malta"),("MH",u"Marshall Islands"),("MQ",u"Martinique"),("MR",u"Mauritania"),("MU",u"Mauritius"),("YT",u"Mayotte"),("MX",u"Mexico"),("FM",u"Micronesia, Federated States Of"),("MD",u"Moldova, Republic Of"),("MC",u"Monaco"),("MN",u"Mongolia"),("ME",u"Montenegro"),("MS",u"Montserrat"),("MA",u"Morocco"),("MZ",u"Mozambique"),("MM",u"Myanmar"),("NA",u"Namibia"),("NR",u"Nauru"),("NP",u"Nepal"),("NL",u"Netherlands"),("NC",u"New Caledonia"),("NZ",u"New Zealand"),("NI",u"Nicaragua"),("NE",u"Niger"),("NG",u"Nigeria"),("NU",u"Niue"),("NF",u"Norfolk Island"),("MP",u"Northern Mariana Islands"),("NO",u"Norway"),("OM",u"Oman"),("PK",u"Pakistan"),("PW",u"Palau"),("PS",u"Palestinian Territory, Occupied"),("PA",u"Panama"),("PG",u"Papua New Guinea"),("PY",u"Paraguay"),("PE",u"Peru"),("PH",u"Philippines"),("PN",u"Pitcairn"),("PL",u"Poland"),("PT",u"Portugal"),("PR",u"Puerto Rico"),("QA",u"Qatar"),("RE",u"Réunion"),("RO",u"Romania"),("RU",u"Russian Federation"),("RW",u"Rwanda"),("BL",u"Saint Barthélemy"),("SH",u"Saint Helena, Ascension And Tristan Da Cunha"),("KN",u"Saint Kitts And Nevis"),("LC",u"Saint Lucia"),("MF",u"Saint Martin (French Part)"),("PM",u"Saint Pierre And Miquelon"),("VC",u"Saint Vincent And The Grenadines"),("WS",u"Samoa"),("SM",u"San Marino"),("ST",u"Sao Tome And Principe"),("SA",u"Saudi Arabia"),("SN",u"Senegal"),("RS",u"Serbia"),("SC",u"Seychelles"),("SL",u"Sierra Leone"),("SG",u"Singapore"),("SX",u"Sint Maarten (Dutch Part)"),("SK",u"Slovakia"),("SI",u"Slovenia"),("SB",u"Solomon Islands"),("SO",u"Somalia"),("ZA",u"South Africa"),("GS",u"South Georgia And The South Sandwich Islands"),("ES",u"Spain"),("LK",u"Sri Lanka"),("SD",u"Sudan"),("SR",u"Suriname"),("SJ",u"Svalbard And Jan Mayen"),("SZ",u"Swaziland"),("SE",u"Sweden"),("CH",u"Switzerland"),("SY",u"Syrian Arab Republic"),("TW",u"Taiwan, Province Of China"),("TJ",u"Tajikistan"),("TZ",u"Tanzania, United Republic Of"),("TH",u"Thailand"),("TL",u"Timor-Leste"),("TG",u"Togo"),("TK",u"Tokelau"),("TO",u"Tonga"),("TT",u"Trinidad And Tobago"),("TN",u"Tunisia"),("TR",u"Turkey"),("TM",u"Turkmenistan"),("TC",u"Turks And Caicos Islands"),("TV",u"Tuvalu"),("UG",u"Uganda"),("UA",u"Ukraine"),("AE",u"United Arab Emirates"),("GB",u"United Kingdom"),("US",u"United States"),("UM",u"United States Minor Outlying Islands"),("UY",u"Uruguay"),("UZ",u"Uzbekistan"),("VU",u"Vanuatu"),("VE",u"Venezuela, Bolivarian Republic Of"),("VN",u"Viet Nam"),("VG",u"Virgin Islands, British"),("VI",u"Virgin Islands, U.S."),("WF",u"Wallis And Futuna"),("EH",u"Western Sahara"),("YE",u"Yemen"),("ZM",u"Zambia"),("ZW",u"Zimbabwe"),("298",u"Africa"),("189",u"Africa - North"),("289",u"Africa - Sub-Saharan"),("089",u"Europe"),("498",u"America"),("389",u"America - North & Central"),("489",u"America - South"),("380",u"West Indies"),("589",u"Middle East"),("798",u"Asia"),("619",u"Asia - Central"),("679",u"Asia - South"),("689",u"Asia - South & Central"),("789",u"Asia - Far East"),("889",u"Oceania"),("998",u"Unspecified"),)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/controllers/group_iati.py Wed Sep 14 17:22:37 2011 +0100
@@ -0,0 +1,76 @@
+from ckan.lib.base import c
+from ckan import model
+
+from ckan.lib.navl.validators import ignore_missing, not_empty
+
+from ckan.logic.schema import group_form_schema
+from ckan.logic.converters import convert_from_extras, convert_to_extras
+from ckan.controllers.group import GroupController
+
+PUBLISHER_TYPES = ['Primary source', 'Secondary source']
+
+
+class GroupIatiController(GroupController):
+
+ group_form = 'group/form_iati.html'
+
+ def _setup_template_variables(self, context):
+
+ super(GroupIatiController,self)._setup_template_variables(context)
+
+ c.licences = [('', '')] + model.Package.get_license_options()
+
+ def _form_to_db_schema(self):
+ schema = group_form_schema()
+ schema.update({
+ 'type': [not_empty, publisher_type_validator, convert_to_extras],
+ 'license_id': [convert_to_extras],
+ 'publisher_segmentation': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_ui': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_frequency': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_thresholds': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_units': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_contact': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_agencies': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_field_exclusions': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_description': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_record_exclusions': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_timeliness': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_refs': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_constraints': [unicode, convert_to_extras, ignore_missing],
+ 'publisher_data_quality': [unicode, convert_to_extras, ignore_missing],
+ })
+
+ return schema
+
+ def _db_to_form_schema(self):
+ schema = group_form_schema()
+ schema.update({
+ 'type': [convert_from_extras],
+ 'license_id': [convert_from_extras],
+ 'publisher_segmentation': [convert_from_extras],
+ 'publisher_ui': [convert_from_extras],
+ 'publisher_frequency': [convert_from_extras],
+ 'publisher_thresholds': [convert_from_extras],
+ 'publisher_units': [convert_from_extras],
+ 'publisher_contact': [convert_from_extras],
+ 'publisher_agencies': [convert_from_extras],
+ 'publisher_field_exclusions': [convert_from_extras],
+ 'publisher_description': [convert_from_extras],
+ 'publisher_record_exclusions': [convert_from_extras],
+ 'publisher_timeliness': [convert_from_extras],
+ 'publisher_refs': [convert_from_extras],
+ 'publisher_constraints': [convert_from_extras],
+ 'publisher_data_quality': [convert_from_extras],
+ })
+
+ return schema
+
+ def _check_data_dict(self, data_dict):
+ return
+
+
+def publisher_type_validator(value,context):
+ if not value in PUBLISHER_TYPES:
+ raise Invalid('Unknown publisher type, allowed values: [%s]' % ', '.join(PUBLISHER_TYPES))
+ return value
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/controllers/group_schema.py Wed Sep 14 17:22:37 2011 +0100
@@ -0,0 +1,44 @@
+fields = (('publisher_contact',
+ 'Contact',
+ 'Email or URL for publisher'),
+ ('publisher_description',
+ 'Description',
+ "General description of Publisher's role and activities"),
+ ('publisher_agencies',
+ 'Organisations / agencies covered',
+ 'Whose activities does this publisher publish?'),
+ ('publisher_timeliness',
+ 'Timeliness of Data',
+ 'How up do date is the data when published?'),
+ ('publisher_frequency',
+ 'Frequency of publication',
+ 'How often is IATI data refreshed? Monthly/Quarterly?'),
+ ('publisher_units',
+ 'Units of Aid',
+ 'A description of any hierarchical reporting units used and how they are applied'),
+ ('publisher_segmentation',
+ 'Segmentation of Published Data',
+ 'Is IATI data published by country, regions?'),
+ ('publisher_refs',
+ 'Data Definitions and References',
+ "Links to guides, explanations, codelists on the publisher's own site that clarify their data"),
+ ('publisher_field_exclusions',
+ 'Field Exclusions',
+ 'What fields does the publisher never use - and for what reason'),
+ ('publisher_record_exclusions',
+ 'Record Exclusions',
+ "What are the policies for excluding particular activities, or parts of an activity's data?"),
+ ('publisher_thresholds',
+ 'Thresholds',
+ 'What are the thresholds below which data or whole activities are not published?'),
+ ('publisher_constraints',
+ 'Other Constraints',
+ 'Other policies that restrict full compliance with the standard'),
+ ('publisher_data_quality',
+ 'Data Quality',
+ "Publisher's comment on the status and accuracyof the data - audited/verified, operational/sub to change, etc"),
+ ('publisher_ui',
+ 'User Interface',
+ "Link to publisher's own public user activity interface"),
+ )
+publisher_record_fields = fields
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/controllers/package_iati.py Wed Sep 14 17:22:37 2011 +0100
@@ -0,0 +1,109 @@
+from ckan.lib.base import c
+from ckan.lib.helpers import json
+from ckan import model
+from ckan.controllers.package import PackageController
+from ckan.authz import Authorizer
+
+from ckan.logic.schema import package_form_schema
+from ckan.lib.navl.validators import (ignore_missing,
+ not_empty,
+ empty,
+ ignore,
+ keep_extras,
+ )
+from ckan.logic.converters import convert_from_extras, convert_to_extras, date_to_db, date_to_form
+from ckan.lib.navl.dictization_functions import Missing, Invalid
+from ckan.lib.field_types import DateType, DateConvertError
+
+from countries import COUNTRIES
+
+class PackageIatiController(PackageController):
+
+ package_form = 'package/form_iati.html'
+
+ def _setup_template_variables(self, context, data_dict=None):
+
+ super(PackageIatiController,self)._setup_template_variables(context,data_dict)
+
+ c.groups_authz = self.get_groups()
+ c.groups_available = self.get_groups(available_only=True)
+
+ c.countries = [(v, k) for k, v in COUNTRIES]
+
+ def _form_to_db_schema(self):
+ schema = package_form_schema()
+ schema.update({
+ 'department': [unicode,convert_to_extras,ignore_missing],
+ 'country': [convert_to_extras, ignore_missing],
+ 'donors': [unicode, convert_from_comma_list, convert_to_extras, ignore_missing],
+ 'donors_type': [unicode, convert_from_comma_list, convert_to_extras, ignore_missing],
+ 'donors_country': [unicode, convert_from_comma_list, convert_to_extras, ignore_missing],
+ 'record_updated': [date_to_db, convert_to_extras,ignore_missing],
+ 'data_updated': [date_to_db, convert_to_extras,ignore_missing],
+ 'activity_period-from': [date_to_db, convert_to_extras,ignore_missing],
+ 'activity_period-to': [date_to_db, convert_to_extras,ignore_missing],
+ 'activity_count': [integer,convert_to_extras,ignore_missing],
+ 'archive_file': [checkbox_value, convert_to_extras,ignore_missing],
+ 'verified': [checkbox_value, convert_to_extras,ignore_missing],
+ })
+
+ return schema
+
+ def _db_to_form_schema(self):
+ schema = package_form_schema()
+ schema.update({
+ 'department': [convert_from_extras,ignore_missing],
+ 'country': [convert_from_extras, ignore_missing],
+ 'donors': [ignore_missing, convert_from_extras, convert_to_comma_list],
+ 'donors_type': [ignore_missing, convert_from_extras, convert_to_comma_list],
+ 'donors_country': [ignore_missing, convert_from_extras, convert_to_comma_list],
+ 'record_updated': [convert_from_extras,ignore_missing, date_to_form],
+ 'data_updated': [convert_from_extras,ignore_missing, date_to_form],
+ 'activity_period-from': [convert_from_extras,ignore_missing, date_to_form],
+ 'activity_period-to': [convert_from_extras,ignore_missing, date_to_form],
+ 'activity_count': [convert_from_extras,ignore_missing],
+ 'archive_file': [convert_from_extras,ignore_missing],
+ 'verified': [convert_from_extras,ignore_missing],
+ })
+
+ return schema
+
+ def _check_data_dict(self, data_dict):
+ return
+
+ # End hooks
+
+ def get_groups(self,available_only=False):
+
+ query = Authorizer().authorized_query(c.user, model.Group, model.Action.EDIT)
+ groups = set(query.all())
+
+ if available_only:
+ package = c.pkg
+ if package:
+ groups = groups - set(package.groups)
+
+ return [{'id':group.id,'name':group.name, 'title':group.title} for group in groups if group.state==model.State.ACTIVE]
+
+
+def convert_to_comma_list(value, context):
+
+ return ', '.join(json.loads(value))
+
+def convert_from_comma_list(value, context):
+
+ return [x.strip() for x in value.split(',') if len(x)]
+
+def checkbox_value(value,context):
+
+ return 'yes' if not isinstance(value, Missing) else 'no'
+
+def integer(value,context):
+
+ if not value == '':
+ try:
+ value = int(value)
+ except ValueError,e:
+ raise Invalid(str(e))
+ return value
+
--- a/ckanext/iati/forms/__init__.py Thu Sep 01 13:59:28 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-
-from package import get_package_fieldset as get_iati_package_fieldset
-from group import get_group_fieldset as get_iati_group_fieldset
--- a/ckanext/iati/forms/countries.py Thu Sep 01 13:59:28 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-# -*- coding: UTF-8 -*-
-
-# This Python file uses the following encoding: utf-8
-# Country and regions names and codes sent by Bill Anderson on 2011-06-28
-
-COUNTRIES = (("", u"(No country assigned)"), ("AF",u"Afghanistan"),("AX",u"Ã
land Islands"),("AL",u"Albania"),("DZ",u"Algeria"),("AS",u"American Samoa"),("AD",u"Andorra"),("AO",u"Angola"),("AI",u"Anguilla"),("AQ",u"Antarctica"),("AG",u"Antigua And Barbuda"),("AR",u"Argentina"),("AM",u"Armenia"),("AW",u"Aruba"),("AU",u"Australia"),("AT",u"Austria"),("AZ",u"Azerbaijan"),("BS",u"Bahamas"),("BH",u"Bahrain"),("BD",u"Bangladesh"),("BB",u"Barbados"),("BY",u"Belarus"),("BE",u"Belgium"),("BZ",u"Belize"),("BJ",u"Benin"),("BM",u"Bermuda"),("BT",u"Bhutan"),("BO",u"Bolivia, Plurinational State Of"),("BQ",u"Bonaire, Sint Eustatius And Saba"),("BA",u"Bosnia And Herzegovina"),("BW",u"Botswana"),("BV",u"Bouvet Island"),("BR",u"Brazil"),("IO",u"British Indian Ocean Territory"),("BN",u"Brunei Darussalam"),("BG",u"Bulgaria"),("BF",u"Burkina Faso"),("BI",u"Burundi"),("KH",u"Cambodia"),("CM",u"Cameroon"),("CA",u"Canada"),("CV",u"Cape Verde"),("KY",u"Cayman Islands"),("CF",u"Central African Republic"),("TD",u"Chad"),("CL",u"Chile"),("CN",u"China"),("CX",u"Christmas Island"),("CC",u"Cocos (Keeling) Islands"),("CO",u"Colombia"),("KM",u"Comoros"),("CG",u"Congo"),("CD",u"Congo, The Democratic Republic Of The"),("CK",u"Cook Islands"),("CR",u"Costa Rica"),("CI",u"Côte D'Ivoire"),("HR",u"Croatia"),("CU",u"Cuba"),("CW",u"Curaçao"),("CY",u"Cyprus"),("CZ",u"Czech Republic"),("DK",u"Denmark"),("DJ",u"Djibouti"),("DM",u"Dominica"),("DO",u"Dominican Republic"),("EC",u"Ecuador"),("EG",u"Egypt"),("SV",u"El Salvador"),("GQ",u"Equatorial Guinea"),("ER",u"Eritrea"),("EE",u"Estonia"),("ET",u"Ethiopia"),("FK",u"Falkland Islands (Malvinas)"),("FO",u"Faroe Islands"),("FJ",u"Fiji"),("FI",u"Finland"),("FR",u"France"),("GF",u"French Guiana"),("PF",u"French Polynesia"),("TF",u"French Southern Territories"),("GA",u"Gabon"),("GM",u"Gambia"),("GE",u"Georgia"),("DE",u"Germany"),("GH",u"Ghana"),("GI",u"Gibraltar"),("GR",u"Greece"),("GL",u"Greenland"),("GD",u"Grenada"),("GP",u"Guadeloupe"),("GU",u"Guam"),("GT",u"Guatemala"),("GG",u"Guernsey"),("GN",u"Guinea"),("GW",u"Guinea-Bissau"),("GY",u"Guyana"),("HT",u"Haiti"),("HM",u"Heard Island And Mcdonald Islands"),("VA",u"Holy See (Vatican City State)"),("HN",u"Honduras"),("HK",u"Hong Kong"),("HU",u"Hungary"),("IS",u"Iceland"),("IN",u"India"),("ID",u"Indonesia"),("IR",u"Iran, Islamic Republic Of"),("IQ",u"Iraq"),("IE",u"Ireland"),("IM",u"Isle Of Man"),("IL",u"Israel"),("IT",u"Italy"),("JM",u"Jamaica"),("JP",u"Japan"),("JE",u"Jersey"),("JO",u"Jordan"),("KZ",u"Kazakhstan"),("KE",u"Kenya"),("KI",u"Kiribati"),("KP",u"Korea, Democratic People's Republic Of"),("KR",u"Korea, Republic Of"),("XK",u"Kosovo"),("KW",u"Kuwait"),("KG",u"Kyrgyzstan"),("LA",u"Lao People's Democratic Republic"),("LV",u"Latvia"),("LB",u"Lebanon"),("LS",u"Lesotho"),("LR",u"Liberia"),("LY",u"Libyan Arab Jamahiriya"),("LI",u"Liechtenstein"),("LT",u"Lithuania"),("LU",u"Luxembourg"),("MO",u"Macao"),("MK",u"Macedonia, The Former Yugoslav Republic Of"),("MG",u"Madagascar"),("MW",u"Malawi"),("MY",u"Malaysia"),("MV",u"Maldives"),("ML",u"Mali"),("MT",u"Malta"),("MH",u"Marshall Islands"),("MQ",u"Martinique"),("MR",u"Mauritania"),("MU",u"Mauritius"),("YT",u"Mayotte"),("MX",u"Mexico"),("FM",u"Micronesia, Federated States Of"),("MD",u"Moldova, Republic Of"),("MC",u"Monaco"),("MN",u"Mongolia"),("ME",u"Montenegro"),("MS",u"Montserrat"),("MA",u"Morocco"),("MZ",u"Mozambique"),("MM",u"Myanmar"),("NA",u"Namibia"),("NR",u"Nauru"),("NP",u"Nepal"),("NL",u"Netherlands"),("NC",u"New Caledonia"),("NZ",u"New Zealand"),("NI",u"Nicaragua"),("NE",u"Niger"),("NG",u"Nigeria"),("NU",u"Niue"),("NF",u"Norfolk Island"),("MP",u"Northern Mariana Islands"),("NO",u"Norway"),("OM",u"Oman"),("PK",u"Pakistan"),("PW",u"Palau"),("PS",u"Palestinian Territory, Occupied"),("PA",u"Panama"),("PG",u"Papua New Guinea"),("PY",u"Paraguay"),("PE",u"Peru"),("PH",u"Philippines"),("PN",u"Pitcairn"),("PL",u"Poland"),("PT",u"Portugal"),("PR",u"Puerto Rico"),("QA",u"Qatar"),("RE",u"Réunion"),("RO",u"Romania"),("RU",u"Russian Federation"),("RW",u"Rwanda"),("BL",u"Saint Barthélemy"),("SH",u"Saint Helena, Ascension And Tristan Da Cunha"),("KN",u"Saint Kitts And Nevis"),("LC",u"Saint Lucia"),("MF",u"Saint Martin (French Part)"),("PM",u"Saint Pierre And Miquelon"),("VC",u"Saint Vincent And The Grenadines"),("WS",u"Samoa"),("SM",u"San Marino"),("ST",u"Sao Tome And Principe"),("SA",u"Saudi Arabia"),("SN",u"Senegal"),("RS",u"Serbia"),("SC",u"Seychelles"),("SL",u"Sierra Leone"),("SG",u"Singapore"),("SX",u"Sint Maarten (Dutch Part)"),("SK",u"Slovakia"),("SI",u"Slovenia"),("SB",u"Solomon Islands"),("SO",u"Somalia"),("ZA",u"South Africa"),("GS",u"South Georgia And The South Sandwich Islands"),("ES",u"Spain"),("LK",u"Sri Lanka"),("SD",u"Sudan"),("SR",u"Suriname"),("SJ",u"Svalbard And Jan Mayen"),("SZ",u"Swaziland"),("SE",u"Sweden"),("CH",u"Switzerland"),("SY",u"Syrian Arab Republic"),("TW",u"Taiwan, Province Of China"),("TJ",u"Tajikistan"),("TZ",u"Tanzania, United Republic Of"),("TH",u"Thailand"),("TL",u"Timor-Leste"),("TG",u"Togo"),("TK",u"Tokelau"),("TO",u"Tonga"),("TT",u"Trinidad And Tobago"),("TN",u"Tunisia"),("TR",u"Turkey"),("TM",u"Turkmenistan"),("TC",u"Turks And Caicos Islands"),("TV",u"Tuvalu"),("UG",u"Uganda"),("UA",u"Ukraine"),("AE",u"United Arab Emirates"),("GB",u"United Kingdom"),("US",u"United States"),("UM",u"United States Minor Outlying Islands"),("UY",u"Uruguay"),("UZ",u"Uzbekistan"),("VU",u"Vanuatu"),("VE",u"Venezuela, Bolivarian Republic Of"),("VN",u"Viet Nam"),("VG",u"Virgin Islands, British"),("VI",u"Virgin Islands, U.S."),("WF",u"Wallis And Futuna"),("EH",u"Western Sahara"),("YE",u"Yemen"),("ZM",u"Zambia"),("ZW",u"Zimbabwe"),("298",u"Africa"),("189",u"Africa - North"),("289",u"Africa - Sub-Saharan"),("089",u"Europe"),("498",u"America"),("389",u"America - North & Central"),("489",u"America - South"),("380",u"West Indies"),("589",u"Middle East"),("798",u"Asia"),("619",u"Asia - Central"),("679",u"Asia - South"),("689",u"Asia - South & Central"),("789",u"Asia - Far East"),("889",u"Oceania"),("998",u"Unspecified"),)
--- a/ckanext/iati/forms/group.py Thu Sep 01 13:59:28 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-import formalchemy
-from formalchemy import helpers as fa_h
-import ckan.lib.helpers as h
-
-from ckan.forms.builder import FormBuilder
-from sqlalchemy.util import OrderedDict
-from pylons.i18n import _, ungettext, N_, gettext
-import ckan.model as model
-import ckan.forms.common as common
-import ckan.forms.group as group
-from ckan.forms.common import ExtrasField, PackageNameField, SelectExtraField
-from ckan.forms.common import TextAreaExtraField
-from ckan.lib.helpers import literal
-
-from group_schema import fields
-
-
-__all__ = ['get_group_dict', 'edit_group_dict']
-
-
-def build_group_form(is_admin=False, with_packages=False):
- PUBLISHER_TYPES = [_("Primary source"),
- _("Secondary source")
- ]
- publisher_record_fields = fields
- builder = FormBuilder(model.Group)
- builder.set_field_text('name', 'Unique Name (required)',
- literal("<br/><strong>Unique identifier</strong> for group.<br/>2+ chars, lowercase, using only 'a-z0-9' and '-_'"))
- builder.set_field_option('name', 'validate', common.group_name_validator)
- builder.set_field_option('state', 'dropdown', {'options': model.State.all})
- builder.add_field(SelectExtraField('type',
- options=PUBLISHER_TYPES,
- allow_empty=False))
- builder.set_field_text('type', 'Source')
-
- builder.add_field(SelectExtraField('license_id',
- options=[('', None)] + model.Package.get_license_options()))
- builder.set_field_text('license_id', _('License'))
-
- for name, title, description in publisher_record_fields:
- builder.add_field(TextAreaExtraField(name))
- builder.set_field_text(name, title, description)
- displayed_fields = ['name', 'title', 'type', 'license_id'] +\
- [x[0] for x in publisher_record_fields]
- from ckan.authz import Authorizer
- from ckan.lib.base import c
- if Authorizer.is_sysadmin(c.user):
- displayed_fields.append('state')
-
- if with_packages:
- builder.add_field(group.PackagesField('packages'))
- displayed_fields.append('packages')
- builder.set_displayed_fields(OrderedDict([('Details', displayed_fields)]))
- builder.set_label_prettifier(common.prettify)
- return builder
-
-
-def get_group_fieldset(is_admin=False, combined=False):
- return build_group_form(is_admin=is_admin,
- with_packages=combined).get_fieldset()
-
--- a/ckanext/iati/forms/group_schema.py Thu Sep 01 13:59:28 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-fields = (('publisher_contact',
- 'Contact',
- 'Email or URL for publisher'),
- ('publisher_description',
- 'Description',
- "General description of Publisher's role and activities"),
- ('publisher_agencies',
- 'Organisations / agencies covered',
- 'Whose activities does this publisher publish?'),
- ('publisher_timeliness',
- 'Timeliness of Data',
- 'How up do date is the data when published?'),
- ('publisher_frequency',
- 'Frequency of publication',
- 'How often is IATI data refreshed? Monthly/Quarterly?'),
- ('publisher_units',
- 'Units of Aid',
- 'A description of any hierarchical reporting units used and how they are applied'),
- ('publisher_segmentation',
- 'Segmentation of Published Data',
- 'Is IATI data published by country, regions?'),
- ('publisher_refs',
- 'Data Definitions and References',
- "Links to guides, explanations, codelists on the publisher's own site that clarify their data"),
- ('publisher_field_exclusions',
- 'Field Exclusions',
- 'What fields does the publisher never use - and for what reason'),
- ('publisher_record_exclusions',
- 'Record Exclusions',
- "What are the policies for excluding particular activities, or parts of an activity's data?"),
- ('publisher_thresholds',
- 'Thresholds',
- 'What are the thresholds below which data or whole activities are not published?'),
- ('publisher_constraints',
- 'Other Constraints',
- 'Other policies that restrict full compliance with the standard'),
- ('publisher_data_quality',
- 'Data Quality',
- "Publisher's comment on the status and accuracyof the data - audited/verified, operational/sub to change, etc"),
- ('publisher_ui',
- 'User Interface',
- "Link to publisher's own public user activity interface"),
- )
-publisher_record_fields = fields
--- a/ckanext/iati/forms/package.py Thu Sep 01 13:59:28 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,226 +0,0 @@
-import formalchemy
-from formalchemy import helpers as h
-from sqlalchemy.util import OrderedDict
-from pylons.i18n import _, ungettext, N_, gettext
-
-from ckan.lib.helpers import literal
-import ckan.forms.common as common
-from ckan.forms.common import fa_h, TextExtraField, RegExRangeValidatingField, GroupSelectField
-import ckan.model as model
-import ckan.forms.package as package
-from ckan.lib import field_types
-
-from countries import COUNTRIES
-
-__all__ = ['get_iati_fieldset']
-
-class CommaListExtraField(RegExRangeValidatingField):
- '''A form field for two TextType fields, representing a range,
- stored in 'extra' fields.'''
- def get_configured(self):
- field = self.CommaListField(self.name).with_renderer(self.CommaListRenderer)
- return RegExRangeValidatingField.get_configured(self, field)
-
- class CommaListField(formalchemy.Field):
- def sync(self):
- if not self.is_readonly():
- pkg = self.model
- vals = self._deserialize() or []
- #vals = [v.strip()for v in vals.split(',') if len(v.strip())]
- pkg.extras[self.name] = vals
-
- class CommaListRenderer(formalchemy.fields.FieldRenderer):
- def _get_value(self):
- if self.value:
- return self.value
- extras = self.field.parent.model.extras
- return extras.get(self.field.name, [])
-
- def render(self, **kwargs):
- values = self._get_value()
- html = fa_h.text_field(self.name, value=', '.join(values), **kwargs)
- return html
-
- def render_readonly(self, **kwargs):
- val = ', '.join(self._get_value())
- return field_readonly_renderer(self.field.key, val_str)
-
- def _serialized_value(self):
- param_val = self.params.get(self.name, u'')
- return [v.strip()for v in param_val.split(',') if len(v.strip())]
-
- def deserialize(self):
- return self._serialized_value()
-
-
-class SelectExtraField(TextExtraField):
- '''A form field for text from from a list of options, that is
- stored in an "extras" field.'''
- def __init__(self, name, options):
- self.options = options[:]
- # ensure options have key and value, not just a value
- for i, option in enumerate(self.options):
- if not isinstance(option, (tuple, list)):
- self.options[i] = (option, option)
- super(SelectExtraField, self).__init__(name)
-
- def get_configured(self):
- return self.TextExtraField(self.name, options=self.options).with_renderer(self.SelectRenderer)
-
- class SelectRenderer(formalchemy.fields.FieldRenderer):
- def _get_value(self, **kwargs):
- extras = self.field.parent.model.extras
- return unicode(kwargs.get('selected', '') or self.value or extras.get(self.field.name, ''))
-
- def render(self, options, **kwargs):
- selected = self._get_value()
- options = [('', '')] + options
- option_keys = [key for value, key in options]
- if selected in option_keys:
- select_field_selected = selected
- else:
- select_field_selected = u''
- fa_version_nums = formalchemy.__version__.split('.')
- # Requires FA 1.3.2 onwards for this select i/f
- html = literal(fa_h.select(self.name, select_field_selected, options, **kwargs))
-
- return html
-
- def render_readonly(self, **kwargs):
- return field_readonly_renderer(self.field.key, self._get_value())
-
- def _serialized_value(self):
- main_value = self.params.get(self.name, u'')
- return main_value
-
-class AtLeastOneGroupSelectField(GroupSelectField):
-
- def get_configured(self):
- field = self.GroupSelectionField(self.name, self.allow_empty).with_renderer(self.GroupSelectEditRenderer)
- field.set(multiple=self.multiple)
- field = field.validate(self.validate_groups)
- field.user_editable_groups = self.user_editable_groups
- return field
-
- def validate_groups(self, val, field):
- if len(val) < 1:
- raise formalchemy.ValidationError(_("Need at least one publishing entity assigned"))
-
-
-# Setup the fieldset
-def build_package_iati_form(is_admin=False, user_editable_groups=None, **kwargs):
- builder = package.build_package_form(is_admin=is_admin,
- user_editable_groups=user_editable_groups, **kwargs)
-
- # IATI specifics
-
- #Publishing Entity:
- builder.set_field_text('groups', _('Publisher'))
- builder.add_field(AtLeastOneGroupSelectField('groups', allow_empty=False,
- user_editable_groups=user_editable_groups))
-
- #builder.add_field(common.TextExtraField('publisher'))
- #builder.set_field_text('publisher', _('Publishing entity'))
-
- #Publishing Entity Type: (Donor, Recipient, Community Data..)
- #builder.add_field(SelectExtraField('publisher_type', options=PUBLISHER_TYPES))
- #builder.set_field_text('publisher_type', _('Publishing entity type'))
-
- #Donor (TODO: Generate from crawler)
- # Editable List, CSV?
- builder.add_field(CommaListExtraField('donors'))
- builder.set_field_text('donors', _('Donors'), "Separate multiple entries using commas.")
-
- builder.add_field(CommaListExtraField('donors_type'))
- builder.set_field_text('donors_type', _('Donor type'), "Separate multiple entries using commas.")
-
- builder.add_field(CommaListExtraField('donors_country'))
- builder.set_field_text('donors_country', _('Donor country'), "Separate multiple entries using commas.")
-
- # TODO: Enforce validation
- countries = [(v, k) for k, v in COUNTRIES]
- builder.add_field(SelectExtraField('country', options=countries))
- builder.set_field_text('country', _('Recipient country'))
-
- #Verification status: enumeration of statuses (checked, not checked etc)
- # TODO: Enforce validation, can probably only be set by admins
- builder.add_field(common.CheckboxExtraField('verified'))
- builder.set_field_text('verified', _('Verification'))
-
- builder.add_field(common.CheckboxExtraField('archive_file'))
- builder.set_field_text('archive_file', _('Archive'))
-
- #Activity period: (Generate from crawler)
- builder.add_field(common.DateRangeExtraField('activity_period'))
- builder.set_field_text('activity_period', _('Activitiy Period'))
-
- #Resource links: to the actual IATI record
- #Number of activities: (Generate from crawler)
- builder.add_field(common.TextExtraField('activity_count'))
- builder.set_field_text('activity_count', _('Num. Activities'))
-
- #Date record updated:
- builder.add_field(common.TextExtraField('record_updated'))
- builder.set_field_text('record_updated', _('Record updated'))
-
- #Date data updated:
- builder.add_field(common.TextExtraField('data_updated'))
- builder.set_field_text('data_updated', _('Data updated'))
-
-
- #License: Need this field even if it may be a standard license
- builder.add_field(common.TextExtraField('license'))
- builder.set_field_text('license', _('License'))
-
- #Department
- # TODO: Make this a group property instead?
- builder.add_field(common.TextExtraField('department'))
- builder.set_field_text('department', _('Department'))
-
- #Contact
- builder.set_field_text('author', _('Contact'))
-
- #Contact e-mail
- builder.set_field_text('author_email', _('Contact e-mail'))
-
- #Licence
- builder.set_field_text('license_id', _('License'))
-
- #Resource format
- #Resource URL
- #Resource ID
- # -- do we have an ID?
-
- # Layout
- field_groups = OrderedDict([
- (_('Basic information'), ['name', 'title',
- 'author', 'author_email', 'department',]),
- (_('Publisher'), ['groups']),
- (_('Details'), ['country', 'donors', 'donors_type', 'donors_country',
- 'record_updated', 'data_updated',
- 'license_id', 'tags', 'notes']),
- (_('Resources'), ['resources']),
- (_('Verification and Analysis'), [
- 'activity_period',
- 'activity_count', 'archive_file',
- ]),
- ])
- if is_admin:
- field_groups[_('Verification and Analysis')].append('verified')
- field_groups[_('Verification and Analysis')].append('state')
-
- builder.set_displayed_fields(field_groups)
-
- return builder
- # Strings for i18n:
- [_('External reference'), _('Date released'), _('Date updated'),
- _('Update frequency'), _('Geographic granularity'),
- _('Geographic coverage'), _('Temporal granularity'),
- _('Temporal coverage'), _('Categories'), _('National Statistic'),
- _('Precision'), _('Taxonomy URL'), _('Department'), _('Agency'),
- ]
-
-def get_package_fieldset(is_admin=False, user_editable_groups=None, **kwargs):
- return build_package_iati_form(is_admin=is_admin,
- user_editable_groups=user_editable_groups, **kwargs).get_fieldset()
-
--- a/ckanext/iati/patch.py Thu Sep 01 13:59:28 2011 +0100
+++ b/ckanext/iati/patch.py Wed Sep 14 17:22:37 2011 +0100
@@ -1,13 +1,13 @@
import logging
import re
-from forms.countries import COUNTRIES
+from controllers.countries import COUNTRIES
import ckan.lib.helpers as h
import ckan.authz as authz
from ckan.lib.base import *
from ckan.model import Package
-from ckanext.iati.forms.group_schema import fields
+from ckanext.iati.controllers.group_schema import fields
log = logging.getLogger(__name__)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/plugin.py Wed Sep 14 17:22:37 2011 +0100
@@ -0,0 +1,54 @@
+import os
+
+from logging import getLogger
+
+from ckan.plugins import implements, SingletonPlugin
+from ckan.plugins import IRoutes
+from ckan.plugins import IConfigurer
+
+import ckanext.iati
+
+log = getLogger(__name__)
+
+def configure_template_directory(config, relative_path):
+ configure_served_directory(config, relative_path, 'extra_template_paths')
+
+def configure_public_directory(config, relative_path):
+ configure_served_directory(config, relative_path, 'extra_public_paths')
+
+def configure_served_directory(config, relative_path, config_var):
+ 'Configure serving of public/template directories.'
+ assert config_var in ('extra_template_paths', 'extra_public_paths')
+ this_dir = os.path.dirname(ckanext.iati.__file__)
+ absolute_path = os.path.join(this_dir, relative_path)
+ if absolute_path not in config.get(config_var, ''):
+ if config.get(config_var):
+ config[config_var] += ',' + absolute_path
+ else:
+ config[config_var] = absolute_path
+
+class IatiForms(SingletonPlugin):
+
+ implements(IRoutes)
+ implements(IConfigurer)
+
+ def before_map(self, map):
+ package_controller = 'ckanext.iati.controllers.package_iati:PackageIatiController'
+ group_controller = 'ckanext.iati.controllers.group_iati:GroupIatiController'
+
+ map.redirect('/package/new','/dataset/new')
+ map.redirect('/package/edit/{id}','/dataset/edit/{id}')
+ map.connect('/dataset/new', controller=package_controller, action='new')
+ map.connect('/dataset/edit/{id}', controller=package_controller, action='edit')
+
+ map.connect('/group/new', controller=group_controller, action='new')
+ map.connect('/group/edit/{id}', controller=group_controller, action='edit')
+
+ return map
+
+ def after_map(self, map):
+ return map
+
+ def update_config(self, config):
+ configure_template_directory(config, 'templates')
+
--- a/ckanext/iati/public/css/overrides.css Thu Sep 01 13:59:28 2011 +0100
+++ b/ckanext/iati/public/css/overrides.css Wed Sep 14 17:22:37 2011 +0100
@@ -560,6 +560,21 @@
color:#536FA1;
}
+/*-------- Form errors --------*/
+
+.error-explanation {
+ border: 1px solid red;
+ background-color: #FFE0E0;
+ padding: 0.5em;
+ margin-bottom: 1em;
+}
+
+.field_error{
+ margin-top: 0;
+ color: red
+}
+
+
/*-------- Flash messages --------*/
/*-------- Wordpress Specific --------*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/templates/group/form_iati.html Wed Sep 14 17:22:37 2011 +0100
@@ -0,0 +1,151 @@
+<form id="group-edit" action="" method="post"
+ py:attrs="{'class':'has-errors'} if errors else {}"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <div class="error-explanation" py:if="error_summary">
+ <h3>Errors in form</h3>
+ <p>The form contains invalid entries:</p>
+ <ul>
+ <li py:for="key, error in error_summary.items()">${"%s: %s" % (key, error)}</li>
+ </ul>
+ </div>
+
+ <fieldset>
+ <legend>Basic information</legend>
+ <dl>
+ <dt><label class="field_req" for="name">Unique Name (required) *</label></dt>
+ <dd><input id="name" name="name" type="text" value="${data.get('name', '')}" /></dd>
+ <dd class="field_error" py:if="errors.get('name', '')">${errors.get('name', '')}</dd>
+ <dd class="instructions basic"><strong>Unique identifier</strong> for group.<br/>2+ chars, lowercase, using only 'a-z0-9' and '-_'</dd>
+ <script type="text/javascript">
+ //<![CDATA[
+ $(document).ready(function () { if (!$('#preview').length) { $("#name").focus();}});
+ //]]>
+ </script>
+
+ <dt><label class="field_opt" for="title">Title</label></dt>
+ <dd><input id="title" name="title" type="text" value="${data.get('title', '')}" /></dd>
+ <dd class="field_error" py:if="errors.get('title', '')">${errors.get('title', '')}</dd>
+
+ <dt><label class="field_req" for="type">Source</label></dt>
+ <dd>
+ <select id="type" name="type">
+ <option value="Primary source" py:attrs="{'selected': 'selected' if data.get('type', '') == 'Primary source' else None}">Primary source</option>
+ <option value="Secondary source" py:attrs="{'selected': 'selected' if data.get('type', '') == 'Secondary source' else None}">Secondary source</option>
+ </select>
+ </dd>
+
+ <dt><label class="field_opt" for="license_id">License</label></dt>
+ <dd>
+ <select id="license_id" name="license_id">
+ <py:for each="licence_desc, licence_id in c.licences">
+ <option value="${licence_id}" py:attrs="{'selected': 'selected' if data.get('license_id', '') == licence_id else None}" >${licence_desc}</option>
+ </py:for>
+
+ </select>
+ </dd>
+
+ <py:choose>
+ <py:when test="c.is_sysadmin">
+ <dt><label class="field_opt" for="state">State</label></dt>
+ <dd>
+ <select id="state" name="state">
+ <option py:attrs="{'selected': 'selected' if data.get('state') == 'active' else None}" value="active">active</option>
+ <option py:attrs="{'selected': 'selected' if data.get('state') == 'deleted' else None}" value="deleted">deleted</option>
+ <option py:attrs="{'selected': 'selected' if data.get('state') == 'pending' else None}" value="pending">pending</option>
+ </select>
+ </dd>
+ </py:when>
+ </py:choose>
+
+ </dl>
+ </fieldset>
+
+ <fieldset>
+ <legend>Details</legend>
+ <dl>
+
+ <dt><label class="field_opt" for="publisher_contact">Contact</label></dt>
+ <dd><textarea id="publisher_contact" name="publisher_contact">${data.get('publisher_contact', '')}</textarea></dd>
+ <dd class="instructions basic">Contact details for publisher</dd>
+
+ <dt><label class="field_opt" for="publisher_description">Description</label></dt>
+ <dd><textarea id="publisher_description" name="publisher_description">${data.get('publisher_description', '')}</textarea></dd>
+ <dd class="instructions basic">General description of publisher's role and activities</dd>
+
+ <dt><label class="field_opt" for="publisher_agencies">Organisations / agencies covered</label></dt>
+ <dd><textarea id="publisher_agencies" name="publisher_agencies">${data.get('publisher_agencies', '')}</textarea></dd>
+ <dd class="instructions basic">Whose activities does this publisher publish?</dd>
+
+ <dt><label class="field_opt" for="publisher_timeliness">Timeliness of Data</label></dt>
+ <dd><textarea id="publisher_timeliness" name="publisher_timeliness">${data.get('publisher_timeliness','')}</textarea></dd>
+ <dd class="instructions basic">How up do date is the data when published?</dd>
+
+ <dt><label class="field_opt" for="publisher_frequency">Frequency of publication</label></dt>
+ <dd><textarea id="publisher_frequency" name="publisher_frequency">${data.get('publisher_frequency','')}</textarea></dd>
+ <dd class="instructions basic">How often is IATI data refreshed? Monthly/Quarterly?</dd>
+
+ <dt><label class="field_opt" for="publisher_units">Units of Aid</label></dt>
+ <dd><textarea id="publisher_units" name="publisher_units">${data.get('publisher_units','')}</textarea></dd>
+ <dd class="instructions basic">A description of any hierarchical reporting units used and how they are applied</dd>
+
+ <dt><label class="field_opt" for="publisher_segmentation">Segmentation of Published Data</label></dt>
+ <dd><textarea id="publisher_segmentation" name="publisher_segmentation">${data.get('publisher_segmentation','')}</textarea></dd>
+ <dd class="instructions basic">Is IATI data published by country, regions?</dd>
+
+ <dt><label class="field_opt" for="publisher_refs">Data Definitions and References</label></dt>
+ <dd><textarea id="publisher_refs" name="publisher_refs">${data.get('publisher_refs','')}</textarea></dd>
+ <dd class="instructions basic">Links to guides, explanations, codelists on the publisher's own site that clarify their data</dd>
+
+ <dt><label class="field_opt" for="publisher_field_exclusions">Field Exclusions</label></dt>
+ <dd><textarea id="publisher_field_exclusions" name="publisher_field_exclusions">${data.get('publisher_field_exclusions','')}</textarea></dd>
+ <dd class="instructions basic">What fields does the publisher never use - and for what reason</dd>
+
+ <dt><label class="field_opt" for="publisher_record_exclusions">Record Exclusions</label></dt>
+ <dd><textarea id="publisher_record_exclusions" name="publisher_record_exclusions">${data.get('publisher_record_exclusions','')}</textarea></dd>
+ <dd class="instructions basic">What are the policies for excluding particular activities, or parts of an activity's data?</dd>
+
+ <dt><label class="field_opt" for="publisher_thresholds">Thresholds</label></dt>
+ <dd><textarea id="publisher_thresholds" name="publisher_thresholds">${data.get('publisher_thresholds','')}</textarea></dd>
+ <dd class="instructions basic">What are the thresholds below which data or whole activities are not published?</dd>
+
+ <dt><label class="field_opt" for="publisher_constraints">Other Constraints</label></dt>
+ <dd><textarea id="publisher_constraints" name="publisher_constraints">${data.get('publisher_constraints','')}</textarea></dd>
+ <dd class="instructions basic">Other policies that restrict full compliance with the standard</dd>
+
+ <dt><label class="field_opt" for="publisher_data_quality">Data Quality</label></dt>
+ <dd><textarea id="publisher_data_quality" name="publisher_data_quality">${data.get('publisher_data_quality','')}</textarea></dd>
+ <dd class="instructions basic">Publisher's comment on the status and accuracyof the data - audited/verified, operational/sub to change, etc</dd>
+
+ <dt><label class="field_opt" for="publisher_ui">User Interface</label></dt>
+ <dd><textarea id="publisher_ui" name="publisher_ui">${data.get('publisher_ui','')}</textarea></dd>
+ <dd class="instructions basic">Link to publisher's own public user activity interface</dd>
+ </dl>
+ </fieldset>
+
+ <fieldset>
+ <legend>Records</legend>
+ <dl py:if="data.get('packages')">
+ <py:for each="num, package in enumerate(data.get('packages'))">
+ <dt><input checked="checked" id="datasets__${num}__name" name="packages__${num}__name" type="checkbox" value="${package['name']}"/></dt>
+ <dd><label for="packages__${num}__name">${package['name']}</label></dd>
+ </py:for>
+ </dl>
+ <p py:if="not data.get('packages')">There are no records currently in this group.</p>
+ </fieldset>
+
+ <fieldset>
+ <legend>Add records</legend>
+ <dl>
+ <dt><label class="field_opt" for="packages__${len(data.get('packages', []))}__name">Dataset</label></dt>
+ <dd><input class="autocomplete-dataset" id="datasets__${len(data.get('packages', []))}__name" name="packages__${len(data.get('packages', []))}__name" type="text" /></dd>
+ </dl>
+ </fieldset>
+
+ <div class="submit">
+ <input id="save" name="save" type="submit" value="Save" />
+ </div>
+
+</form>
--- a/ckanext/iati/templates/layout_base.html Thu Sep 01 13:59:28 2011 +0100
+++ b/ckanext/iati/templates/layout_base.html Wed Sep 14 17:22:37 2011 +0100
@@ -149,7 +149,8 @@
<div id="minornavigation"><minornavigation></minornavigation></div>
- <!-- support both options for defining content -->
+ <h2 py:if="defined('page_heading')">${page_heading()}</h2>
+ <!-- support both options for defining content --><py:if test="defined('content')">
${content()}
</py:if>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/templates/package/form_iati.html Wed Sep 14 17:22:37 2011 +0100
@@ -0,0 +1,223 @@
+<form id="package-edit" method="post"
+ py:attrs="{'class':'has-errors'} if errors else {}"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <div class="error-explanation" py:if="error_summary">
+ <h3>Errors in form</h3>
+ <p>The form contains invalid entries:</p>
+ <ul>
+ <li py:for="key, error in error_summary.items()">${"%s: %s" % (key, error)}</li>
+ </ul>
+ </div>
+
+ <fieldset>
+ <legend>Basic information </legend>
+ <dl>
+ <dt><label class="field_req" for="name">Name *</label></dt>
+ <dd><input id="name" name="name" type="text" value="${data.get('name', '')}" /></dd>
+ <dd class="field_error" py:if="errors.get('name', '')">${errors.get('name', '')}</dd>
+ <dd class="instructions basic">A unique identifier for the activity record.</dd>
+ <dd class="instructions further">It should be broadly humanly readable, in the spirit of Semantic Web URIs. Only use an acronym if it is widely recognised. Renaming is possible but discouraged.</dd>
+ <dd class="hints">2+ characters, lowercase, using only 'a-z0-9' and '-_'</dd>
+ <script type="text/javascript">
+ //<![CDATA[
+ $(document).ready(function () { if (!$('#preview').length) {$("#name").focus(); } });
+ //]]>
+ </script>
+
+ <dt><label class="field_opt" for="title">Title </label></dt>
+ <dd><input id="title" name="title" type="text" value="${data.get('title', '')}" /></dd>
+ <dd class="field_error" py:if="errors.get('title', '')">${errors.get('title', '')}</dd>
+ <dd class="instructions basic">A short descriptive title for the data set.</dd>
+ <dd class="instructions further">It should not be a description though - save that for the Notes field. Do not give a trailing full stop.</dd>
+
+ <dt><label class="field_opt" for="author">Contact</label></dt>
+ <dd><input id="author" name="author" type="text" value="${data.get('author', '')}" /></dd>
+ <dd class="instructions basic">The name of the main contact, for enquiries about this particular dataset, using the e-mail address in the following field.</dd>
+
+ <dt><label class="field_opt" for="author_email">Contact e-mail</label></dt>
+ <dd><input id="author_email" name="author_email" type="text" value="${data.get('author_email', '')}" /></dd>
+
+ <dt><label class="field_opt" for="department">Department</label></dt>
+ <dd><input id="department" name="department" size="40" type="text" value="${data.get('department', '')}" /></dd>
+ </dl>
+ </fieldset>
+
+ <fieldset id="groups">
+ <legend>Publisher</legend>
+ <dl>
+ <py:for each="num, group in enumerate(data.get('groups', []))">
+ <?python
+ authorized_group = [group_authz for group_authz in c.groups_authz if group_authz['id'] == group['id']]
+ authorized_group = authorized_group[0] if authorized_group else None
+ ?>
+
+ <dt py:if="'id' in group">
+ <input type="${'checkbox' if authorized_group else 'hidden'}" name="groups__${num}__id" checked="checked" value="${group['id']}" />
+ <input type="hidden" name="groups__${num}__name" value="${group.get('name', authorized_group['name'] if authorized_group else '')}" />
+ </dt>
+ <dd py:if="'id' in group"><label for="groups__${num}__checked">${group.get('name', authorized_group['name'] if authorized_group else '')}</label></dd>
+ </py:for>
+
+ <dt>Publisher</dt>
+ <dd py:if="c.groups_available">
+ <select id="groups__${len(data.get('groups', []))}__id" name="groups__${len(data.get('groups', []))}__id">
+ <dd py:if="data.get('groups',[])">
+ <option value="" >(None)</option>
+ </dd>
+ <py:for each="group in c.groups_available">
+ <option value="${group['id']}" >${group['title']}</option>
+ </py:for>
+ </select>
+ </dd>
+ <dd py:if="not c.groups_available">Cannot add any publisher.</dd>
+ </dl>
+
+ </fieldset>
+
+ <fieldset>
+ <legend>Details</legend>
+ <dl>
+ <dt><label class="field_opt" for="country">Recipient country</label></dt>
+ <dd>
+ <py:with vars="country = data.get('country','')">
+ <select id="country" name="country">
+ <py:for each="name,id in c.countries">
+ <option value="${id}" py:attrs="{'selected': 'selected' if country == id else None}">${name}</option>
+ </py:for>
+ </select>
+ </py:with>
+ </dd>
+
+ <dt><label class="field_opt" for="donors">Donors</label></dt>
+ <dd><input id="donors" name="donors" type="text" value="${data.get('donors', '')}" /></dd>
+ <dd class="instructions basic">Separate multiple entries using commas.</dd>
+
+ <dt><label class="field_opt" for="donors_type">Donor type</label></dt>
+ <dd><input id="donors_type" name="donors_type" type="text" value="${data.get('donors_type', '')}" /></dd>
+ <dd class="instructions basic">Separate multiple entries using commas.</dd>
+
+ <dt><label class="field_opt" for="donors_country">Donor country</label></dt>
+ <dd><input id="donors_country" name="donors_country" type="text" value="${data.get('donors_country', '')}" /></dd>
+ <dd class="instructions basic">Separate multiple entries using commas.</dd>
+
+ <dt><label class="field_opt" for="record_updated">Record updated</label></dt>
+ <dd><input id="record_updated" name="record_updated" size="40" type="text" value="${data.get('record_updated', '')}" /></dd>
+ <dd class="instructions basic">Acceptable formats: 'DD/MM/YYYY HH:MM', 'DD/MM/YYYY', 'MM/YYYY', 'YYYY'.</dd>
+
+ <dt><label class="field_opt" for="data_updated">Data updated</label></dt>
+ <dd><input id="data_updated" name="data_updated" size="40" type="text" value="${data.get('data_updated', '')}"/></dd>
+ <dd class="instructions basic">Acceptable formats: 'DD/MM/YYYY HH:MM', 'DD/MM/YYYY', 'MM/YYYY', 'YYYY'.</dd>
+
+ <dt><label class="field_opt" for="license_id">License</label></dt>
+ <dd>
+ <select id="license_id" name="license_id">
+ <py:for each="licence_desc, licence_id in c.licences">
+ <option value="${licence_id}" py:attrs="{'selected': 'selected' if data.get('license_id', '') == licence_id else None}" >${licence_desc}</option>
+ </py:for>
+ </select>
+ </dd>
+ <dd class="instructions basic">The licence under which the dataset is released.</dd>
+
+ <dt><label class="field_opt" for="tags">Tags</label></dt>
+ <dd>
+ <input class="autocomplete-tag" id="tag_string" name="tag_string" size="40" type="text"
+ value="${data.get('tag_string') or ' '.join([tag['name'] for tag in data.get('tags', [])])}" />
+ </dd>
+ <dd class="field_error" py:if="errors.get('tag_string', '')">${errors.get('tag_string', '')}</dd>
+ <dd class="instructions basic">Terms that may link this dataset to similar ones. For more information on conventions, see <a href="http://wiki.okfn.org/ckan/doc/faq#TagConventions">this wiki page</a>.</dd>
+ <dd class="hints">e.g. pollution rivers water-quality</dd>
+
+ <dt><label class="field_opt" for="notes">Notes</label></dt>
+ <dd><textarea cols="60" id="notes" name="notes" rows="15">${data.get('notes', '')}</textarea></dd>
+ <dd class="instructions basic">The main description of the dataset</dd>
+ <dd class="instructions further">It is often displayed with the record title. In particular, it should start with a short sentence that describes the data set succinctly, because the first few words alone may be used in some views of the data sets.</dd>
+ <dd class="hints">You can use <a href="http://daringfireball.net/projects/markdown/syntax">Markdown formatting</a> here.</dd>
+ </dl>
+ </fieldset>
+
+ <fieldset id="resources">
+ <legend>Resources</legend>
+ <table class="flexitable">
+ <thead>
+ <tr>
+ <th class="field_req resource-url">URL*</th>
+ <th class="field_opt resource-format">Format</th>
+ <th class="field_opt resource-description">Description</th>
+ <th class="field_opt resource-hash">Hash</th>
+ </tr>
+ </thead>
+ <tbody>
+ <py:for each="num, res in enumerate(data.get('resources', []) + [{}])">
+ <tr>
+ <py:for each="col in c.resource_columns">
+ <td py:choose="" class="resource-${col}">
+ <input py:when="col == 'format'" name="resources__${num}__${col}" type="text" value="${res.get(col, '')}" class="autocomplete-format short" />
+
+ <input py:otherwise="" name="resources__${num}__${col}" type="text" value="${res.get(col, '')}" class="${'medium-width' if col == 'url' else 'short'}" />
+ </td>
+ </py:for>
+ <td class="resource-id"><input name="resources__${num}__id" type="hidden" value="${res.get('id', '')}" /></td>
+ </tr>
+ </py:for>
+ </tbody>
+ </table>
+
+ <div class="instructions basic">The files containing the data or address of the APIs for accessing it.</div>
+ <div class="instructions further"><br /><b>URL:</b> This is the Internet link directly to the data - by selecting this link in a web browser, the user will immediately download the full dataset. Note that datasets are not hosted on this site, but by the publisher of the data.<br /><b>Format:</b> This should give the file format in which the data is supplied. (i.e. IATI-XML)<br /><b>Description</b> Any information you want to add to describe the resource.<br /></div>
+ <div class="field_error" py:if="errors.get('resources', '')">Dataset resource(s) incomplete.</div>
+ </fieldset>
+
+ <fieldset>
+ <legend>Verification and Analysis </legend>
+ <dl>
+ <dt><label class="field_opt" for="activity_period">Activitiy Period</label></dt>
+ <dd>
+ <input class="short" id="activity_period-from" name="activity_period-from" type="text" value="${data.get('activity_period-from', '')}" /> -
+ <input class="short" id="activity_period-to" name="activity_period-to" type="text" value="${data.get('activity_period-to', '')}" />
+ </dd>
+ <dd class="instructions basic">Acceptable formats: 'DD/MM/YYYY HH:MM', 'DD/MM/YYYY', 'MM/YYYY', 'YYYY'.</dd>
+
+ <dt><label class="field_opt" for="activity_count">Num. Activities</label></dt>
+ <dd><input id="activity_count" name="activity_count" size="40" type="text" value="${data.get('activity_count', '')}"/></dd>
+
+ <dt><label class="field_opt" for="archive_file">Archive</label></dt>
+ <dd><input id="archive_file" name="archive_file" size="40" type="checkbox" py:attrs="{'checked': 'checked' if data.get('archive_file','') == 'yes' else None}" /></dd>
+ <py:choose>
+ <py:when test="c.is_sysadmin">
+ <dt><label class="field_opt" for="verified">Verification</label></dt>
+ <dd><input id="verified" name="verified" size="40" type="checkbox" py:attrs="{'checked': 'checked' if data.get('verified','') == 'yes' else None}" /></dd>
+
+ <dt><label class="field_opt" for="state">State</label></dt>
+ <dd>
+ <select id="state" name="state">
+ <option py:attrs="{'selected': 'selected' if data.get('state') == 'active' else None}" value="active">active</option>
+ <option py:attrs="{'selected': 'selected' if data.get('state') == 'deleted' else None}" value="deleted">deleted</option>
+ <option py:attrs="{'selected': 'selected' if data.get('state') == 'pending' else None}" value="pending">pending</option>
+ </select>
+ </dd>
+ </py:when>
+ </py:choose>
+
+ </dl>
+ </fieldset>
+
+ <hr />
+ <label for="log_message">Edit summary (briefly describe the changes you have made)</label>
+ <textarea id="log_message" name="log_message" class="short wide"></textarea>
+
+ <div class="ckan-logged-in">
+ <p>Author: ${c.author}</p>
+ </div>
+
+ <div class="submit">
+ <input id="save" name="save" type="submit" value="Save" />
+ </div>
+ <p class="hints">
+ <strong>Important:</strong> By submitting content, you agree to release your contributions
+ under the open license specified on the <a href="/license">license page</a>. Please <strong>refrain</strong> from editing this page if you are <strong>not</strong> happy to do this.
+ </p>
+
+</form>
--- a/ckanext/iati/templates/package/read_core.html Thu Sep 01 13:59:28 2011 +0100
+++ b/ckanext/iati/templates/package/read_core.html Wed Sep 14 17:22:37 2011 +0100
@@ -34,7 +34,7 @@
<div class="notes" py:if="str(c.pkg_notes_formatted).strip()">
${c.pkg_notes_formatted}
</div>
-
+
<py:choose test=""><table py:when="c.pkg.resources" width="100%"><tr><th>URL</th><th>Format</th><th>Preview</th></tr>
@@ -50,7 +50,7 @@
</table><table py:otherwise=""><tr><th>Resources</th><td>None given for this package.</td></tr></table></py:choose>
-
+
<py:def function="details_item(label, value)"><tr py:if="value is not None and len(value) > 0"><td class="package-label">
@@ -61,18 +61,18 @@
</td></tr></py:def>
-
+
<py:def function="details_asbool(label, value)"><tr><td class="package-label">
${label}
</td><td class="package-details">
- ${'yes' if value else 'no'}
+ ${'yes' if value == 'yes' else 'no'}
</td></tr></py:def>
-
+
<py:def function="details_list(label, values)"><tr py:if="values is not None and len(values) > 0"><td class="package-label" valign="top">
@@ -95,14 +95,14 @@
${details_list('Donor types', c.pkg.extras.get('donors_type', []))}
${details_list('Donor countries', [h.country_name(x) for x in c.pkg.extras.get('donors_country', [])])}
${details_item('Recipient Country', h.country_name(c.pkg.extras.get('country', '(Unknown)')))}
-
+
${details_asbool('Verified', c.pkg.extras.get('verified', False))}
${details_asbool('Archive File', c.pkg.extras.get('archive_file', False))}
${details_item('Department', c.pkg.extras.get('department', '-'))}
-
+
${details_item('Data updated', c.pkg.extras.get('data_updated', '-'))}
${details_item('Record updated', c.pkg.extras.get('record_updated', '-'))}
-
+
<tr><td class="package-label">
License
@@ -122,14 +122,18 @@
</tr></tbody></table>
-
-
-
+
+
+
<h4>Contents</h4><table width="100%"><tbody>
- ${details_item('# of Activities', c.pkg.extras.get('activity_count', '-'))}
-
+ <tr>
+ <td class="package-label"># of Activities</td>
+ <td class="package-details">
+ ${c.pkg.extras.get('activity_count', '-')}</td>
+ </tr>
+
<tr><td class="package-label">Activity Period</td><td class="package-details">
--- a/i18n/en/ckan.po Thu Sep 01 13:59:28 2011 +0100
+++ b/i18n/en/ckan.po Wed Sep 14 17:22:37 2011 +0100
@@ -930,7 +930,7 @@
#: ckan/templates/layout_base.html:99
#: ckan/templates/package/search.html:14
-msgid "Add a package"
+msgid "Add a Dataset"
msgstr "Add a record"
#: ckan/templates/layout_base.html:101
@@ -1186,7 +1186,7 @@
msgstr "Publishers History"
#: ckan/templates/group/index.html:6
-msgid "Groups of Data Packages"
+msgid "Groups of Datasets"
msgstr "Publishers"
#: ckan/templates/group/index.html:11
--- a/setup.py Thu Sep 01 13:59:28 2011 +0100
+++ b/setup.py Wed Sep 14 17:22:37 2011 +0100
@@ -31,7 +31,8 @@
iati_approval = ckanext.iati.approval:IatiGroupApprovalExtension
iati_group_authz = ckanext.iati.authz:IatiGroupAuthzExtension
iati_package_authz = ckanext.iati.authz:IatiPackageAuthzExtension
-
+ iati_forms = ckanext.iati.plugin:IatiForms
+
[ckan.forms]
iati_package = ckanext.iati.forms:get_iati_package_fieldset
iati_group = ckanext.iati.forms:get_iati_group_fieldset
http://bitbucket.org/okfn/ckanextiati/changeset/08e8d8fe9ad1/
changeset: 08e8d8fe9ad1
user: amercader
date: 2011-09-14 18:43:30
summary: Update i18n
affected #: 1 file (23 bytes)
--- a/i18n/en/ckan.po Wed Sep 14 17:22:37 2011 +0100
+++ b/i18n/en/ckan.po Wed Sep 14 17:43:30 2011 +0100
@@ -931,7 +931,7 @@
#: ckan/templates/layout_base.html:99
#: ckan/templates/package/search.html:14
msgid "Add a Dataset"
-msgstr "Add a record"
+msgstr "Register a New IATI Activity Record"
#: ckan/templates/layout_base.html:101
#: ckan/templates/home/about.html:6
http://bitbucket.org/okfn/ckanextiati/changeset/5f484113b4ef/
changeset: 5f484113b4ef
user: amercader
date: 2011-09-14 18:57:33
summary: [theme] Ensure that the theme uses the CKAN rules from the old theme
affected #: 7 files (20.9 KB)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/public/css/buttons.css Wed Sep 14 17:57:33 2011 +0100
@@ -0,0 +1,120 @@
+.buttons {
+ display: inline-block;
+}
+
+.buttons:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+}
+
+* html .buttons {
+ height: 1px;
+}
+
+.buttons img {
+ vertical-align: baseline;
+ float: none;
+}
+
+.buttons a, button {
+ display: block;
+ margin: 0 7px 0 0;
+ background-color: #f0f0f0;
+ border: 1px solid #dedede;
+ border-top: 1px solid #eee;
+ border-left: 1px solid #eee;
+ -moz-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+ font-size: 100%;
+ line-height: 1.4;
+ text-decoration: none;
+ font-weight: bold;
+ color: #565656;
+ cursor: pointer;
+ padding: 5px 10px 6px 7px;
+ background-image: url(/images/button-shadow.png);
+ background-repeat: no-repeat;
+ background-position: left top;
+}
+
+button {
+ width: auto;
+ overflow: visible;
+ padding: 4px 10px 3px 7px;
+}
+
+button[type] {
+ padding: 5px 10px 5px 7px;
+ line-height: 17px;
+}
+
+*:first-child+html button[type] {
+ padding: 4px 10px 3px 7px;
+}
+
+.buttons a.secondary, button.secondary {
+ float: right;
+}
+
+button img, .buttons a img {
+ margin: 0 3px -3px 0 !important;
+ padding: 0;
+ border: none;
+ width: 16px;
+ height: 16px;
+}
+
+button:hover, .buttons a:hover {
+ border: 1px solid #ccc;
+ color: #333;
+ background-color: #f0f0f0;
+}
+
+button:active, .buttons a:active {
+ background-image: none;
+ background-color: #888;
+ border: 1px solid #444;
+ /* override position indicator */
+ color: #fff ! important;
+}
+
+button.positive, .buttons a.positive {
+ color: #529214;
+}
+
+.buttons a.positive:hover, button.positive:hover {
+ background-image: none;
+ background-color: #e6efc2;
+ border: 1px solid #c6d880;
+ color: #529214;
+}
+
+.buttons a.positive:active {
+ background-image: none;
+ background-color: #529214;
+ border: 1px solid #529214;
+ color: #fff;
+}
+
+/* negative (cancel, delete) */
+
+.buttons a.negative, button.negative {
+ color: #d12f19;
+}
+
+.buttons a.negative:hover, button.negative:hover {
+ background-image: none;
+ background: #fbe3e4;
+ border: 1px solid #fbc2c4;
+ color: #d12f19;
+}
+
+.buttons a.negative:active {
+ background-image: none;
+ background-color: #d12f19;
+ border: 1px solid #d12f19;
+ color: #fff;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/public/css/ckan.css Wed Sep 14 17:57:33 2011 +0100
@@ -0,0 +1,1052 @@
+/* The main css styles for CKAN (specific UI elements may have thier own css linked via style.css) */
+
+body, input, textarea, .page-title span, .pingback a.url {
+ font-family: "Lucida Grande", Lucida, Verdana, sans-serif;
+}
+
+#content, #content input, #content textarea {
+ font-size: 14px;
+ line-height: 20px;
+}
+
+a {
+ color: #b00;
+ text-decoration: none;
+}
+a:link {
+ color: #b22;
+ text-decoration: none;
+}
+a:visited {
+ color: #b22;
+ text-decoration: none;
+}
+#main a:visited {
+ text-decoration: none;
+}
+
+a:active {
+ color: #f22;
+ text-decoration: none;
+}
+a:hover {
+ text-decoration: underline;
+}
+
+#content p, #content ul, #content ol, #content dd, #content pre, #content hr, #content dl {
+ margin-bottom: 14px;
+}
+
+/* ===========================
+ * Flash messages
+*/
+
+.flash-banner-box {
+ margin-top: -20px;
+ margin-bottom: 10px;
+}
+
+.flash-banner {
+ width: auto;
+ line-height: 1em;
+ font-size: 14px;
+ padding: 0.8em 1.5%;
+ font-weight: bold;
+ text-align: center;
+ border-bottom: solid 1px #9f9f9f;
+ color: #133362;
+}
+
+.flash-banner.notice {
+ background: #f4a83d;
+ border-bottom-color: #dddddd;
+}
+
+.flash-banner.success {
+ background-color: #e7f9e0;
+ border-bottom-color: #ccc;
+ color: #2d6b00;
+}
+
+.flash-banner.error {
+ background-color: #ffeae8;
+ border-bottom-color: #ccc;
+ color: #b50000;
+}
+
+/* ===========================
+ * Masthead
+*/
+
+#header {
+ padding-top: 15px;
+ padding-bottom: 5px;
+}
+
+#site-title {
+ line-height: normal;
+ width: auto;
+ float: left;
+ font-size: 40px;
+ margin: 0;
+ padding: 0 0 5px 0;
+ font-weight: normal;
+ letter-spacing: -0.032em;
+}
+
+#site-title a,
+#site-title a:link, #site-title a:visited {
+ font-weight:normal;
+ color: #333;
+}
+
+/* hide the main twentyten image */
+#branding img {
+ display:none;
+}
+
+#site-title a img {
+ background: transparent;
+ display: block;
+ border: none;
+ margin: 0;
+ max-height: 50px;
+}
+
+#site-description {
+ width:auto;
+ float: left;
+ clear: left;
+ color: #000;
+ font-style: normal;
+ font-size: 13px;
+ letter-spacing: normal;
+ text-transform: none;
+ margin: -5px 0 10px 3px;
+ padding: 0;
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode', Lucida, Arial, Helvetica, sans-serif;
+ font-family: 'Helvetica Neue', Arial, Helvetica, 'Nimbus Sans L', sans-serif;
+}
+
+/* ===========================
+ * Top Bar
+*/
+
+#top-bar {
+ text-align: right;
+}
+
+#top-bar-login {
+ max-width: 150px;
+ display: inline-block;
+}
+
+#top-bar .search-form, #top-bar .search-form form {
+}
+
+#top-bar .search-form input.search {
+ width: 120px;
+}
+
+#top-bar-login .ckan-logged-in img {
+ margin-bottom: -3px;
+}
+
+
+/* =Menu
+-------------------------------------------------------------- */
+
+#access {
+ border-top: 1px solid #aaa;
+ border-bottom: 1px solid #aaa;
+ background: transparent;
+}
+
+#access ul li a {
+ color: #b22;
+ text-decoration: none;
+ font-weight: bold;
+}
+
+#access ul li a.active {
+ color: black;
+ font-weight: bold;
+}
+
+#access ul li a:hover {
+ color: #333;
+}
+
+#access ul ul a {
+ background: #fff;
+}
+#access li:hover > a,
+#access ul ul :hover > a {
+ background: #fff;
+ color: #333;
+}
+#access ul li.current_page_item > a,
+#access ul li.current-menu-ancestor > a,
+#access ul li.current-menu-item > a,
+#access ul li.current-menu-parent > a {
+ color: #333;
+}
+* html #access ul li.current_page_item a,
+* html #access ul li.current-menu-ancestor a,
+* html #access ul li.current-menu-item a,
+* html #access ul li.current-menu-parent a,
+* html #access ul li a:hover {
+ color: #333;
+ cursor: default;
+ font-weight: bold;
+}
+
+/* ===========================
+ * Main
+ */
+
+#main {
+ padding-top: 20px;
+}
+
+#container {
+}
+
+.entry-content {
+ padding-top: 0;
+}
+
+/* ===========================
+ * Sidebar
+ */
+#primary
+{
+ padding-top:40px;
+}
+#primary .widget-container
+{
+ background: #f9f2ce;
+ color: #333;
+ margin: 0 0 1em 0;
+ padding: 10px;
+ border: 1px solid #ebd897;
+ border-left: none;
+ border-top: none;
+ border-radius: 0.5em;
+ -moz-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+}
+
+#primary .widget-container h2 {
+ margin-bottom: 10px;
+}
+
+#primary .widget-container h4 {
+ margin-bottom: 10px;
+ font-weight:bold;
+}
+
+#primary .widget-container .widget_action{
+ text-align:right;
+ margin:18px 0 0 0;
+ font-weight:bold;
+}
+
+.hide-sidebar #primary {
+ display: none;
+}
+
+.hide-sidebar #content {
+ margin: 0 20px 0 20px;
+}
+
+/* ==========================
+ * Facets
+ */
+
+.facet-box {
+
+}
+
+.facet-box h2 {
+ color: #000;
+ font-size: 1.2em;
+ font-weight: bold;
+ margin-top: 1em;
+}
+
+.facet-options {
+ margin-top: 0.5em;
+}
+
+.facet-options li {
+ padding-top: 0.2em;
+ font-size: 1.2em;
+ color: #000;
+}
+
+.register-link {
+ padding-top: 10px;
+}
+
+.register-link a {
+ color: white;
+ background: #199150;
+ font-weight: bold;
+ padding: 5px;
+ width: 100%;
+ font-size: 1.3em;
+ -moz-border-radius: 2px;
+ -webkit-border-radius: 2px;
+ border-radius: 2px;
+
+}
+
+.package-search-filters {
+ margin-top: 15px;
+}
+
+.search-field {
+ display: inline-block;
+ margin-right: 5px;
+ margin-bottom: 10px;
+ padding: 1px 1px 3px 2px;
+ font-size: 14px;
+ background-color: #eee;
+ line-height: 16px;
+ -moz-box-shadow: 1px 1px 3px #bbb;
+ -webkit-box-shadow: 1px 1px 3px #bbb;
+ box-shadow: 1px 1px 3px #bbb;
+
+}
+
+.search-field-name::after {
+ content: ":";
+}
+
+.search-field-value {
+ font-weight: bold;
+}
+
+
+/* ===========================
+ * Footer
+ */
+
+#footer {
+ border-top: 1px solid;
+ margin: 1em auto 0 auto;
+ overflow: auto;
+}
+
+#footer ul {
+ margin-top: 0;
+}
+
+#footer-widget-area .widget-area {
+ float: none;
+ width: 100%;
+ margin: 0;
+}
+
+#footer-widget-area .widget-container {
+ margin-bottom: 0;
+}
+
+#footer-widget-area .widget-container h3 {
+ display: inline-block;
+ margin-top: 0;
+ margin-right: 10px;
+ /*
+ * IE 6 & 7 don't support inline-block, but we can use the hasLayout
+ * magical property.
+ * http://blog.mozilla.com/webdev/2009/02/20/cross-browser-inline-block/
+ */
+ zoom: 1;
+ *display: inline;
+}
+
+#footer-widget-area .widget-container .textwidget {
+ display: inline;
+}
+
+
+#footer-widget-area .widget-container ul {
+ display: inline;
+ margin: 0.3em 0 0 0;
+}
+
+#footer ul li abbr {
+ border-bottom: none;
+}
+
+#footer-widget-area .widget-container ul li {
+ margin: 0 1em 0 0;
+ padding: 0;
+ display: inline-block;
+ /*
+ * IE 6 & 7 don't support inline-block, but we can use the hasLayout
+ * magical property.
+ * http://blog.mozilla.com/webdev/2009/02/20/cross-browser-inline-block/
+ */
+ zoom: 1;
+ *display: inline;
+}
+
+#footer-widget-area #fourth {
+ margin-right: 0;
+}
+
+#site-info {
+}
+
+#site-generator {
+ width: auto;
+}
+
+#site-generator a {
+ background-image: none;
+}
+
+img#footer-okf-logo {
+ margin-bottom: -4px;
+}
+
+
+/* ===========================
+ * Forms
+ */
+
+#content input, #content textarea {
+ line-height: 14px;
+ font-size: 14px;
+}
+
+form #log_message {
+ width: 80%;
+ height: 30px;
+}
+
+.entry-content label {
+ font-size: 14px;
+}
+
+#content form.ckan.package_create_form dt {
+ clear: both;
+}
+
+#content form.ckan.package_create_form dl, #content form.ckan.package_create_form dd {
+ margin-bottom: 0;
+}
+
+#content form.ckan.package_create_form select {
+ margin-bottom: 12px;
+}
+
+form.simple-form label {
+ display: inline-block;
+ float: left;
+ min-width: 40%;
+}
+
+form.simple-form fieldset input {
+ border: 1px solid #E7E7E7;
+ padding: 0.3em;
+ width: 40%;
+}
+
+form.simple-form textarea {
+ width: 99%;
+}
+
+.purge-button {
+ border: none;
+ background: none;
+ background-color: #b33a3a;
+ color: white;
+ display: block;
+ margin-bottom: 1em;
+}
+
+.purge-button:hover {
+ border: none;
+}
+
+/* ===========================
+ * Tables
+ */
+
+#content tr td {
+ padding: 6px 10px;
+}
+
+#content tr th, #content thead th {
+ padding: 6px 12px;
+}
+
+caption {
+ caption-side:bottom;
+ text-align:left;
+ font-size:0.85em;
+ line-height:1.4em;
+ padding-top:0.5em;
+ color:#888;
+ padding-left:0.8em;
+}
+
+
+
+/* ============= */
+/* = Utilities = */
+/* ============= */
+
+.clearfix:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+}
+
+.clearfix { display: inline-block; } /* for IE/Mac */
+
+.cleared { clear: both; }
+hr.cleared {
+ height: 0 ! important;
+ visibility: hidden;
+}
+
+hr.nomargin { margin: 0; }
+
+/* ======================= */
+/* = Fixes to KForge CSS = */
+/* ======================= */
+
+table {
+ border-collapse: collapse;
+ border: none;
+ border-radius: 1em;
+ margin: 0 0 1.2em 0;
+}
+
+table th, table td {
+ border: 1px solid #ccc;
+ border-top-color: #eee;
+ border-left-color: #eee;
+ padding: 0.3em;
+}
+
+table td {
+ background: #f0f0f0;
+}
+
+table th {
+ background: #fff;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode', Lucida, Arial, Helvetica, sans-serif;
+ letter-spacing: -0.02em;
+}
+
+/* ================ */
+/* = Search boxes = */
+/* ================ */
+
+form.package-search input.search {
+ width: 99%;
+ padding: 5px;
+ font-size: 1.1em;
+ margin: 0px;
+ -webkit-appearance: textfield;
+}
+
+.package-search input.button {
+ display: inline-block;
+ float: right;
+ margin-top: 5px;
+ margin-right: 10px !important;
+ margin-bottom: 1px !important;
+}
+
+/* ========================================= */
+/* = Changes/additions to kforge forms.css = */
+/* ========================================= */
+
+input.openid {
+ background: transparent url(../images/icons/openid.png) 2px 2px no-repeat;
+ padding-left: 22px;
+}
+
+input.openid:focus {
+ background-position: 1px 1px;
+ padding-left: 21px;
+}
+
+/* ============== */
+/* = Pagination = */
+/* ============== */
+
+.pager {
+ width: 100%;
+ text-align: center;
+ margin: 0 0 1.2em 0;
+ clear: both;
+}
+
+.pager span, .pager a {
+ text-decoration: none;
+ margin: 0em;
+ border: none;
+ padding: 0.3em 0.1em;
+}
+
+.pager a:hover, .pager a:active {
+ color: #fff;
+ background-color: #c22;
+}
+
+.pager span.pager_dotdot {
+ color: #aaa;
+}
+
+.pager span.pager_curpage {
+ font-weight: bold;
+ border: 1px solid #ddd;
+}
+
+/* ======================= */
+/* = Various iconography = */
+/* ======================= */
+
+img.icon {
+ height: 25px;
+}
+
+a.icon {
+ display: block;
+ height: 0;
+ overflow: hidden;
+ padding-top: 20px;
+ width: 20px;
+}
+
+table.no-margin { margin: 0; }
+
+div.extras-new-field label {
+ display: inline;
+ line-height: 2.6em;
+}
+
+label.inline {
+ display:inline;
+ margin: 1em 0 0 1em;
+}
+
+dl.icons dt {
+ float: left;
+ clear: both;
+ margin: 0.4em 0 0 0;
+ height: 16px;
+ width: 16px;
+}
+
+dl.icons dt img {
+ vertical-align: middle;
+}
+
+dl.icons dd {
+ float: left;
+ margin: 0.4em 0 0 10px;
+}
+
+dl.icons dd.tiny {
+ font-size: 75%;
+ color: #888;
+ line-height: 1.2em;
+ margin: 0 0 0 26px;
+}
+
+/* ========================= */
+/* = Tag and Group listing = */
+/* ========================= */
+
+.item-list {
+ border-top: solid 1px #cbcbcb;
+ border-bottom: solid 1px #cbcbcb;
+ margin-top: 5px;
+}
+
+.item-list ul, ul.tags {
+ margin: 0 0 0.75em 0;
+ padding:0;
+ list-style: none;
+}
+
+.item-list ul li, ul.tags li {
+ padding-left: 0;
+ padding-right: 3px;
+}
+
+.tags a {
+ text-decoration: none;
+ color: #b00;
+}
+
+.tags a:hover {
+}
+
+/* tags small is for autocomplete list in package editor */
+.tags.small a {
+ padding-left: 6px;
+ padding-right: 6px;
+}
+
+/* =================== */
+/* = Package listing = */
+/* =================== */
+
+ul.packages {
+ padding-left: 0;
+ margin: 0 0 18px 0;
+}
+
+.packages .header {
+ font-weight: bold;
+}
+
+.packages .extract {
+ font-size: 0.9em;
+ padding-top:10px;
+}
+
+.packages li {
+ list-style: none;
+ padding: 0.4em 0 0.4em 0.0em;
+ border-left: 0.5em solid #fff;
+ border-bottom: 1px solid #ececec;
+ overflow: hidden;
+ /*white-space: nowrap;*/
+}
+
+.packages li a {
+ text-decoration: none;
+}
+
+.packages li img {
+ margin-bottom: -2px;
+}
+
+.search_meta {
+ float:right;
+}
+
+ul.package_formats {
+ float:right;
+ padding:0 0 3px 0; margin:0;
+}
+
+ul.package_formats li {
+ display:inline;
+ margin:0;
+ padding:0 5px 0 5px;
+ border:none;
+ font-weight:normal;
+ font-size:0.8em;
+ color:#808080;
+ background:#ececec;
+}
+
+.openness {
+ clear:right;
+ float:right;
+ font-size:0.8em;
+}
+
+.openness img {
+ vertical-align:top;
+}
+
+.openness li {
+ margin:0;
+ padding:0;
+ border:none;
+}
+
+/*
+.packages li.fullyopen {
+ border-left: 0.5em solid #AFC6E9;
+}
+*/
+
+.packages li .tags {
+ margin: 0 0 0 0.5em;
+ font-size: 80%;
+ opacity: 0.3;
+}
+
+.packages li:hover .tags {
+ opacity: 1;
+}
+
+.packages .name,
+.packages .license {
+ color: #666;
+ font-weight: normal;
+ font-size: 0.9em;
+}
+
+/* ==================== */
+/* = Extra RHS styles = */
+/* ==================== */
+
+.sidebar dl {
+ margin: 0 1em 0.8em 1em;
+ padding: 0;
+}
+
+.sidebar hr {
+ width: 90%;
+ color: #EBDBA7;
+ background-color: #EBDBA7;
+ border: none;
+ height: 1px;
+}
+
+.sidebar .buttons {
+ margin-top: 0;
+}
+
+.sidebar .buttons a, .sidebar .buttons button {
+ margin-bottom: 0.3em;
+}
+
+.okdstripe {
+ /* Amusingly, this has to be a slightly different color to look the same
+ as the stripe on a white background */
+ border-left: 0.5em solid #8FB0DE;
+ padding-left: 0.4em ! important;
+}
+
+/* ===================== */
+/* = Package read view = */
+/* ===================== */
+
+#primary .widget-container .formats ul {
+ background: transparent;
+}
+
+#primary .widget-container .formats ul li {
+ background: transparent;
+ display: inline;
+}
+
+#content .package .subsection h3,
+#content #comments h3, #content #comments h4 {
+ background-color: #444;
+ padding: 10px;
+ color: white;
+}
+
+.package h3, .package h4 {
+ font-weight: bold;
+ margin: 1em 0 0.6em 0;
+}
+
+.package div.tags {
+ margin: 20px 0;
+}
+
+.package .resources {
+ margin-bottom: 2em;
+}
+
+.package .resources table {
+ width: 100%;
+}
+
+.package h2.head {
+ margin-bottom: 0.3em!important;
+ line-height: 1.0;
+}
+
+.package .name, .group .name {
+ color: #888;
+ font-family: monospace;
+}
+
+.package div.url {
+ margin: 0 ;
+}
+
+.package .url a {
+ text-decoration: none;
+}
+
+.package .notes, .group .description {
+ padding: 0.2em 0 0.2em 0;
+ margin: 0 3% 0.5 0 ! important;
+}
+
+.package .notes span.nonegiven {
+ opacity: 0.5;
+}
+.package .notes span.nonegiven:hover {
+ opacity: 1;
+}
+
+.package .details table {
+ border-collapse: collapse;
+ background: transparent;
+ border-color: grey;
+ border-spacing: 2px 2px;
+}
+
+.package .details table tr {
+ border: none;
+ border-bottom: solid 1px #888;
+}
+
+.package .details td {
+ background: transparent;
+ border: none;
+}
+
+.package .details td.package-label {
+ width: 150px;
+}
+
+.package .api div {
+ background:#f0f0f0;
+ padding:10px;
+}
+
+.package .api h5 {
+ font-weight:bold;
+ margin-bottom:1em!important;
+ font-size:1em;
+}
+
+.package .api code {
+ background:#444;
+ color:#fff;
+ padding:3px 10px ;
+ margin-bottom:1em;
+ display:block;
+}
+.package .api code a {
+ color:#fff;
+}
+
+.relationship_comment {
+ font-style: italic;
+}
+
+p.atom-feed-link {
+ float: right;
+ display: inline;
+ font-size: 14px;
+}
+
+p.atom-feed-link a {
+ background: url('../images/icons/atom_feed.png') no-repeat;
+ padding-left: 20px;
+}
+
+p.atom-feed-link.package-history-link {
+ float: none;
+}
+
+#revision.widget-container
+{
+ background: #f9f2ce;
+ color: #333;
+ margin: 0 0 1em 0;
+ padding: 10px;
+ border: 1px solid #ebd897;
+ border-left: none;
+ border-top: none;
+ border-radius: 0.5em;
+ -moz-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+}
+
+/* ===================== */
+/* = User Listing = */
+/* ===================== */
+
+body.user-list #content {
+ margin-right: 20px;
+}
+
+ul.userlist, ul.userlist ul {
+ list-style-type: none;
+ margin: 0;
+}
+
+ul.userlist li.user {
+ display: inline-block;
+ width: 200px;
+ padding: 5px;
+ font-size: 90%;
+ margin-bottom: 15px;
+}
+
+ul.userlist li ul span.edits {
+ color: #333;
+ font-size: 110%;
+ font-weight: bold;
+ margin-left: 3px;
+}
+
+ul.userlist li.user .username {
+}
+
+#content ul.userlist .username img {
+ margin-bottom: -3px;
+}
+
+ul.userlist .created {
+ font-size: 80%;
+}
+
+ul.userlist .badge {
+ color: #fc0;
+}
+
+body.user-list .sort {
+ float: right;
+}
+
+body.user-list .sort a {
+ font-size: 85%;
+ background: #eee;
+ padding: 5px;
+ border-bottom: 1px solid #ccc;
+ border-right: 1px solid #ccc;
+}
+
+/* ===================== */
+/* = Stateful stuff = */
+/* ===================== */
+
+.state-deleted, .state-deleted a, .state-deleted * {
+ color: rgba(0, 0, 0, 0.4);
+}
+
+.state-deleted {
+ padding-left: 3px;
+}
+
+.state-deleted:hover * {
+ color: rgba(0, 0, 0, 0.8);
+}
+
+.state-notice {
+ text-transform: uppercase;
+ font-size: 120%;
+ background: #f4a83d;
+ padding: 15px;
+ text-align: center;
+ color: #fff;
+}
--- a/ckanext/iati/public/css/overrides.css Wed Sep 14 17:43:30 2011 +0100
+++ b/ckanext/iati/public/css/overrides.css Wed Sep 14 17:57:33 2011 +0100
@@ -560,7 +560,7 @@
color:#536FA1;
}
-/*-------- Form errors --------*/
+/*-------- Form --------*/
.error-explanation {
border: 1px solid red;
@@ -574,6 +574,10 @@
color: red
}
+#content dl,
+#content dd {
+ margin-bottom: 0px;
+}
/*-------- Flash messages --------*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/public/css/stars.css Wed Sep 14 17:57:33 2011 +0100
@@ -0,0 +1,64 @@
+/* based on http://www.pmob.co.uk/temp/star-rating.htm */
+
+div.inline-rating{
+ display:-moz-inline-block;
+ display:-moz-inline-box;
+ display:inline-block;
+ /* vertical-align:middle; */
+ margin-bottom: -1px;
+}
+
+.stars{
+ width:80px;
+ height:16px;
+ margin: 0;
+ padding:0;
+ list-style:none;
+ clear:both;
+ position:relative;
+ background: url(/images/stars.png) no-repeat 0 0;
+}
+
+.default0star {background-position:0 0}
+.default1star {background-position:0 -16px}
+.default2star {background-position:0 -32px}
+.default3star {background-position:0 -48px}
+.default4star {background-position:0 -64px}
+.default5star {background-position:0 -80px}
+
+ul.stars li {
+ cursor: pointer;
+ float:left;
+ text-indent:-999em;
+}
+
+ul.stars li a {
+ position:absolute;
+ left:0;
+ top:0;
+ width:16px;
+ height:16px;
+ text-decoration:none;
+ z-index: 200;
+}
+
+ul.stars li.one a {left:0}
+ul.stars li.two a {left:16px;}
+ul.stars li.three a {left:32px;}
+ul.stars li.four a {left:48px;}
+ul.stars li.five a {left:64px;}
+
+ul.stars li a:hover {
+ z-index:2;
+ width:80px;
+ height:16px;
+ overflow:hidden;
+ left:0;
+ background: url(/images/stars.png) no-repeat 0 0
+}
+
+ul.stars li.one a:hover {background-position:0 -96px;}
+ul.stars li.two a:hover {background-position:0 -112px;}
+ul.stars li.three a:hover {background-position:0 -128px}
+ul.stars li.four a:hover {background-position:0 -144px}
+ul.stars li.five a:hover {background-position:0 -160px}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/public/css/style.ckan.css Wed Sep 14 17:57:33 2011 +0100
@@ -0,0 +1,8 @@
+/* This file is just for importing other css files */
+ at import url(http://assets.okfn.org/themes/twentyten/style.css);
+ at import url(ckan.css);
+ at import url(buttons.css);
+ at import url(stars.css);
+ at import url(tabs.css);
+ at import url(forms.css);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckanext/iati/public/css/tabs.css Wed Sep 14 17:57:33 2011 +0100
@@ -0,0 +1,63 @@
+/* @override http://localhost:5000/style/tabs.css */
+
+ul.tabbed {
+ position: relative;
+ float: left;
+ width: 100%;
+ padding: 0;
+ margin: 0 0 1em 0;
+ list-style: none;
+ line-height: 1em;
+ border-bottom: 1px solid #aaa;
+}
+
+ul.tabbed li {
+ float: left;
+ margin: 0 0 0 0.5em;
+ border-left: 1px solid #eaeaea;
+ border-top: 1px solid #eaeaea;
+ border-right: 1px solid #eaeaea;
+ -moz-border-radius: 0.4em 0.4em 0 0;
+ -webkit-border-top-left-radius: 0.4em;
+ -webkit-border-top-right-radius: 0.4em;
+}
+
+ul.tabbed a {
+ display: block;
+ color: #bbb;
+ text-decoration: none;
+ font-weight: bold;
+ background: #fff;
+ margin: 0;
+ padding: 4px 0.6em;
+}
+
+ul.tabbed li a:hover,
+ul.tabbed li a:active {
+ color: #444;
+ background: #fff;
+ border-color: #aaa;
+ border-bottom-color: #fff;
+}
+
+ul.tabbed .hidden a {
+ display: none;
+}
+
+ul.tabbed a.active,
+ul.tabbed a.active:link,
+ul.tabbed a.active:visited
+{
+ position: relative;
+ top: 1px;
+ z-index: 102;
+ color: #444;
+ background: #fff;
+ border-color: #aaa;
+ border-bottom-color: #fff;
+ display: block;
+}
+
+ul.tabbed a img {
+ margin-bottom: -2px;
+}
--- a/ckanext/iati/templates/layout_base.html Wed Sep 14 17:43:30 2011 +0100
+++ b/ckanext/iati/templates/layout_base.html Wed Sep 14 17:57:33 2011 +0100
@@ -28,7 +28,7 @@
@import url(http://openbiblio.net/wp-content/themes/twentyten/style.css);
</style><link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/themes/ui-lightness/jquery-ui.css" type="text/css" media="screen, print" />
- <link rel="stylesheet" href="/css/style.css" type="text/css" media="screen, print" />
+ <link rel="stylesheet" href="/css/style.ckan.css" type="text/css" media="screen, print" /><link rel="stylesheet" href="/css/iati.css" type="text/css" media="screen, print" /><link rel="stylesheet" href="/fonts/fonts.css" type="text/css" media="screen, print" /><link rel="stylesheet" href="/css/overrides.css" type="text/css" media="screen, print" />
@@ -149,8 +149,8 @@
<div id="minornavigation"><minornavigation></minornavigation></div>
- <h2 py:if="defined('page_heading')">${page_heading()}</h2>
- <!-- support both options for defining content -->
+ <h2 py:if="defined('page_heading')" class="page_heading">${page_heading()}</h2>
+ <!-- support both options for defining content --><py:if test="defined('content')">
${content()}
</py:if>
http://bitbucket.org/okfn/ckanextiati/changeset/76db02abad5e/
changeset: 76db02abad5e
user: amercader
date: 2011-09-14 19:33:43
summary: [forms] Fix resources table and prevent showing an ugly flash message when creating a dataset
affected #: 2 files (869 bytes)
--- a/ckanext/iati/controllers/package_iati.py Wed Sep 14 17:57:33 2011 +0100
+++ b/ckanext/iati/controllers/package_iati.py Wed Sep 14 18:33:43 2011 +0100
@@ -1,4 +1,5 @@
-from ckan.lib.base import c
+from pylons.i18n import _
+from ckan.lib.base import c, request, config, h, redirect
from ckan.lib.helpers import json
from ckan import model
from ckan.controllers.package import PackageController
@@ -71,6 +72,26 @@
def _check_data_dict(self, data_dict):
return
+ def _form_save_redirect(self, pkgname, action):
+ '''This redirects the user to the CKAN package/read page,
+ unless there is request parameter giving an alternate location,
+ perhaps an external website.
+ @param pkgname - Name of the package just edited
+ @param action - What the action of the edit was
+ '''
+ assert action in ('new', 'edit')
+ if action == 'new':
+ msg = _('IATI Record created')
+ h.flash_success(msg,allow_html=True)
+
+ url = request.params.get('return_to') or \
+ config.get('package_%s_return_url' % action)
+ if url:
+ url = url.replace('<NAME>', pkgname)
+ else:
+ url = h.url_for(controller='package', action='read', id=pkgname)
+ redirect(url)
+
# End hooks
def get_groups(self,available_only=False):
--- a/ckanext/iati/templates/package/form_iati.html Wed Sep 14 17:57:33 2011 +0100
+++ b/ckanext/iati/templates/package/form_iati.html Wed Sep 14 18:33:43 2011 +0100
@@ -146,20 +146,22 @@
<th class="field_req resource-url">URL*</th><th class="field_opt resource-format">Format</th><th class="field_opt resource-description">Description</th>
- <th class="field_opt resource-hash">Hash</th></tr></thead><tbody><py:for each="num, res in enumerate(data.get('resources', []) + [{}])"><tr>
- <py:for each="col in c.resource_columns">
- <td py:choose="" class="resource-${col}">
- <input py:when="col == 'format'" name="resources__${num}__${col}" type="text" value="${res.get(col, '')}" class="autocomplete-format short" />
+ <td class="resource-url">
+ <input name="resources__${num}__url" type="text" value="${res.get('url', '')}" class="medium-width" />
+ </td>
+ <td class="resource-format">
+ <input name="resources__${num}__format" type="text" value="${res.get('format', '')}" class="short" />
+ </td>
+ <td class="resource-description">
+ <input name="resources__${num}__description" type="text" value="${res.get('description', '')}" class="short" />
+ <input name="resources__${num}__id" type="hidden" value="${res.get('id', '')}" />
+ </td>
- <input py:otherwise="" name="resources__${num}__${col}" type="text" value="${res.get(col, '')}" class="${'medium-width' if col == 'url' else 'short'}" />
- </td>
- </py:for>
- <td class="resource-id"><input name="resources__${num}__id" type="hidden" value="${res.get('id', '')}" /></td></tr></py:for></tbody>
Repository URL: https://bitbucket.org/okfn/ckanextiati/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
More information about the ckan-changes
mailing list