[ckan-changes] [okfn/ckan] 0b3089: [2347] Implemented related dashboard with filter o...

GitHub noreply at github.com
Wed May 2 11:42:51 UTC 2012


  Branch: refs/heads/feature-2347-related-dashboard
  Home:   https://github.com/okfn/ckan
  Commit: 0b30897cd28bbc62efa2d9811cb3bff8af6627ae
      https://github.com/okfn/ckan/commit/0b30897cd28bbc62efa2d9811cb3bff8af6627ae
  Author: Ross Jones <rossdjones at gmail.com>
  Date:   2012-05-02 (Wed, 02 May 2012)

  Changed paths:
    M ckan/config/routing.py
    M ckan/controllers/related.py
    M ckan/logic/action/get.py
    R ckan/templates/_snippet/add-related.html
    M ckan/templates/_util.html
    R ckan/templates/package/related_list.html
    A ckan/templates/related/add-related.html
    A ckan/templates/related/dashboard.html
    A ckan/templates/related/related_list.html

  Log Message:
  -----------
  [2347] Implemented related dashboard with filter on type and tidied up some of the related templates


diff --git a/ckan/config/routing.py b/ckan/config/routing.py
index 43fa8fd..1ad271e 100644
--- a/ckan/config/routing.py
+++ b/ckan/config/routing.py
@@ -155,6 +155,7 @@ def make_map():
     with SubMapper(map, controller='related') as m:
         m.connect('related_list', '/dataset/{id}/related', action='list')
         m.connect('related_read', '/dataset/{id}/related/{related_id}', action='read')
+        m.connect('related_dashboard', '/apps', action='dashboard')
 
     with SubMapper(map, controller='package') as m:
         m.connect('/dataset', action='search')
diff --git a/ckan/controllers/related.py b/ckan/controllers/related.py
index 85042aa..fb6effd 100644
--- a/ckan/controllers/related.py
+++ b/ckan/controllers/related.py
@@ -4,13 +4,59 @@
 import ckan.logic as logic
 import ckan.lib.base as base
 import ckan.lib.helpers as h
+import urllib
 
 c = base.c
 
 class RelatedController(base.BaseController):
 
-    def list(self, id):
+    def dashboard(self):
+        """ List all related items regardless of dataset """
+        context = {'model': model, 'session': model.Session,
+                   'user': c.user or c.author, 'extras_as_string': True,
+                   'for_view': True}
+        data_dict = {
+            'type_filter': base.request.params.get('type', '')
+        }
+
+        params_nopage = [(k, v) for k,v in base.request.params.items()
+                         if k != 'page']
+        try:
+            page = int(base.request.params.get('page', 1))
+        except ValueError, e:
+            abort(400, ('"page" parameter must be an integer'))
+
+        # Update ordering in the context
+        query = logic.get_action('related_list')(context,data_dict)
+
+        def search_url(params):
+            url = h.url_for(controller='related', action='dashboard')
+            params = [(k, v.encode('utf-8')
+                      if isinstance(v, basestring) else str(v))
+                      for k, v in params]
+            return url + u'?' + urllib.urlencode(params)
 
+        def pager_url(q=None, page=None):
+            params = list(params_nopage)
+            params.append(('page', page))
+            return search_url(params)
+
+
+        c.page = h.Page(
+            collection=query.all(),
+            page=page,
+            url=pager_url,
+            item_count=query.count(),
+            items_per_page=8
+        )
+
+        c.filters = dict(params_nopage)
+
+        return base.render( "related/dashboard.html")
+
+
+    def list(self, id):
+        """ List all related items for a specific dataset """
         context = {'model': model, 'session': model.Session,
                    'user': c.user or c.author, 'extras_as_string': True,
                    'for_view': True}
@@ -32,5 +78,5 @@ def list(self, id):
 
         c.related_count = len(c.pkg.related)
 
-        return base.render( "package/related_list.html")
+        return base.render( "related/related_list.html")
 
diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py
index b2afe94..b0e315e 100644
--- a/ckan/logic/action/get.py
+++ b/ckan/logic/action/get.py
@@ -138,8 +138,8 @@ def related_show(context, data_dict=None):
 
 def related_list(context, data_dict=None):
     """
-    List the related items for a specific package which should be
-    mentioned in the data_dict
+    List the related items which may be for a specific package which
+    should be mentioned in the data_dict
 
     context:
         model - The CKAN model module
@@ -150,6 +150,9 @@ def related_list(context, data_dict=None):
         id - The ID of the dataset to which we want to list related items
         or
         dataset - The dataset (package) model
+
+    If neither value is in the data_dict then all related items will
+    be returned, and the ordering requested will be applied.
     """
     model = context['model']
     session = context['session']
@@ -158,14 +161,18 @@ def related_list(context, data_dict=None):
     if not dataset:
         dataset = model.Package.get(data_dict.get('id'))
 
-    if not dataset:
-        raise NotFound
-
     check_access('related_show',context, data_dict)
 
-    relateds = model.Related.get_for_dataset(dataset, status='active')
-    related_items = (r.related for r in relateds)
-    related_list = model_dictize.related_list_dictize( related_items, context)
+    related_list = []
+    if not dataset:
+        related_list = model.Session.query(model.Related)
+        tfilter = data_dict.get('type_filter', None)
+        if tfilter:
+            related_list = related_list.filter(model.Related.type == tfilter)
+    else:
+        relateds = model.Related.get_for_dataset(dataset, status='active')
+        related_items = (r.related for r in relateds)
+        related_list = model_dictize.related_list_dictize( related_items, context)
     return related_list
 
 
diff --git a/ckan/templates/_snippet/add-related.html b/ckan/templates/_snippet/add-related.html
deleted file mode 100644
index e5b2a64..0000000
--- a/ckan/templates/_snippet/add-related.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<html
-  xmlns="http://www.w3.org/1999/xhtml"
-  xmlns:i18n="http://genshi.edgewall.org/i18n"
-  xmlns:py="http://genshi.edgewall.org/"
-  xmlns:xi="http://www.w3.org/2001/XInclude"
-  py:strip=""
->
-<div class="modal-add-related modal fade in" style="display: none"
-  py:def="add_related(dataset)">
-  <div class="modal-header">
-    <a class="close" data-dismiss="modal">×</a>
-    <h3 class="heading">Add related item</h3>
-  </div>
-  <div class="modal-body">
-    <form id="form-add-related" action="" method="POST" class="well">
-      <div class="control-group">
-        <input id="related-dataset" type="hidden" name="dataset_id" value="${c.pkg.id}"/>
-        <label for="related-title">Title <span class="required">(required)</span></label>
-        <input id="related-title" name="title" class="span6" placeholder="Please add the title for the item"/>
-      </div>
-      <div class="control-group">
-        <label for="related-type">Type of item</label>
-        <select id="related-type" name="type" class="span6 chzn-select">
-          <option value="app">Application</option>
-          <option value="idea">Idea</option>
-          <option value="visualization">Visualization</option>
-        </select>
-      </div>
-      <div class="control-group">
-        <label for="related-description">Description</label>
-        <textarea id="related-description" name="description" class="input-xlarge span6" rows="4" placeholder="Please describe the item"></textarea>
-      </div>
-      <div class="control-group">
-        <label for="related-url">URL <span class="required">(required)</span></label>
-        <input id="related-url" name="url" type="url" class="span6" placeholder="Please add a url"/>
-      </div>
-      <div class="control-group">
-        <label for="related-image-url">Image URL</label>
-        <input id="related-image-url" name="image_url" type="url" class="span6" placeholder="Please add a link to the image"/>
-      </div>
-      <div>
-        <button type="submit" class="btn btn-primary">Submit</button>
-        <button type="button" class="btn" data-dismiss="modal">Cancel</button>
-      </div>
-    </form>
-  </div>
-</div>
-</html>
diff --git a/ckan/templates/_util.html b/ckan/templates/_util.html
index 5aa7c07..73f976f 100644
--- a/ckan/templates/_util.html
+++ b/ckan/templates/_util.html
@@ -125,10 +125,10 @@
   </py:def>
 
 
-  <py:def function="related_summary(related)">
+  <py:def function="related_summary(related, allow_delete)">
     <li class="span3">
       <div class="thumbnail">
