From c8abe999511fb6b46279d3c4a5afd191ffc9c7c9 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Mon, 6 Feb 2012 14:51:51 +0000 Subject: [PATCH 01/13] [doc][xs]: change mercurial to git-core in instructions for additional software to install. --- doc/prepare-extensions.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/prepare-extensions.rst b/doc/prepare-extensions.rst index b0fa0856119..496c54c54d9 100644 --- a/doc/prepare-extensions.rst +++ b/doc/prepare-extensions.rst @@ -8,7 +8,9 @@ Firstly, you'll need to set up and enter a virtual Python environment, as follow :: - sudo apt-get install python-virtualenv mercurial + # install software we need (virtualenv and git to retrieve the source code) + sudo apt-get install python-virtualenv git-core + # create a python virtual env and activate virtualenv /home/ubuntu/pyenv . /home/ubuntu/pyenv/bin/activate From 9a3658ed4bf7946ee5d27f58850a287987f814e3 Mon Sep 17 00:00:00 2001 From: Ian Murray Date: Mon, 6 Feb 2012 22:08:06 +0000 Subject: [PATCH 02/13] [master][nav] Generalised tag_string_convert() Now multiple keys in the schema can contribute to the tag list. --- ckan/logic/validators.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/ckan/logic/validators.py b/ckan/logic/validators.py index 4f2392f8543..0101bc726c0 100644 --- a/ckan/logic/validators.py +++ b/ckan/logic/validators.py @@ -1,5 +1,6 @@ -import re import datetime +from itertools import count +import re from pylons.i18n import _, ungettext, N_, gettext from ckan.lib.navl.dictization_functions import Invalid, Missing, missing, unflatten from ckan.authz import Authorizer @@ -268,13 +269,17 @@ def tag_string_convert(key, data, errors, context): '''Takes a list of tags that is a comma-separated string (in data[key]) and parses tag names. These are added to the data dict, enumerated. They are also validated.''' - tag_string = data[key] - tags = [tag.strip() \ - for tag in tag_string.split(',') \ - if tag.strip()] + if isinstance(data[key], basestring): + tags = [tag.strip() \ + for tag in data[key].split(',') \ + if tag.strip()] + else: + tags = data[key] + + current_index = max( [int(k[1]) for k in data.keys() if len(k) == 3 and k[0] == 'tags'] + [-1] ) - for num, tag in enumerate(tags): + for num, tag in zip(count(current_index+1), tags): data[('tags', num, 'name')] = tag for tag in tags: From d1886aeecff85a8c60059477f8c62dc3caa6ebdc Mon Sep 17 00:00:00 2001 From: Ian Murray Date: Mon, 6 Feb 2012 22:09:13 +0000 Subject: [PATCH 03/13] [master][requires] Froze the required version of ofs. --- requires/lucid_missing.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requires/lucid_missing.txt b/requires/lucid_missing.txt index 89e2eb8cac7..a5ed111fdf0 100644 --- a/requires/lucid_missing.txt +++ b/requires/lucid_missing.txt @@ -15,7 +15,7 @@ solrpy==0.9.4 formalchemy==1.4.1 pairtree==0.7.1-T -ofs>=0.4.1 +ofs==0.4.1 apachemiddleware==0.1.1 licenses==0.6.1 From 0c60e95af1a3e38e1fc08645202172fa63d1dcee Mon Sep 17 00:00:00 2001 From: Sean Hammond Date: Tue, 7 Feb 2012 11:55:47 +0100 Subject: [PATCH 04/13] [#1743] Don't link to the deleted objects in "deleted" activities The link would either be broken or to a page for a deleted object. Old activities of other types ("created", "updated"...) will still link to the deleted object if it has since been deleted. --- ckan/templates/activity_streams/deleted_group.html | 2 +- ckan/templates/activity_streams/deleted_package.html | 2 +- ckan/templates/activity_streams/deleted_resource.html | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ckan/templates/activity_streams/deleted_group.html b/ckan/templates/activity_streams/deleted_group.html index c7a21046bfd..a36b4dddafa 100644 --- a/ckan/templates/activity_streams/deleted_group.html +++ b/ckan/templates/activity_streams/deleted_group.html @@ -9,7 +9,7 @@ ${activity_stream_activity( actor=h.linked_user(activity.user_id), verb='deleted', - object="the group "+h.group_link(activity.data.group), + object="the group "+activity.data.group.name, activity=activity )} diff --git a/ckan/templates/activity_streams/deleted_package.html b/ckan/templates/activity_streams/deleted_package.html index 0c56596dfb8..d580b3c6e7b 100644 --- a/ckan/templates/activity_streams/deleted_package.html +++ b/ckan/templates/activity_streams/deleted_package.html @@ -9,6 +9,6 @@ ${activity_stream_activity( actor=h.linked_user(activity.user_id), verb='deleted', - object="the dataset "+h.dataset_link(activity.data.package), + object="the dataset "+h.dataset_display_name(activity.data.package), activity=activity)} diff --git a/ckan/templates/activity_streams/deleted_resource.html b/ckan/templates/activity_streams/deleted_resource.html index 29fb0a3bb2d..7fbaf9d77b0 100644 --- a/ckan/templates/activity_streams/deleted_resource.html +++ b/ckan/templates/activity_streams/deleted_resource.html @@ -9,8 +9,7 @@ ${activity_stream_activity( actor=h.linked_user(activity.user_id), verb='deleted', - object='the resource '+h.resource_link(detail.data.resource, - activity.data.package.id), + object='the resource '+h.resource_display_name(detail.data.resource), target='from the dataset '+h.dataset_link(activity.data.package), activity=activity )} From 495d94466a542d4daf2f3018ff311d2189b70b9a Mon Sep 17 00:00:00 2001 From: Sean Hammond Date: Tue, 7 Feb 2012 11:58:58 +0100 Subject: [PATCH 05/13] Make activity date formats consistent with date formats elsewhere on the site. Everyone should be using the render_datetime() helper and if they really want a different date format, still user render_datetime() but pass their own date_format arg. --- ckan/templates/_util.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ckan/templates/_util.html b/ckan/templates/_util.html index 6142b80ceda..a4c42730fcf 100644 --- a/ckan/templates/_util.html +++ b/ckan/templates/_util.html @@ -474,7 +474,7 @@ - ${h.render_datetime(activity.timestamp, '%B %d %Y')} + ${h.render_datetime(activity.timestamp)} From 8f059edf279ec3d184c35bfc29f794a34c9e02fc Mon Sep 17 00:00:00 2001 From: David Read Date: Tue, 7 Feb 2012 10:59:16 +0000 Subject: [PATCH 06/13] [master][1783][xs]: Avoid issue with foreign chars being passed into hash function as unicode. --- ckan/lib/hash.py | 2 +- ckan/tests/lib/test_hash.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 ckan/tests/lib/test_hash.py diff --git a/ckan/lib/hash.py b/ckan/lib/hash.py index 8aae27ae3b8..7fa52331912 100644 --- a/ckan/lib/hash.py +++ b/ckan/lib/hash.py @@ -12,7 +12,7 @@ def get_message_hash(value): # avoid getting config value at module scope since config may # not be read in yet secret = config['beaker.session.secret'] - return hmac.new(secret, value, hashlib.sha1).hexdigest() + return hmac.new(secret, value.encode('utf8'), hashlib.sha1).hexdigest() def get_redirect(): '''Checks the return_to value against the hash, and if it diff --git a/ckan/tests/lib/test_hash.py b/ckan/tests/lib/test_hash.py new file mode 100644 index 00000000000..45002bccfee --- /dev/null +++ b/ckan/tests/lib/test_hash.py @@ -0,0 +1,16 @@ +from nose.tools import assert_equals + +from ckan.lib.hash import get_message_hash, get_redirect + +class TestHash: + @classmethod + def setup_class(cls): + global secret + secret = '42' # so that these tests are repeatable + + def test_get_message_hash(self): + assert_equals(get_message_hash(u'/tag/country-uk'), '6f58ff51b42e6b2d2e700abd1a14c9699e115c61') + + def test_get_message_hash_unicode(self): + assert_equals(get_message_hash(u'/tag/biocombust\xedveis'), 'd748fa890eb6a964cd317e6ff62905fad645b43d') + From 61c01e614514fa499884a21488aadbad7a41bca8 Mon Sep 17 00:00:00 2001 From: David Read Date: Tue, 7 Feb 2012 11:00:26 +0000 Subject: [PATCH 07/13] [master][noticket][xs]: Removed unused test code. --- ckan/tests/functional/api/base.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ckan/tests/functional/api/base.py b/ckan/tests/functional/api/base.py index eb28a343b53..82165d0dcf4 100644 --- a/ckan/tests/functional/api/base.py +++ b/ckan/tests/functional/api/base.py @@ -278,13 +278,6 @@ def _ref_group(cls, group): assert cls.ref_group_by in ['id', 'name'] return getattr(group, cls.ref_group_by) - @classmethod - def _list_package_refs(cls, packages): - return [getattr(p, cls.ref_package_by) for p in packages] - - @classmethod - def _list_group_refs(cls, groups): - return [getattr(p, cls.ref_group_by) for p in groups] class Api1TestCase(Api1and2TestCase): From 072786c4095f54daa957ebdfaf87f1b9757ba162 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Tue, 7 Feb 2012 11:48:28 +0000 Subject: [PATCH 08/13] [#1396,template][xs]: fix check for about being empty and switch to using h.render_datetime rather than our hand-crafted rendering. --- ckan/controllers/user.py | 2 -- ckan/templates/user/read.html | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ckan/controllers/user.py b/ckan/controllers/user.py index 4deaf17a1a8..7a0cf3389bb 100644 --- a/ckan/controllers/user.py +++ b/ckan/controllers/user.py @@ -103,8 +103,6 @@ def read(self, id=None): c.about_formatted = self._format_about(user_dict['about']) c.user_activity_stream = user_activity_list_html(context, {'id':c.user_dict['id']}) - - c.created_formatted = h.date_str_to_datetime(user_dict['created']).strftime('%b %d, %Y') return render('user/read.html') def me(self): diff --git a/ckan/templates/user/read.html b/ckan/templates/user/read.html index ed5fb1661b9..835b87abc2f 100644 --- a/ckan/templates/user/read.html +++ b/ckan/templates/user/read.html @@ -31,8 +31,8 @@
Member since
-
${c.created_formatted}
- +
${h.render_datetime(c.user_dict['created'])}
+
About
${c.about_formatted}
From 2acab36f3b643793306f2f078d52000931914688 Mon Sep 17 00:00:00 2001 From: Sean Hammond Date: Tue, 7 Feb 2012 12:28:54 +0100 Subject: [PATCH 09/13] Tweak activity streams HTML and CSS --- ckan/public/css/style.css | 14 +++++++------- ckan/templates/_util.html | 4 ++-- ckan/templates/activity_streams/added_tag.html | 2 +- ckan/templates/activity_streams/changed_group.html | 2 +- .../activity_streams/changed_package.html | 2 +- .../activity_streams/changed_package_extra.html | 2 +- .../activity_streams/changed_resource.html | 2 +- ckan/templates/activity_streams/changed_user.html | 2 +- ckan/templates/activity_streams/deleted_group.html | 2 +- .../activity_streams/deleted_package.html | 2 +- .../activity_streams/deleted_package_extra.html | 2 +- .../activity_streams/deleted_resource.html | 2 +- ckan/templates/activity_streams/new_group.html | 2 +- ckan/templates/activity_streams/new_package.html | 2 +- .../activity_streams/new_package_extra.html | 2 +- ckan/templates/activity_streams/new_resource.html | 2 +- ckan/templates/activity_streams/new_user.html | 2 +- ckan/templates/activity_streams/removed_tag.html | 2 +- ckan/templates/user/read.html | 4 +++- ckan/tests/functional/test_activity.py | 2 +- 20 files changed, 29 insertions(+), 27 deletions(-) diff --git a/ckan/public/css/style.css b/ckan/public/css/style.css index b22627c0281..394ddba620f 100644 --- a/ckan/public/css/style.css +++ b/ckan/public/css/style.css @@ -1527,30 +1527,30 @@ body.authz form button { /* = Activity Streams = */ /* ==================== */ -.activity-stream-activity { +.activity-stream .activity { padding-bottom:1em; } -.activity-stream-activity a { +.activity-stream .activity a { font-weight:bold; } -.activity-stream-activity .actor { +.activity-stream .activity .actor { } -.activity-stream-activity .verb { +.activity-stream .activity .verb { background-color:PapayaWhip; padding:.25em; margin:.25em; } -.activity-stream-activity .object { +.activity-stream .activity .object { } -.activity-stream-activity .target { +.activity-stream .activity .target { } -.activity-stream-activity .date { +.activity-stream .activity .date { color:#999; } diff --git a/ckan/templates/_util.html b/ckan/templates/_util.html index a4c42730fcf..2dfde706850 100644 --- a/ckan/templates/_util.html +++ b/ckan/templates/_util.html @@ -451,8 +451,8 @@ -
+
${actor} diff --git a/ckan/templates/activity_streams/added_tag.html b/ckan/templates/activity_streams/added_tag.html index c90d7b18d62..7a92899dbac 100644 --- a/ckan/templates/activity_streams/added_tag.html +++ b/ckan/templates/activity_streams/added_tag.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='added', object="the tag "+h.tag_link(detail.data.tag), diff --git a/ckan/templates/activity_streams/changed_group.html b/ckan/templates/activity_streams/changed_group.html index 0aba79a7f36..32e8d87f9b1 100644 --- a/ckan/templates/activity_streams/changed_group.html +++ b/ckan/templates/activity_streams/changed_group.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='updated', object="the group "+h.group_link(activity.data.group), diff --git a/ckan/templates/activity_streams/changed_package.html b/ckan/templates/activity_streams/changed_package.html index 94faf4fc8fd..e80c83dab7b 100644 --- a/ckan/templates/activity_streams/changed_package.html +++ b/ckan/templates/activity_streams/changed_package.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='updated', object="the dataset "+h.dataset_link(activity.data.package), diff --git a/ckan/templates/activity_streams/changed_package_extra.html b/ckan/templates/activity_streams/changed_package_extra.html index 8d3a1c43837..6f213e7a597 100644 --- a/ckan/templates/activity_streams/changed_package_extra.html +++ b/ckan/templates/activity_streams/changed_package_extra.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='changed', object='the extra "'+detail.data.package_extra.key+'"', diff --git a/ckan/templates/activity_streams/changed_resource.html b/ckan/templates/activity_streams/changed_resource.html index 4e374fca74b..576ab16df9a 100644 --- a/ckan/templates/activity_streams/changed_resource.html +++ b/ckan/templates/activity_streams/changed_resource.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='updated', object='the resource '+h.resource_link(detail.data.resource, diff --git a/ckan/templates/activity_streams/changed_user.html b/ckan/templates/activity_streams/changed_user.html index f33395ac7d2..3205f365368 100644 --- a/ckan/templates/activity_streams/changed_user.html +++ b/ckan/templates/activity_streams/changed_user.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='updated their profile.', activity=activity diff --git a/ckan/templates/activity_streams/deleted_group.html b/ckan/templates/activity_streams/deleted_group.html index a36b4dddafa..66f45550f9b 100644 --- a/ckan/templates/activity_streams/deleted_group.html +++ b/ckan/templates/activity_streams/deleted_group.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='deleted', object="the group "+activity.data.group.name, diff --git a/ckan/templates/activity_streams/deleted_package.html b/ckan/templates/activity_streams/deleted_package.html index d580b3c6e7b..4413e645017 100644 --- a/ckan/templates/activity_streams/deleted_package.html +++ b/ckan/templates/activity_streams/deleted_package.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='deleted', object="the dataset "+h.dataset_display_name(activity.data.package), diff --git a/ckan/templates/activity_streams/deleted_package_extra.html b/ckan/templates/activity_streams/deleted_package_extra.html index 5f2bc972841..abc43eead81 100644 --- a/ckan/templates/activity_streams/deleted_package_extra.html +++ b/ckan/templates/activity_streams/deleted_package_extra.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='deleted', object='the extra "'+detail.data.package_extra.key+'"', diff --git a/ckan/templates/activity_streams/deleted_resource.html b/ckan/templates/activity_streams/deleted_resource.html index 7fbaf9d77b0..09e3233f816 100644 --- a/ckan/templates/activity_streams/deleted_resource.html +++ b/ckan/templates/activity_streams/deleted_resource.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='deleted', object='the resource '+h.resource_display_name(detail.data.resource), diff --git a/ckan/templates/activity_streams/new_group.html b/ckan/templates/activity_streams/new_group.html index 0f5cb35645c..9ff83bab89a 100644 --- a/ckan/templates/activity_streams/new_group.html +++ b/ckan/templates/activity_streams/new_group.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='created', object="the group "+h.group_link(activity.data.group), diff --git a/ckan/templates/activity_streams/new_package.html b/ckan/templates/activity_streams/new_package.html index cce9cfa23af..b09f3ee4dc2 100644 --- a/ckan/templates/activity_streams/new_package.html +++ b/ckan/templates/activity_streams/new_package.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='created', object="the dataset "+h.dataset_link(activity.data.package), diff --git a/ckan/templates/activity_streams/new_package_extra.html b/ckan/templates/activity_streams/new_package_extra.html index 550f412847f..a811dd656ea 100644 --- a/ckan/templates/activity_streams/new_package_extra.html +++ b/ckan/templates/activity_streams/new_package_extra.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='added', object='the extra "'+detail.data.package_extra.key+'"', diff --git a/ckan/templates/activity_streams/new_resource.html b/ckan/templates/activity_streams/new_resource.html index 46e1e805920..a86f60138e9 100644 --- a/ckan/templates/activity_streams/new_resource.html +++ b/ckan/templates/activity_streams/new_resource.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='added', object='the resource '+h.resource_link(detail.data.resource, diff --git a/ckan/templates/activity_streams/new_user.html b/ckan/templates/activity_streams/new_user.html index aef2cc82289..e480e1d7149 100644 --- a/ckan/templates/activity_streams/new_user.html +++ b/ckan/templates/activity_streams/new_user.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='signed up.', activity=activity diff --git a/ckan/templates/activity_streams/removed_tag.html b/ckan/templates/activity_streams/removed_tag.html index 6376caf7861..9b2eef3d2f8 100644 --- a/ckan/templates/activity_streams/removed_tag.html +++ b/ckan/templates/activity_streams/removed_tag.html @@ -6,7 +6,7 @@ py:strip="" > -${activity_stream_activity( +${activity_div( actor=h.linked_user(activity.user_id), verb='removed', object="the tag "+h.tag_link(detail.data.tag), diff --git a/ckan/templates/user/read.html b/ckan/templates/user/read.html index ed5fb1661b9..d2efb976113 100644 --- a/ckan/templates/user/read.html +++ b/ckan/templates/user/read.html @@ -69,7 +69,9 @@

Datasets

Public Activity

- ${c.user_activity_stream} +
+ ${c.user_activity_stream} +
diff --git a/ckan/tests/functional/test_activity.py b/ckan/tests/functional/test_activity.py index 796c44bd6d3..fcc9d317c07 100644 --- a/ckan/tests/functional/test_activity.py +++ b/ckan/tests/functional/test_activity.py @@ -201,5 +201,5 @@ def test_activity(self): # By now we've created >15 activities, but only the latest 15 should # appear on the page. result = self.app.get(offset, status=200) - assert result.body.count('
') \ + assert result.body.count('
') \ == 15 From ad599eacb1fa8c62bc45afe73f130b1ab65f2d3e Mon Sep 17 00:00:00 2001 From: David Read Date: Tue, 7 Feb 2012 11:59:38 +0000 Subject: [PATCH 10/13] [master][1783][xs]: Fix hash tests - obviously the hash is not universally determinable. --- ckan/tests/lib/test_hash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ckan/tests/lib/test_hash.py b/ckan/tests/lib/test_hash.py index 45002bccfee..e24dd19b2b3 100644 --- a/ckan/tests/lib/test_hash.py +++ b/ckan/tests/lib/test_hash.py @@ -9,8 +9,8 @@ def setup_class(cls): secret = '42' # so that these tests are repeatable def test_get_message_hash(self): - assert_equals(get_message_hash(u'/tag/country-uk'), '6f58ff51b42e6b2d2e700abd1a14c9699e115c61') + assert_equals(len(get_message_hash(u'/tag/country-uk')), len('6f58ff51b42e6b2d2e700abd1a14c9699e115c61')) def test_get_message_hash_unicode(self): - assert_equals(get_message_hash(u'/tag/biocombust\xedveis'), 'd748fa890eb6a964cd317e6ff62905fad645b43d') + assert_equals(len(get_message_hash(u'/tag/biocombust\xedveis')), len('d748fa890eb6a964cd317e6ff62905fad645b43d')) From ed0d130c233fb56d163d12c688463f5507f0174a Mon Sep 17 00:00:00 2001 From: David Read Date: Tue, 7 Feb 2012 18:46:15 +0000 Subject: [PATCH 11/13] [master][noticket][xs]: Docstring addded. --- ckan/lib/base.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ckan/lib/base.py b/ckan/lib/base.py index 501dc7f7233..753dcc2ffa4 100644 --- a/ckan/lib/base.py +++ b/ckan/lib/base.py @@ -87,6 +87,18 @@ def __before__(self, action, **params): i18n.handle_request(request, c) def _identify_user(self): + ''' + Identifies the user using two methods: + a) If he has logged into the web interface then repoze.who will + set REMOTE_USER. + b) For API calls he may set a header with his API key. + If the user is identified then: + c.user = user name (unicode) + c.author = user name + otherwise: + c.user = None + c.author = user\'s IP address (unicode) + ''' # see if it was proxied first c.remote_addr = request.environ.get('HTTP_X_FORWARDED_FOR', '') if not c.remote_addr: @@ -98,7 +110,7 @@ def _identify_user(self): c.user = c.user.decode('utf8') c.userobj = model.User.by_name(c.user) if c.userobj is None: - # This occurs when you are logged in with openid, clean db + # This occurs when you are logged in, clean db # and then restart i.e. only really for testers. There is no # user object, so even though repoze thinks you are logged in # and your cookie has ckan_display_name, we need to force user From fe6829e163a0e4878c2c701b05c8f6bf2c1c2e4d Mon Sep 17 00:00:00 2001 From: David Read Date: Tue, 7 Feb 2012 18:46:53 +0000 Subject: [PATCH 12/13] [master][#1786][lib/dictization]: Fix relationships getting lost when editing the package. --- ckan/lib/dictization/model_save.py | 12 ++++++++---- ckan/tests/functional/test_package.py | 27 +++++++++++++++++++++++++++ doc/apiv3.rst | 2 +- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/ckan/lib/dictization/model_save.py b/ckan/lib/dictization/model_save.py index e0bf7c9c297..ab62f8db6ae 100644 --- a/ckan/lib/dictization/model_save.py +++ b/ckan/lib/dictization/model_save.py @@ -281,10 +281,14 @@ def package_dict_save(pkg_dict, context): package_tag_list_save(pkg_dict.get("tags", []), pkg, context) package_membership_list_save(pkg_dict.get("groups", []), pkg, context) - subjects = pkg_dict.get('relationships_as_subject', []) - relationship_list_save(subjects, pkg, 'relationships_as_subject', context) - objects = pkg_dict.get('relationships_as_object', []) - relationship_list_save(subjects, pkg, 'relationships_as_object', context) + # relationships are not considered 'part' of the package, so only + # process this if the key is provided + if 'relationships_as_subject' in pkg_dict: + subjects = pkg_dict.get('relationships_as_subject', []) + relationship_list_save(subjects, pkg, 'relationships_as_subject', context) + if 'relationships_as_object' in pkg_dict: + objects = pkg_dict.get('relationships_as_object', []) + relationship_list_save(objects, pkg, 'relationships_as_object', context) extras = package_extras_save(pkg_dict.get("extras", []), pkg, context) diff --git a/ckan/tests/functional/test_package.py b/ckan/tests/functional/test_package.py index 81c67d93a2d..170e5fbbac5 100644 --- a/ckan/tests/functional/test_package.py +++ b/ckan/tests/functional/test_package.py @@ -1016,6 +1016,33 @@ def test_edit_indexerror(self): plugins.unload('synchronous_search') SolrSettings.init(solr_url) + def test_edit_pkg_with_relationships(self): + # 1786 + try: + # add a relationship to a package + pkg = model.Package.by_name(self.editpkg_name) + anna = model.Package.by_name(u'annakarenina') + model.repo.new_revision() + pkg.add_relationship(u'depends_on', anna) + model.repo.commit_and_remove() + + # check relationship before the test + rels = model.Package.by_name(self.editpkg_name).get_relationships() + assert_equal(str(rels), '[<*PackageRelationship editpkgtest depends_on annakarenina>]') + + # edit the package + self.offset = url_for(controller='package', action='edit', id=self.editpkg_name) + self.res = self.app.get(self.offset) + fv = self.res.forms['dataset-edit'] + fv['title'] = u'New Title' + res = fv.submit('save') + + # check relationship still exists + rels = model.Package.by_name(self.editpkg_name).get_relationships() + assert_equal(str(rels), '[<*PackageRelationship editpkgtest depends_on annakarenina>]') + + finally: + self._reset_data() class TestNew(TestPackageForm): pkg_names = [] diff --git a/doc/apiv3.rst b/doc/apiv3.rst index 6843628ed7d..99b1b816f47 100644 --- a/doc/apiv3.rst +++ b/doc/apiv3.rst @@ -150,7 +150,7 @@ license_id "cc-by" ID of the licens extras [] tags ["government-spending"] List of tags associated with this dataset. groups ["spending", "country-uk"] List of groups this dataset is a member of. -relationships_as_subject [] List of relationships (edit this only using relationship specific command). The 'type' of the relationship is described in terms of this package being the subject and the related package being the object. +relationships_as_subject [] List of relationships. The 'type' of the relationship is described in terms of this package being the subject and the related package being the object. state active May be ``deleted`` or other custom states like ``pending``. revision_id "f645243a-7334-44e2-b87c-64231700a9a6" (Read-only) ID of the last revision for the core package object was (doesn't include tags, groups, extra fields, relationships). revision_timestamp "2010-12-21T15:26:17.345502" (Read-only) Time and date when the last revision for the core package object was (doesn't include tags, groups, extra fields, relationships). ISO format. UTC timezone assumed. From ed6ddf098293b20137db10f32972321adafcf27f Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Wed, 8 Feb 2012 09:52:22 +0000 Subject: [PATCH 13/13] [master,ux][s]: improve rendering of datetime in frontend by updating h.render_datetime (now like Feb 10, 2010). * Also have generic option to add hours/mins (with_hours) * Default is now without hours/min so had to update various templates to reflect this (and a few tests) --- ckan/lib/helpers.py | 6 +++++- ckan/templates/_util.html | 2 +- ckan/templates/package/history.html | 2 +- ckan/templates/package/read.html | 4 ++-- ckan/tests/functional/test_package.py | 7 +++---- ckan/tests/lib/test_helpers.py | 4 ++-- 6 files changed, 14 insertions(+), 11 deletions(-) diff --git a/ckan/lib/helpers.py b/ckan/lib/helpers.py index 3dc42483dfd..d8141278773 100644 --- a/ckan/lib/helpers.py +++ b/ckan/lib/helpers.py @@ -281,11 +281,15 @@ def pager(self, *args, **kwargs): ) return super(Page, self).pager(*args, **kwargs) -def render_datetime(datetime_, date_format='%Y-%m-%d %H:%M'): +def render_datetime(datetime_, date_format=None, with_hours=False): '''Render a datetime object or timestamp string as a pretty string (Y-m-d H:m). If timestamp is badly formatted, then a blank string is returned. ''' + if not date_format: + date_format = '%b %d, %Y' + if with_hours: + date_format += ', %H:%M' if isinstance(datetime_, datetime.datetime): return datetime_.strftime(date_format) elif isinstance(datetime_, basestring): diff --git a/ckan/templates/_util.html b/ckan/templates/_util.html index 6142b80ceda..64fc1594cc3 100644 --- a/ckan/templates/_util.html +++ b/ckan/templates/_util.html @@ -384,7 +384,7 @@
- ${h.render_datetime(revision.timestamp)} + ${h.render_datetime(revision.timestamp, with_hours=True)} ${h.linked_user(revision.author)} diff --git a/ckan/templates/package/history.html b/ckan/templates/package/history.html index c35f97f50ba..595835aa122 100644 --- a/ckan/templates/package/history.html +++ b/ckan/templates/package/history.html @@ -47,7 +47,7 @@

${rev['id'][:4]}… - ${h.render_datetime(rev['timestamp'])} + ${h.render_datetime(rev['timestamp'], with_hours=True)} ${h.linked_user(rev['author'])} ${rev['message']} diff --git a/ckan/templates/package/read.html b/ckan/templates/package/read.html index c5dad62261e..2682e9f7d4d 100644 --- a/ckan/templates/package/read.html +++ b/ckan/templates/package/read.html @@ -84,8 +84,8 @@

Related Datasets

-

This is an old revision of this dataset, as edited at ${h.render_datetime(c.pkg_revision_timestamp)}. It may differ significantly from the current revision.

-

This is the current revision of this dataset, as edited at ${h.render_datetime(c.pkg_revision_timestamp)}.

+

This is an old revision of this dataset, as edited at ${h.render_datetime(c.pkg_revision_timestamp, with_hours=True)}. It may differ significantly from the current revision.

+

This is the current revision of this dataset, as edited at ${h.render_datetime(c.pkg_revision_timestamp, with_hours=True)}.

diff --git a/ckan/tests/functional/test_package.py b/ckan/tests/functional/test_package.py index 81c67d93a2d..18b7c3a3aca 100644 --- a/ckan/tests/functional/test_package.py +++ b/ckan/tests/functional/test_package.py @@ -503,7 +503,7 @@ def test_read_revision1(self): side_html = self.named_div('sidebar', res) print 'MAIN', main_html assert 'This is an old revision of this dataset' in main_html - assert 'at 2011-01-01 00:00' in main_html + assert 'at Jan 01, 2011, 00:00' in main_html self.check_named_element(main_html, 'a', 'href="/dataset/%s"' % self.pkg_name) print 'PKG', pkg_html assert 'title1' in res @@ -521,7 +521,7 @@ def test_read_revision2(self): side_html = self.named_div('sidebar', res) print 'MAIN', main_html assert 'This is an old revision of this dataset' in main_html - assert 'at 2011-01-02 00:00' in main_html + assert 'at Jan 02, 2011, 00:00' in main_html self.check_named_element(main_html, 'a', 'href="/dataset/%s"' % self.pkg_name) print 'PKG', pkg_html assert 'title2' in res @@ -540,7 +540,7 @@ def test_read_revision3(self): print 'MAIN', main_html assert 'This is an old revision of this dataset' not in main_html assert 'This is the current revision of this dataset' in main_html - assert 'at 2011-01-03 00:00' in main_html + assert 'at Jan 03, 2011, 00:00' in main_html self.check_named_element(main_html, 'a', 'href="/dataset/%s"' % self.pkg_name) print 'PKG', pkg_html assert 'title3' in res @@ -1421,7 +1421,6 @@ def test_4_history_revision_package_link(self): res = res.click(href=url) main_html = self.main_div(res) assert 'This is an old revision of this dataset' in main_html - assert 'at %s' % str(self.revision_timestamps[1])[:6] in main_html class TestMarkdownHtmlWhitelist(TestPackageForm): diff --git a/ckan/tests/lib/test_helpers.py b/ckan/tests/lib/test_helpers.py index da44820867b..2500c64b69e 100644 --- a/ckan/tests/lib/test_helpers.py +++ b/ckan/tests/lib/test_helpers.py @@ -22,11 +22,11 @@ def test_extract_markdown(self): def test_render_datetime(self): res = h.render_datetime(datetime.datetime(2008, 4, 13, 20, 40, 20, 123456)) - assert_equal(res, '2008-04-13 20:40') + assert_equal(res, 'Apr 13, 2008') def test_render_datetime_but_from_string(self): res = h.render_datetime('2008-04-13T20:40:20.123456') - assert_equal(res, '2008-04-13 20:40') + assert_equal(res, 'Apr 13, 2008') def test_render_datetime_blank(self): res = h.render_datetime(None)