Added a sample IDatasetForm to show how we can implement a custom form from a plugin.
[ckanext-datagovau.git] / ckanext / example / controller_plugin.py
blob:a/ckanext/example/controller_plugin.py -> blob:b/ckanext/example/controller_plugin.py
--- a/ckanext/example/controller_plugin.py
+++ b/ckanext/example/controller_plugin.py
@@ -1,1 +1,223 @@
-
+import logging
+from ckan.lib.base import BaseController, render, c, model, abort, request
+from ckan.lib.base import redirect, _, config, h
+import ckan.logic.action.create as create
+import ckan.logic.action.update as update
+import ckan.logic.action.get as get
+from ckan.logic.converters import date_to_db, date_to_form, convert_to_extras, convert_from_extras
+from ckan.lib.navl.dictization_functions import DataError, flatten_dict, unflatten
+from ckan.logic import NotFound, NotAuthorized, ValidationError
+from ckan.logic import tuplize_dict, clean_dict, parse_params
+from ckan.logic.schema import package_form_schema
+from ckan.plugins import IDatasetForm
+from ckan.plugins import implements, SingletonPlugin
+from ckan.lib.package_saver import PackageSaver
+from ckan.lib.field_types import DateType, DateConvertError
+from ckan.authz import Authorizer
+from ckan.lib.navl.dictization_functions import Invalid
+from ckanext.dgu.forms.package_gov_fields import GeoCoverageType
+from ckan.lib.navl.dictization_functions import validate, missing
+import ckan.logic.validators as val
+import ckan.logic.schema as default_schema
+from ckan.lib.navl.validators import (ignore_missing,
+                                      not_empty,
+                                      empty,
+                                      ignore,
+                                      keep_extras,
+                                     )
+
+log = logging.getLogger(__name__)
+
+geographic_granularity = [('', ''),
+                          ('national', 'national'),
+                          ('regional', 'regional'),
+                          ('local authority', 'local authority'),
+                          ('ward', 'ward'),
+                          ('point', 'point'),
+                          ('other', 'other - please specify')]
+
+update_frequency = [('', ''),
+                    ('never', 'never'),
+                    ('discontinued', 'discontinued'),
+                    ('annual', 'annual'),
+                    ('quarterly', 'quarterly'),
+                    ('monthly', 'monthly'),
+                    ('other', 'other - please specify')]
+
+temporal_granularity = [("",""),
+                       ("year","year"),
+                       ("quarter","quarter"),
+                       ("month","month"),
+                       ("week","week"),
+                       ("day","day"),
+                       ("hour","hour"),
+                       ("point","point"),
+                       ("other","other - please specify")]
+
+
+class ExamplePackageController(SingletonPlugin):
+
+    implements(IDatasetForm, inherit=True)
+
+    def package_form(self):
+        return 'controller/package_plugin.html'
+
+    def is_fallback(self):
+        """
+        Returns true iff this provides the fallback behaviour, when no other
+        plugin instance matches a package's type.
+
+        As this is not the fallback controller we should return False.  If 
+        we were wanting to act as the fallback, we'd return True
+        """
+        return False
+
+    def package_types(self):
+        """
+        Returns an iterable of package type strings.
+
+        If a request involving a package of one of those types is made, then
+        this plugin instance will be delegated to.
+
+        There must only be one plugin registered to each package type.  Any
+        attempts to register more than one plugin instance to a given package
+        type will raise an exception at startup.
+        """
+        return ["example"]
+
+    def _setup_template_variables(self, context, data_dict=None):
+        c.licences = [('', '')] + model.Package.get_license_options()
+        c.geographic_granularity = geographic_granularity
+        c.update_frequency = update_frequency
+        c.temporal_granularity = temporal_granularity 
+
+        c.publishers = self.get_publishers()
+
+        c.is_sysadmin = Authorizer().is_sysadmin(c.user)
+        c.resource_columns = model.Resource.get_columns()
+
+        ## This is messy as auths take domain object not data_dict
+        pkg = context.get('package') or c.pkg
+        if pkg:
+            c.auth_for_change_state = Authorizer().am_authorized(
+                c, model.Action.CHANGE_STATE, pkg)
+
+    def _form_to_db_schema(self):
+
+        schema = {
+            'title': [not_empty, unicode],
+            'name': [not_empty, unicode, val.name_validator, val.package_name_validator],
+            'notes': [not_empty, unicode],
+
+            'date_released': [date_to_db, convert_to_extras],
+            'date_updated': [date_to_db, convert_to_extras],
+            'date_update_future': [date_to_db, convert_to_extras],
+            'update_frequency': [use_other, unicode, convert_to_extras],
+            'update_frequency-other': [],
+            'precision': [unicode, convert_to_extras],
+            'geographic_granularity': [use_other, unicode, convert_to_extras],
+            'geographic_granularity-other': [],
+            'geographic_coverage': [ignore_missing, convert_geographic_to_db, convert_to_extras],
+            'temporal_granularity': [use_other, unicode, convert_to_extras],
+            'temporal_granularity-other': [],
+            'temporal_coverage-from': [date_to_db, convert_to_extras],
+            'temporal_coverage-to': [date_to_db, convert_to_extras],
+            'url': [unicode],
+            'taxonomy_url': [unicode, convert_to_extras],
+
+            'resources': default_schema.default_resource_schema(),
+            
+            'published_by': [not_empty, unicode, convert_to_extras],
+            'published_via': [ignore_missing, unicode, convert_to_extras],
+            'author': [ignore_missing, unicode],
+            'author_email': [ignore_missing, unicode],
+            'mandate': [ignore_missing, unicode, convert_to_extras],
+            'license_id': [ignore_missing, unicode],
+            'tag_string': [ignore_missing, val.tag_string_convert],
+            'national_statistic': [ignore_missing, convert_to_extras],
+            'state': [val.ignore_not_admin, ignore_missing],
+
+            'log_message': [unicode, val.no_http],
+
+            '__extras': [ignore],
+            '__junk': [empty],
+        }
+        return schema
+    
+    def _db_to_form_schema(data):
+        schema = {
+            'date_released': [convert_from_extras, ignore_missing, date_to_form],
+            'date_updated': [convert_from_extras, ignore_missing, date_to_form],
+            'date_update_future': [convert_from_extras, ignore_missing, date_to_form],
+            'update_frequency': [convert_from_extras, ignore_missing, extract_other(update_frequency)],
+            'precision': [convert_from_extras, ignore_missing],
+            'geographic_granularity': [convert_from_extras, ignore_missing, extract_other(geographic_granularity)],
+            'geographic_coverage': [convert_from_extras, ignore_missing, convert_geographic_to_form],
+            'temporal_granularity': [convert_from_extras, ignore_missing, extract_other(temporal_granularity)],
+            'temporal_coverage-from': [convert_from_extras, ignore_missing, date_to_form],
+            'temporal_coverage-to': [convert_from_extras, ignore_missing, date_to_form],
+            'taxonomy_url': [convert_from_extras, ignore_missing],
+
+            'resources': default_schema.default_resource_schema(),
+            'extras': {
+                'key': [],
+                'value': [],
+                '__extras': [keep_extras]
+            },
+            'tags': {
+                '__extras': [keep_extras]
+            },
+            
+            'published_by': [convert_from_extras, ignore_missing],
+            'published_via': [convert_from_extras, ignore_missing],
+            'mandate': [convert_from_extras, ignore_missing],
+            'national_statistic': [convert_from_extras, ignore_missing],
+            '__extras': [keep_extras],
+            '__junk': [ignore],
+        }
+        return schema
+
+    def _check_data_dict(self, data_dict):
+        return
+
+    def get_publishers(self):
+        return [('pub1', 'pub2')]
+
+
+def use_other(key, data, errors, context):
+
+    other_key = key[-1] + '-other'
+    other_value = data.get((other_key,), '').strip()
+    if other_value:
+        data[key] = other_value
+
+def extract_other(option_list):
+
+    def other(key, data, errors, context):
+        value = data[key]
+        if value in dict(option_list).keys():
+            return
+        elif value is missing:
+            data[key] = ''
+            return
+        else:
+            data[key] = 'other'
+            other_key = key[-1] + '-other'
+            data[(other_key,)] = value
+    return other
+            
+def convert_geographic_to_db(value, context):
+
+    if isinstance(value, list):
+        regions = value
+    elif value:
+        regions = [value]
+    else:
+        regions = []
+        
+    return GeoCoverageType.get_instance().form_to_db(regions)
+
+def convert_geographic_to_form(value, context):
+
+    return GeoCoverageType.get_instance().db_to_form(value)
+