From 0b30897cd28bbc62efa2d9811cb3bff8af6627ae Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Wed, 2 May 2012 12:42:33 +0100 Subject: [PATCH 001/100] [2347] Implemented related dashboard with filter on type and tidied up some of the related templates --- ckan/config/routing.py | 1 + ckan/controllers/related.py | 50 ++++++++++++++++- ckan/logic/action/get.py | 23 +++++--- ckan/templates/_util.html | 4 +- .../{_snippet => related}/add-related.html | 0 ckan/templates/related/dashboard.html | 56 +++++++++++++++++++ .../{package => related}/related_list.html | 6 +- 7 files changed, 125 insertions(+), 15 deletions(-) rename ckan/templates/{_snippet => related}/add-related.html (100%) create mode 100644 ckan/templates/related/dashboard.html rename ckan/templates/{package => related}/related_list.html (95%) diff --git a/ckan/config/routing.py b/ckan/config/routing.py index 43fa8fd9e1f..1ad271e9c76 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 85042aaa8eb..fb6effdd5ee 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 b2afe947171..b0e315e789d 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/_util.html b/ckan/templates/_util.html index 5aa7c077c7e..73f976ffea1 100644 --- a/ckan/templates/_util.html +++ b/ckan/templates/_util.html @@ -125,10 +125,10 @@ - +
  • @@ -70,6 +70,6 @@

    Related items - + From db36db63dd994cd1ea84bf294e8b756c0bd41bab Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Wed, 2 May 2012 15:07:55 +0100 Subject: [PATCH 002/100] [2347] Added support for sorting by view count, or creation date --- ckan/config/routing.py | 2 +- ckan/controllers/related.py | 25 ++++++++++++++++++++++++- ckan/logic/action/get.py | 19 ++++++++++++++++--- ckan/model/related.py | 1 + ckan/templates/_util.html | 5 +++-- ckan/templates/related/dashboard.html | 15 ++++++++++++++- 6 files changed, 59 insertions(+), 8 deletions(-) diff --git a/ckan/config/routing.py b/ckan/config/routing.py index 1ad271e9c76..dee0f514bef 100644 --- a/ckan/config/routing.py +++ b/ckan/config/routing.py @@ -154,7 +154,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_read', '/apps/{id}', action='read') m.connect('related_dashboard', '/apps', action='dashboard') with SubMapper(map, controller='package') as m: diff --git a/ckan/controllers/related.py b/ckan/controllers/related.py index fb6effdd5ee..3519ad26dd4 100644 --- a/ckan/controllers/related.py +++ b/ckan/controllers/related.py @@ -16,7 +16,8 @@ def dashboard(self): 'user': c.user or c.author, 'extras_as_string': True, 'for_view': True} data_dict = { - 'type_filter': base.request.params.get('type', '') + 'type_filter': base.request.params.get('type', ''), + 'sort': base.request.params.get('sort', '') } params_nopage = [(k, v) for k,v in base.request.params.items() @@ -54,6 +55,28 @@ def pager_url(q=None, page=None): return base.render( "related/dashboard.html") + def read(self, id): + context = {'model': model, 'session': model.Session, + 'user': c.user or c.author, 'extras_as_string': True, + 'for_view': True} + data_dict = {'id': id} + + try: + logic.check_access('related_show', context, data_dict) + except logic.NotAuthorized: + abort(401, _('Not authorized to see this page')) + + related = model.Session.query(model.Related).\ + filter(model.Related.id == id).first() + if not related: + abort(404, _('The requested related item was not found')) + + related.view_count += 1 + model.Session.add(related) + model.Session.commit() + + base.redirect(related.url) + def list(self, id): """ List all related items for a specific dataset """ diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py index b0e315e789d..2227e4db199 100644 --- a/ckan/logic/action/get.py +++ b/ckan/logic/action/get.py @@ -166,9 +166,22 @@ def related_list(context, data_dict=None): 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) + + filter_on_type = data_dict.get('type_filter', None) + if filter_on_type: + related_list = related_list.filter(model.Related.type == filter_on_type) + + sort = data_dict.get('sort', None) + if sort: + sortables = { + 'view_count_asc' : model.Related.view_count.asc, + 'view_count_desc': model.Related.view_count.desc, + 'created_asc' : model.Related.created.asc, + 'created_desc': model.Related.created.desc, + } + s = sortables.get(sort, None) + if s: + related_list = related_list.order_by( s() ) else: relateds = model.Related.get_for_dataset(dataset, status='active') related_items = (r.related for r in relateds) diff --git a/ckan/model/related.py b/ckan/model/related.py index df2d5890317..c7f093ee1a2 100644 --- a/ckan/model/related.py +++ b/ckan/model/related.py @@ -16,6 +16,7 @@ meta.Column('url', meta.UnicodeText), meta.Column('created', meta.DateTime, default=datetime.datetime.now), meta.Column('owner_id', meta.UnicodeText), + meta.Column('view_count', meta.Integer, default=0) ) related_dataset_table = meta.Table('related_dataset', meta.metadata, diff --git a/ckan/templates/_util.html b/ckan/templates/_util.html index 73f976ffea1..1d75af8ae2c 100644 --- a/ckan/templates/_util.html +++ b/ckan/templates/_util.html @@ -129,15 +129,16 @@
  • - + + ${related.view_count}
    ${h.markdown_extract(related.title, extract_length=30)}
    ${h.markdown_extract(related.description, extract_length=1000)}
    No description for this item -

    View this related item

    +

    View this related item

  • diff --git a/ckan/templates/related/dashboard.html b/ckan/templates/related/dashboard.html index fc519b7baec..029b7416b32 100644 --- a/ckan/templates/related/dashboard.html +++ b/ckan/templates/related/dashboard.html @@ -25,7 +25,7 @@

    Showing items ${c.page.first_item} - ${c.p

    ${c.page.item_count} related items found

    -
    + @@ -36,6 +36,19 @@

    ${c.page.item_count} related + + + + +

    From 5a97413dd61e905624dcb1fae95d4cbe180ea5c5 Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Thu, 3 May 2012 09:08:12 +0100 Subject: [PATCH 003/100] [2347] viewcount migration and related on user page --- ckan/controllers/user.py | 1 + ckan/lib/dictization/model_dictize.py | 7 +++++++ ckan/migration/versions/058_add_related_viewcount.py | 11 +++++++++++ ckan/templates/user/read.html | 8 ++++++-- 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 ckan/migration/versions/058_add_related_viewcount.py diff --git a/ckan/controllers/user.py b/ckan/controllers/user.py index d17df6fc410..d836a459c06 100644 --- a/ckan/controllers/user.py +++ b/ckan/controllers/user.py @@ -91,6 +91,7 @@ def read(self, id=None): except NotAuthorized: abort(401, _('Not authorized to see this page')) + context['with_related'] = True try: user_dict = get_action('user_show')(context,data_dict) except NotFound: diff --git a/ckan/lib/dictization/model_dictize.py b/ckan/lib/dictization/model_dictize.py index 74aa8b78877..d95950c9a5f 100644 --- a/ckan/lib/dictization/model_dictize.py +++ b/ckan/lib/dictization/model_dictize.py @@ -355,6 +355,13 @@ def user_dictize(user, context): result_dict['number_of_edits'] = user.number_of_edits() result_dict['number_administered_packages'] = user.number_administered_packages() + model = context['model'] + session = model.Session + + if context.get('with_related'): + result_dict['related_items'] = session.query(model.Related).\ + filter(model.Related.owner_id==user.id).all() + return result_dict def task_status_dictize(task_status, context): diff --git a/ckan/migration/versions/058_add_related_viewcount.py b/ckan/migration/versions/058_add_related_viewcount.py new file mode 100644 index 00000000000..f85493ee66e --- /dev/null +++ b/ckan/migration/versions/058_add_related_viewcount.py @@ -0,0 +1,11 @@ +from sqlalchemy import * +from migrate import * + +def upgrade(migrate_engine): + migrate_engine.execute(''' + ALTER TABLE "related" + ADD COLUMN view_count int NOT NULL DEFAULT 0; + + UPDATE related SET view_count=0 WHERE view_count IS NULL; + ''' + ) diff --git a/ckan/templates/user/read.html b/ckan/templates/user/read.html index 681f0dbf701..91b14c1abee 100644 --- a/ckan/templates/user/read.html +++ b/ckan/templates/user/read.html @@ -1,7 +1,7 @@ - + ${c.user_dict['display_name']} - User ${h.linked_gravatar(c.user_dict['email_hash'],48)} @@ -14,7 +14,7 @@ - +
    @@ -58,6 +58,10 @@ ${c.user_dict['number_of_edits']} Edits

  • +
  • + ${len(c.user_dict['related_items'])} + Related items +
  • From 6002a53a6be3c9a1d9a5940a05377d7f8233d5bc Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Thu, 3 May 2012 11:39:13 +0100 Subject: [PATCH 004/100] [2347] Restrict updates/create of related featured flag to admins for now --- ckan/logic/action/create.py | 6 ++++++ ckan/logic/action/update.py | 5 +++++ ckan/logic/schema.py | 1 + ckan/templates/related/dashboard.html | 2 +- 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ckan/logic/action/create.py b/ckan/logic/action/create.py index aee73a32aa4..5da99b6db83 100644 --- a/ckan/logic/action/create.py +++ b/ckan/logic/action/create.py @@ -1,6 +1,7 @@ import logging from pylons.i18n import _ +import ckan.authz as authz import ckan.lib.plugins as lib_plugins import ckan.logic as logic import ckan.rating as ratings @@ -126,6 +127,11 @@ def related_create(context, data_dict): model.Session.rollback() raise ValidationError(errors, error_summary(errors)) + # Only sys admins can update a related item to make it 1 + if not authz.Authorizer().is_sysadmin(unicode(user)): + data['featured'] = 0 + + related = model_save.related_dict_save(data, context) if not context.get('defer_commit'): model.repo.commit_and_remove() diff --git a/ckan/logic/action/update.py b/ckan/logic/action/update.py index cd5aa2fe8da..3b839d0a07d 100644 --- a/ckan/logic/action/update.py +++ b/ckan/logic/action/update.py @@ -4,6 +4,7 @@ from pylons.i18n import _ from vdm.sqlalchemy.base import SQLAlchemySession +import ckan.authz as authz import ckan.plugins as plugins import ckan.logic as logic import ckan.logic.schema @@ -120,6 +121,10 @@ def related_update(context, data_dict): model.Session.rollback() raise ValidationError(errors, error_summary(errors)) + # Only sys admins can update a related item to make it 1 + if not authz.Authorizer().is_sysadmin(unicode(user)): + data['featured'] = 0 + related = model_save.related_dict_save(data, context) if not context.get('defer_commit'): model.repo.commit() diff --git a/ckan/logic/schema.py b/ckan/logic/schema.py index 09ffe2217ae..4c174e7af27 100644 --- a/ckan/logic/schema.py +++ b/ckan/logic/schema.py @@ -245,6 +245,7 @@ def default_related_schema(): 'url': [ignore_missing, unicode], 'owner_id': [not_empty, unicode], 'created': [ignore], + 'featured': [ignore_missing, unicode], } return schema diff --git a/ckan/templates/related/dashboard.html b/ckan/templates/related/dashboard.html index aa1f0fb2fe6..39b4664be3c 100644 --- a/ckan/templates/related/dashboard.html +++ b/ckan/templates/related/dashboard.html @@ -14,7 +14,7 @@ no-sidebar - Apps + Application Applications From 7cc252d7d5d3c3b7a892f756e8443cc599e7de3c Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Thu, 3 May 2012 14:10:26 +0100 Subject: [PATCH 005/100] [2347] Added activity for creating of related items --- ckan/logic/action/create.py | 23 ++++++++++++++++++- ckan/logic/action/get.py | 6 +++++ ckan/logic/validators.py | 15 ++++++++++++ .../activity_streams/new_related_item.html | 13 +++++++++++ ckan/templates/related/add-related.html | 2 +- ckan/templates/related/dashboard.html | 2 +- 6 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 ckan/templates/activity_streams/new_related_item.html diff --git a/ckan/logic/action/create.py b/ckan/logic/action/create.py index 5da99b6db83..84f99211bd2 100644 --- a/ckan/logic/action/create.py +++ b/ckan/logic/action/create.py @@ -116,6 +116,7 @@ def resource_create(context, data_dict): def related_create(context, data_dict): model = context['model'] + session = context['session'] user = context['user'] userobj = model.User.get(user) @@ -141,10 +142,30 @@ def related_create(context, data_dict): dataset.related.append( related ) model.repo.commit_and_remove() + session.flush() + + related_dict = model_dictize.related_dictize(related, context) + activity_dict = { + 'user_id': userobj.id, + 'object_id': related.id, + 'activity_type': 'new related item', + } + activity_dict['data'] = { + 'related': related_dict + } + activity_create_context = { + 'model': model, + 'user': user, + 'defer_commit':True, + 'session': session + } + activity_create(activity_create_context, activity_dict, ignore_auth=True) + session.commit() + context["related"] = related context["id"] = related.id log.debug('Created object %s' % str(related.title)) - return model_dictize.related_dictize(related, context) + return related_dict def package_relationship_create(context, data_dict): diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py index 4d26f89ccab..0cc18d77891 100644 --- a/ckan/logic/action/get.py +++ b/ckan/logic/action/get.py @@ -1245,6 +1245,11 @@ def render_new_package_activity(context, activity): return render('activity_streams/new_package.html', extra_vars = {'activity': activity}) +def render_new_related_activity(context, activity): + return render('activity_streams/new_related_item.html', + extra_vars = {'activity': activity, + 'type': activity['data']['related']['type']}) + def render_deleted_package_activity(context, activity): return render('activity_streams/deleted_package.html', extra_vars = {'activity': activity}) @@ -1347,6 +1352,7 @@ def render_deleted_group_activity(context, activity): 'new group' : render_new_group_activity, 'changed group' : render_changed_group_activity, 'deleted group' : render_deleted_group_activity, + 'new related item': render_new_related_activity } def _activity_list_to_html(context, activity_stream): diff --git a/ckan/logic/validators.py b/ckan/logic/validators.py index 58c69ee3aef..3ca2e100529 100644 --- a/ckan/logic/validators.py +++ b/ckan/logic/validators.py @@ -114,6 +114,20 @@ def group_id_exists(group_id, context): raise Invalid('%s: %s' % (_('Not found'), _('Group'))) return group_id + +def related_id_exists(related_id, context): + """Raises Invalid if the given related_id does not exist in the model + given in the context, otherwise returns the given related_id. + + """ + model = context['model'] + session = context['session'] + + result = session.query(model.Related).get(related_id) + if not result: + raise Invalid('%s: %s' % (_('Not found'), _('Related'))) + return related_id + def group_id_or_name_exists(reference, context): """ Raises Invalid if a group identified by the name or id cannot be found. @@ -146,6 +160,7 @@ def activity_type_exists(activity_type): 'new group' : group_id_exists, 'changed group' : group_id_exists, 'deleted group' : group_id_exists, + 'new related item': related_id_exists } def object_id_validator(key, activity_dict, errors, context): diff --git a/ckan/templates/activity_streams/new_related_item.html b/ckan/templates/activity_streams/new_related_item.html new file mode 100644 index 00000000000..be0690782f7 --- /dev/null +++ b/ckan/templates/activity_streams/new_related_item.html @@ -0,0 +1,13 @@ + +${ h.activity_div( + template=_("{actor} created the %s {object}"), + activity=activity, + actor=h.linked_user(activity.user_id), + object=h.link_to(activity.data.related['title'], h.url_for(controller='related', action='read', id=activity.data.related['id'])) + ) % type} + diff --git a/ckan/templates/related/add-related.html b/ckan/templates/related/add-related.html index e5b2a64a1a3..fdda87d0ee3 100644 --- a/ckan/templates/related/add-related.html +++ b/ckan/templates/related/add-related.html @@ -21,7 +21,7 @@

    Add related item

    diff --git a/ckan/templates/related/dashboard.html b/ckan/templates/related/dashboard.html index 39b4664be3c..7149cd6b58d 100644 --- a/ckan/templates/related/dashboard.html +++ b/ckan/templates/related/dashboard.html @@ -31,7 +31,7 @@

    ${c.page.item_count} related From 3eac5416da57d42a4b5ee9ae48b30efffbfc9f6b Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Thu, 3 May 2012 15:30:07 +0100 Subject: [PATCH 006/100] [2347] Added activity for deleting related items --- ckan/logic/action/delete.py | 25 +++++++++++++++++++ ckan/logic/action/get.py | 7 +++++- ckan/logic/validators.py | 3 ++- .../deleted_related_item.html | 14 +++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 ckan/templates/activity_streams/deleted_related_item.html diff --git a/ckan/logic/action/delete.py b/ckan/logic/action/delete.py index c806a5113cd..1084f4707ec 100644 --- a/ckan/logic/action/delete.py +++ b/ckan/logic/action/delete.py @@ -3,11 +3,13 @@ import ckan.logic import ckan.logic.action import ckan.plugins as plugins +import ckan.lib.dictization.model_dictize as model_dictize # define some shortcuts ValidationError = ckan.logic.ValidationError NotFound = ckan.logic.NotFound check_access = ckan.logic.check_access +get_action = ckan.logic.get_action def package_delete(context, data_dict): @@ -65,8 +67,12 @@ def package_relationship_delete(context, data_dict): model.repo.commit() def related_delete(context, data_dict): + import ckan.logic.action as action + model = context['model'] + session = context['session'] user = context['user'] + userobj = model.User.get(user) id = data_dict['id'] entity = model.Related.get(id) @@ -76,6 +82,25 @@ def related_delete(context, data_dict): check_access('related_delete',context, data_dict) + related_dict = model_dictize.related_dictize(entity, context) + activity_dict = { + 'user_id': userobj.id, + 'object_id': entity.id, + 'activity_type': 'deleted related item', + } + activity_dict['data'] = { + 'related': related_dict + } + activity_create_context = { + 'model': model, + 'user': user, + 'defer_commit':True, + 'session': session + } + + get_action('activity_create')(activity_create_context, activity_dict, ignore_auth=True) + session.commit() + entity.delete() model.repo.commit() diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py index 0cc18d77891..a45b90c63f3 100644 --- a/ckan/logic/action/get.py +++ b/ckan/logic/action/get.py @@ -1262,6 +1262,10 @@ def render_changed_resource_activity(context, activity, detail): return render('activity_streams/changed_resource.html', extra_vars = {'activity': activity, 'detail': detail}) +def render_deleted_related_activity(context, activity): + return render('activity_streams/deleted_related_item.html', + extra_vars = {'activity': activity}) + def render_deleted_resource_activity(context, activity, detail): return render('activity_streams/deleted_resource.html', extra_vars = {'activity': activity, 'detail': detail}) @@ -1352,7 +1356,8 @@ def render_deleted_group_activity(context, activity): 'new group' : render_new_group_activity, 'changed group' : render_changed_group_activity, 'deleted group' : render_deleted_group_activity, - 'new related item': render_new_related_activity + 'new related item': render_new_related_activity, + 'deleted related item': render_deleted_related_activity } def _activity_list_to_html(context, activity_stream): diff --git a/ckan/logic/validators.py b/ckan/logic/validators.py index 3ca2e100529..3f58a78df37 100644 --- a/ckan/logic/validators.py +++ b/ckan/logic/validators.py @@ -160,7 +160,8 @@ def activity_type_exists(activity_type): 'new group' : group_id_exists, 'changed group' : group_id_exists, 'deleted group' : group_id_exists, - 'new related item': related_id_exists + 'new related item': related_id_exists, + 'deleted related item': related_id_exists } def object_id_validator(key, activity_dict, errors, context): diff --git a/ckan/templates/activity_streams/deleted_related_item.html b/ckan/templates/activity_streams/deleted_related_item.html new file mode 100644 index 00000000000..bf615e1ad2c --- /dev/null +++ b/ckan/templates/activity_streams/deleted_related_item.html @@ -0,0 +1,14 @@ + +${h.activity_div( + template=_("{actor} deleted the related item {object}"), + activity=activity, + actor=h.linked_user(activity.user_id), + object=activity.data.related.title, + )} + From da04077f943dfd83354b74097c5aa09d9ef7fcbc Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Fri, 4 May 2012 09:56:17 +0100 Subject: [PATCH 007/100] [2347] Added config option to hide related and documented it --- ckan/templates/package/layout.html | 3 +-- doc/configuration.rst | 11 +++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ckan/templates/package/layout.html b/ckan/templates/package/layout.html index 3646d0f5a5d..ae63355a17f 100644 --- a/ckan/templates/package/layout.html +++ b/ckan/templates/package/layout.html @@ -34,8 +34,7 @@ -
  • ${h.subnav_link(h.icon('package') + _('Related') + ' (%s)' % c.related_count, controller='related', action='list', id=c.pkg.name)}
  • - +
  • ${h.subnav_link(h.icon('package') + _('Related') + ' (%s)' % c.related_count, controller='related', action='list', id=c.pkg.name)}
  • |
  • diff --git a/doc/configuration.rst b/doc/configuration.rst index 7bcc74701e3..728cbecda24 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -122,6 +122,17 @@ This sets a space-separated list of extra field key values which will not be sho .. index:: single: rdf_packages +package_show_related +^^^^^^^^^^^^^^^^^^^^ + +package_show_related:: + + package_show_related = 0 + +Default value: 1 + +When set to 0 this setting will hide the related item tab on the package read page. If the value is not set, or is set to 1, then the related item tab will shown. + rdf_packages ^^^^^^^^^^^^ From eeb1cc954e0cc7604edbdcc6fb3a95d3b91c5f73 Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Fri, 4 May 2012 10:51:14 +0100 Subject: [PATCH 008/100] [2347] Add a url validator to the related schema --- ckan/logic/schema.py | 7 ++++--- ckan/logic/validators.py | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/ckan/logic/schema.py b/ckan/logic/schema.py index 4c174e7af27..8bcbdfd998b 100644 --- a/ckan/logic/schema.py +++ b/ckan/logic/schema.py @@ -37,7 +37,8 @@ user_id_exists, object_id_validator, activity_type_exists, - tag_not_in_vocabulary) + tag_not_in_vocabulary, + url_validator) from formencode.validators import OneOf import ckan.model @@ -241,8 +242,8 @@ def default_related_schema(): 'title': [not_empty, unicode], 'description': [ignore_missing, unicode], 'type': [not_empty, unicode], - 'image_url': [ignore_missing, unicode], - 'url': [ignore_missing, unicode], + 'image_url': [ignore_missing, unicode, url_validator], + 'url': [ignore_missing, unicode, url_validator], 'owner_id': [not_empty, unicode], 'created': [ignore], 'featured': [ignore_missing, unicode], diff --git a/ckan/logic/validators.py b/ckan/logic/validators.py index 3f58a78df37..9451d4d06db 100644 --- a/ckan/logic/validators.py +++ b/ckan/logic/validators.py @@ -492,3 +492,23 @@ def tag_not_in_vocabulary(key, tag_dict, errors, context): (tag_name, vocabulary_id)) else: return + +def url_validator(key, data, errors, context): + """ Checks that the provided value (if it is present) is a valid URL """ + import urlparse + import string + + model = context['model'] + session = context['session'] + + url = data.get(key, None) + if not url: + return + + pieces = urlparse.urlparse(url) + if all([pieces.scheme, pieces.netloc]) and \ + set(pieces.netloc) <= set(string.letters + string.digits + '-.') and \ + pieces.scheme in ['http', 'https']: + return + + errors[key].append(_('Please provide a valid URL')) From d2ea8735a3d01a8135c7635b83f204c92712b878 Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Fri, 4 May 2012 11:05:53 +0100 Subject: [PATCH 009/100] [2347] Following advice from tobes to use h.bool to allow use or more than 1 or 0 in ini file --- ckan/templates/package/layout.html | 2 +- doc/configuration.rst | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ckan/templates/package/layout.html b/ckan/templates/package/layout.html index ae63355a17f..5ff630a88ef 100644 --- a/ckan/templates/package/layout.html +++ b/ckan/templates/package/layout.html @@ -34,7 +34,7 @@ -
  • ${h.subnav_link(h.icon('package') + _('Related') + ' (%s)' % c.related_count, controller='related', action='list', id=c.pkg.name)}
  • +
  • ${h.subnav_link(h.icon('package') + _('Related') + ' (%s)' % c.related_count, controller='related', action='list', id=c.pkg.name)}
  • |
  • diff --git a/doc/configuration.rst b/doc/configuration.rst index 728cbecda24..523323c0ce2 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -127,11 +127,11 @@ package_show_related package_show_related:: - package_show_related = 0 + package_show_related = false -Default value: 1 +Default value: true -When set to 0 this setting will hide the related item tab on the package read page. If the value is not set, or is set to 1, then the related item tab will shown. +When set to false, or no, this setting will hide the related item tab on the package read page. If the value is not set, or is set to true or yes, then the related item tab will shown. rdf_packages ^^^^^^^^^^^^ From 45336e342fc1a0dd6a469d67c0438296a2dc6513 Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Fri, 4 May 2012 11:14:37 +0100 Subject: [PATCH 010/100] [2347] Fixing up naming --- ckan/templates/package/layout.html | 2 +- doc/configuration.rst | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ckan/templates/package/layout.html b/ckan/templates/package/layout.html index 5ff630a88ef..f196b37e9e7 100644 --- a/ckan/templates/package/layout.html +++ b/ckan/templates/package/layout.html @@ -34,7 +34,7 @@ -
  • ${h.subnav_link(h.icon('package') + _('Related') + ' (%s)' % c.related_count, controller='related', action='list', id=c.pkg.name)}
  • +
  • ${h.subnav_link(h.icon('package') + _('Related') + ' (%s)' % c.related_count, controller='related', action='list', id=c.pkg.name)}
  • |
  • diff --git a/doc/configuration.rst b/doc/configuration.rst index 523323c0ce2..ac2f45e20e1 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -122,12 +122,12 @@ This sets a space-separated list of extra field key values which will not be sho .. index:: single: rdf_packages -package_show_related -^^^^^^^^^^^^^^^^^^^^ +ckan.dataset.show_related +^^^^^^^^^^^^^^^^^^^^^^^^^ -package_show_related:: +ckan.dataset.show_related:: - package_show_related = false + ckan.dataset.show_related = false Default value: true From 8c73fbcda5de09db39efb4469c4e22b0812db87d Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Wed, 9 May 2012 10:46:34 +0100 Subject: [PATCH 011/100] [2347] Use auth check in template for add button and make sure related_create for publisher auth is accurate --- ckan/logic/action/create.py | 3 ++- ckan/logic/auth/publisher/create.py | 16 +++++++++++++--- ckan/templates/related/related_list.html | 4 ++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/ckan/logic/action/create.py b/ckan/logic/action/create.py index 0bc3110016a..2b44b5e2884 100644 --- a/ckan/logic/action/create.py +++ b/ckan/logic/action/create.py @@ -121,6 +121,8 @@ def related_create(context, data_dict): user = context['user'] userobj = model.User.get(user) + check_access('related_create', context, data_dict) + data_dict["owner_id"] = userobj.id data, errors = validate(data_dict, ckan.logic.schema.default_related_schema(), @@ -133,7 +135,6 @@ def related_create(context, data_dict): if not authz.Authorizer().is_sysadmin(unicode(user)): data['featured'] = 0 - related = model_save.related_dict_save(data, context) if not context.get('defer_commit'): model.repo.commit_and_remove() diff --git a/ckan/logic/auth/publisher/create.py b/ckan/logic/auth/publisher/create.py index d1bece7ebaf..a5112a599fe 100644 --- a/ckan/logic/auth/publisher/create.py +++ b/ckan/logic/auth/publisher/create.py @@ -25,10 +25,20 @@ def related_create(context, data_dict=None): user = context['user'] userobj = model.User.get( user ) - if userobj: - return {'success': True} + if not userobj: + return {'success': False, 'msg': _('You must be logged in to add a related item')} + + if 'dataset_id' in data_dict: + # If this is to be associated with a dataset then we need to make sure that + # the user doing so is a member of that group + dataset = model.Package.get(data_dict['dataset_id']) + if dataset and not _groups_intersect( userobj.get_groups(), + dataset.get_groups() ): + return {'success': False, + 'msg': _('You do not have permission to create an item')} + + return {'success': True } - return {'success': False, 'msg': _('You must be logged in to add a related item')} def resource_create(context, data_dict): diff --git a/ckan/templates/related/related_list.html b/ckan/templates/related/related_list.html index 4d18838fc28..f97872fb440 100644 --- a/ckan/templates/related/related_list.html +++ b/ckan/templates/related/related_list.html @@ -23,10 +23,10 @@
    ${add_related(c.pkg)} -

    Related items Add related item

    +

    Related items Add related item

    diff --git a/ckan/templates/package/layout.html b/ckan/templates/package/layout.html index 24b340bcc6f..a5425a4031c 100644 --- a/ckan/templates/package/layout.html +++ b/ckan/templates/package/layout.html @@ -34,7 +34,7 @@ -
  • ${h.subnav_link(h.icon('package') + _('Related') + ' (%s)' % c.related_count, controller='related', action='list', id=c.pkg.name)}
  • +
  • ${h.subnav_link(h.icon('package') + _('Apps & Ideas') + ' (%s)' % c.related_count, controller='related', action='list', id=c.pkg.name)}
  • ${h.subnav_link(h.icon('page_stack') + _('History'), controller='package', action='history', id=c.pkg.name)}
  • ${h.subnav_link( diff --git a/ckan/templates/related/add-related.html b/ckan/templates/related/add-related.html index f7396720d8b..1e5f23e49d5 100644 --- a/ckan/templates/related/add-related.html +++ b/ckan/templates/related/add-related.html @@ -9,7 +9,7 @@ py:def="add_related(dataset)">