-        <button py:if="c.user and (c.userobj.id == related.owner_id or h.check_access('package_update',{'id':c.pkg.id}))" class="close" onclick="related_delete('${related.id}');">×</button>
+        <button py:if="allow_delete and c.user and (c.userobj.id == related.owner_id or h.check_access('package_update',{'id':c.pkg.id}))" class="close" onclick="related_delete('${related.id}');">×</button>
         <a href="${related.url}" class="image">
           <img src="${related.image_url}" width="210" py:if="related.image_url" />
           <img src="/images/photo-placeholder.png" width="210" py:if="not related.image_url" />
diff --git a/ckan/templates/package/related_list.html b/ckan/templates/package/related_list.html
deleted file mode 100644
index baced80..0000000
--- a/ckan/templates/package/related_list.html
+++ /dev/null
@@ -1,75 +0,0 @@
-<html xmlns:py="http://genshi.edgewall.org/"
-  xmlns:i18n="http://genshi.edgewall.org/i18n"
-  xmlns:xi="http://www.w3.org/2001/XInclude"
-  xmlns:foaf="http://xmlns.com/foaf/0.1/"
-  xmlns:owl="http://www.w3.org/2002/07/owl#"
-  xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
-  xmlns:dc="http://purl.org/dc/terms/"
-  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-  xmlns:dcat="http://www.w3.org/ns/dcat#"
-  typeof="dcat:Dataset"
-  about=""
-  py:strip="">
-
-  <py:def function="body_class">no-sidebar</py:def>
-  <xi:include href="../_snippet/add-related.html" />
-
-  <py:def function="page_title">${c.pkg_dict.get('title', c.pkg_dict['name'])}
-  - Related</py:def>
-
-  <py:def function="page_heading" property="dc:title">
-    ${c.pkg_dict['title']} - Related
-  </py:def>
-
-  <div py:match="content">
-    ${add_related(c.pkg)}
-    <h3>Related items <a class="btn btn-small btn-primary pull-right" data-toggle="modal" href=".modal-add-related" py:if="c.user"><i class="icon-plus-sign icon-white"></i> Add related item</a></h3>
-    <div>
-      <div py:if="not c.pkg.related" class="span8 no-related-items">
-          There are no related items here yet<span py:if="c.user">, why not <a data-toggle="modal" href=".modal-add-related">add one</a>?</span>
-      </div>
-
-      <ul class="related-items thumbnails">
-        <py:for each="related in c.pkg.related">
-          ${related_summary(related)}
-        </py:for>
-      </ul>
-    </div>
-
-    <span class="insert-comment-thread"></span>
-  </div>
-
-  <py:def function="optional_head">
-    <script type="text/javascript" py:if="c.user">
-        function related_delete(related_id) {
-          var data = { 'id' : related_id }
-          $.ajax({
-            type: "post",
-            url: CKAN.SITE_URL + '/api/3/action/related_delete',
-            data: JSON.stringify(data),
-            success: function (data) {
-              window.location.reload();
-            },
-            error: function(err, txt, w) {
-              // This needs to be far more informative.
-              var msg = '<strong>Error:</strong> Unable to delete related item';
-              $('<div class="alert alert-error" />').html(msg).hide().prependTo($('div#main')).fadeIn();
-            }
-          });
-
-        }
-    </script>
-    <py:if test="config.get('rdf_packages')">
-      <link rel="alternate" type="application/rdf+xml" title="RDF/XML" href="${config['rdf_packages'] + '/' + c.pkg.id + '.rdf' }" />
-      <link rel="alternate" type="application/turtle" title="RDF/Turtle" href="${config['rdf_packages'] + '/' + c.pkg.id + '.ttl' }" />
-    </py:if>
-  </py:def>
-
-  <py:def function="optional_feed">
-  <link rel="alternate" type="application/atom+xml" title="Dataset History"
-    href="${h.url(controller='package', action='history', id=c.pkg.name, format='atom', days=7)}" />
-  </py:def>
-
-  <xi:include href="layout.html" />
-</html>
-
diff --git a/ckan/templates/related/add-related.html b/ckan/templates/related/add-related.html
new file mode 100644
index 0000000..e5b2a64
--- /dev/null
+++ b/ckan/templates/related/add-related.html
@@ -0,0 +1,48 @@
+<html
+  xmlns="http://www.w3.org/1999/xhtml"
+  xmlns:i18n="http://genshi.edgewall.org/i18n"
+  xmlns:py="http://genshi.edgewall.org/"
+  xmlns:xi="http://www.w3.org/2001/XInclude"
+  py:strip=""
+>
+<div class="modal-add-related modal fade in" style="display: none"
+  py:def="add_related(dataset)">
+  <div class="modal-header">
+    <a class="close" data-dismiss="modal">×</a>
+    <h3 class="heading">Add related item</h3>
+  </div>
+  <div class="modal-body">
+    <form id="form-add-related" action="" method="POST" class="well">
+      <div class="control-group">
+        <input id="related-dataset" type="hidden" name="dataset_id" value="${c.pkg.id}"/>
+        <label for="related-title">Title <span class="required">(required)</span></label>
+        <input id="related-title" name="title" class="span6" placeholder="Please add the title for the item"/>
+      </div>
+      <div class="control-group">
+        <label for="related-type">Type of item</label>
+        <select id="related-type" name="type" class="span6 chzn-select">
+          <option value="app">Application</option>
+          <option value="idea">Idea</option>
+          <option value="visualization">Visualization</option>
+        </select>
+      </div>
+      <div class="control-group">
+        <label for="related-description">Description</label>
+        <textarea id="related-description" name="description" class="input-xlarge span6" rows="4" placeholder="Please describe the item"></textarea>
+      </div>
+      <div class="control-group">
+        <label for="related-url">URL <span class="required">(required)</span></label>
+        <input id="related-url" name="url" type="url" class="span6" placeholder="Please add a url"/>
+      </div>
+      <div class="control-group">
+        <label for="related-image-url">Image URL</label>
+        <input id="related-image-url" name="image_url" type="url" class="span6" placeholder="Please add a link to the image"/>
+      </div>
+      <div>
+        <button type="submit" class="btn btn-primary">Submit</button>
+        <button type="button" class="btn" data-dismiss="modal">Cancel</button>
+      </div>
+    </form>
+  </div>
+</div>
+</html>
diff --git a/ckan/templates/related/dashboard.html b/ckan/templates/related/dashboard.html
new file mode 100644
index 0000000..fc519b7
--- /dev/null
+++ b/ckan/templates/related/dashboard.html
@@ -0,0 +1,56 @@
+<html xmlns:py="http://genshi.edgewall.org/"
+  xmlns:i18n="http://genshi.edgewall.org/i18n"
+  xmlns:xi="http://www.w3.org/2001/XInclude"
+  xmlns:foaf="http://xmlns.com/foaf/0.1/"
+  xmlns:owl="http://www.w3.org/2002/07/owl#"
+  xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+  xmlns:dc="http://purl.org/dc/terms/"
+  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+  xmlns:dcat="http://www.w3.org/ns/dcat#"
+  typeof="dcat:Dataset"
+  about=""
+  py:strip="">
+
+  <py:def function="body_class">no-sidebar</py:def>
+  <xi:include href="add-related.html" />
+
+  <py:def function="page_title">Apps</py:def>
+
+  <py:def function="page_heading" property="dc:title">
+    Applications
+  </py:def>
+
+  <div py:match="content">
+    <h4 py:if="c.page.item_count">Showing items <strong>${c.page.first_item} - ${c.page.last_item}</strong> of <strong>${c.page.item_count}</strong> related items found</h4>
+    <h4 py:if="not c.page.item_count"><strong>${c.page.item_count}</strong> related items found</h4>
+
+    <div class="well">
+        <form action="" method="get" class="form-horizontal">
+            <input type='hidden' name='page' value='1'/>
+
+            <label for="type">Filter by type</label>
+            <select name="type">
+                <option value="">All</option>
+                <option value="app" py:attrs="{'selected': 'selected' if c.filters.get('type') == 'app' else None}">Application</option>
+                <option value="idea"  py:attrs="{'selected': 'selected' if c.filters.get('type') == 'idea' else None}">Idea</option>
+                <option value="visualization"  py:attrs="{'selected': 'selected' if c.filters.get('type') == 'visualization' else None}">Visualization</option>
+            </select>
+
+            <button class="btn btn-primary pull-right">Apply</button>
+        </form>
+    </div>
+
+      <ul class="related-items thumbnails">
+        <py:for each="related in c.page.items">
+          ${related_summary(related,False)}
+        </py:for>
+      </ul>
+
+    ${c.page.pager()}
+
+    <span class="insert-comment-thread"></span>
+  </div>
+
+  <xi:include href="../layout.html" />
+</html>
+
diff --git a/ckan/templates/related/related_list.html b/ckan/templates/related/related_list.html
new file mode 100644
index 0000000..324c381
--- /dev/null
+++ b/ckan/templates/related/related_list.html
@@ -0,0 +1,75 @@
+<html xmlns:py="http://genshi.edgewall.org/"
+  xmlns:i18n="http://genshi.edgewall.org/i18n"
+  xmlns:xi="http://www.w3.org/2001/XInclude"
+  xmlns:foaf="http://xmlns.com/foaf/0.1/"
+  xmlns:owl="http://www.w3.org/2002/07/owl#"
+  xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+  xmlns:dc="http://purl.org/dc/terms/"
+  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+  xmlns:dcat="http://www.w3.org/ns/dcat#"
+  typeof="dcat:Dataset"
+  about=""
+  py:strip="">
+
+  <py:def function="body_class">no-sidebar</py:def>
+  <xi:include href="add-related.html" />
+
+  <py:def function="page_title">${c.pkg_dict.get('title', c.pkg_dict['name'])}
+  - Related</py:def>
+
+  <py:def function="page_heading" property="dc:title">
+    ${c.pkg_dict['title']} - Related
+  </py:def>
+
+  <div py:match="content">
+    ${add_related(c.pkg)}
+    <h3>Related items <a class="btn btn-small btn-primary pull-right" data-toggle="modal" href=".modal-add-related" py:if="c.user"><i class="icon-plus-sign icon-white"></i> Add related item</a></h3>
+    <div>
+      <div py:if="not c.pkg.related" class="span8 no-related-items">
+          There are no related items here yet<span py:if="c.user">, why not <a data-toggle="modal" href=".modal-add-related">add one</a>?</span>
+      </div>
+
+      <ul class="related-items thumbnails">
+        <py:for each="related in c.pkg.related">
+          ${related_summary(related, True)}
+        </py:for>
+      </ul>
+    </div>
+
+    <span class="insert-comment-thread"></span>
+  </div>
+
+  <py:def function="optional_head">
+    <script type="text/javascript" py:if="c.user">
+        function related_delete(related_id) {
+          var data = { 'id' : related_id }
+          $.ajax({
+            type: "post",
+            url: CKAN.SITE_URL + '/api/3/action/related_delete',
+            data: JSON.stringify(data),
+            success: function (data) {
+              window.location.reload();
+            },
+            error: function(err, txt, w) {
+              // This needs to be far more informative.
+              var msg = '<strong>Error:</strong> Unable to delete related item';
+              $('<div class="alert alert-error" />').html(msg).hide().prependTo($('div#main')).fadeIn();
+            }
+          });
+
+        }
+    </script>
+    <py:if test="config.get('rdf_packages')">
+      <link rel="alternate" type="application/rdf+xml" title="RDF/XML" href="${config['rdf_packages'] + '/' + c.pkg.id + '.rdf' }" />
+      <link rel="alternate" type="application/turtle" title="RDF/Turtle" href="${config['rdf_packages'] + '/' + c.pkg.id + '.ttl' }" />
+    </py:if>
+  </py:def>
+
+  <py:def function="optional_feed">
+  <link rel="alternate" type="application/atom+xml" title="Dataset History"
+    href="${h.url(controller='package', action='history', id=c.pkg.name, format='atom', days=7)}" />
+  </py:def>
+
+  <xi:include href="../package/layout.html" />
+</html>
+


================================================================



More information about the ckan-changes mailing list