diff --git a/ckan/config/routing.py b/ckan/config/routing.py index a9d33839516..883514a3a9d 100644 --- a/ckan/config/routing.py +++ b/ckan/config/routing.py @@ -195,6 +195,8 @@ def make_map(): 'read_ajax', 'history_ajax', 'followers', + 'follow', + 'unfollow', 'delete', 'api_data', ])) diff --git a/ckan/controllers/package.py b/ckan/controllers/package.py index 996019bff56..c67da39f16a 100644 --- a/ckan/controllers/package.py +++ b/ckan/controllers/package.py @@ -1188,6 +1188,41 @@ def api_data(self, id=None): url = h.url_for('datastore_read', id=id, qualified=True) return render('package/resource_api_data.html', {'datastore_root_url': url}) + def follow(self, id): + '''Start following this dataset.''' + context = {'model': model, + 'session': model.Session, + 'user': c.user or c.author} + data_dict = {'id': id} + try: + get_action('follow_dataset')(context, data_dict) + h.flash_success(_("You are now following {0}").format(id)) + except ValidationError as e: + error_message = (e.extra_msg or e.message or e.error_summary + or e.error_dict) + h.flash_error(error_message) + except NotAuthorized as e: + h.flash_error(e.extra_msg) + h.redirect_to(controller='package', action='read', id=id) + + def unfollow(self, id): + '''Stop following this dataset.''' + context = {'model': model, + 'session': model.Session, + 'user': c.user or c.author} + data_dict = {'id': id} + try: + get_action('unfollow_dataset')(context, data_dict) + h.flash_success(_("You are no longer following {0}").format(id)) + except ValidationError as e: + error_message = (e.extra_msg or e.message or e.error_summary + or e.error_dict) + h.flash_error(error_message) + except (NotFound, NotAuthorized) as e: + error_message = e.extra_msg or e.message + h.flash_error(error_message) + h.redirect_to(controller='package', action='read', id=id) + def followers(self, id=None): context = {'model': model, 'session': model.Session, 'user': c.user or c.author, 'for_view': True} diff --git a/ckan/logic/action/create.py b/ckan/logic/action/create.py index 279d980836b..dc25af1a8b5 100644 --- a/ckan/logic/action/create.py +++ b/ckan/logic/action/create.py @@ -968,41 +968,44 @@ def follow_dataset(context, data_dict): ''' if not context.has_key('user'): - raise logic.NotAuthorized + raise logic.NotAuthorized( + _("You must be logged in to follow a dataset.")) model = context['model'] session = context['session'] userobj = model.User.get(context['user']) if not userobj: - raise logic.NotAuthorized + raise logic.NotAuthorized( + _("You must be logged in to follow a dataset.")) schema = (context.get('schema') or ckan.logic.schema.default_follow_dataset_schema()) - data_dict, errors = _validate(data_dict, schema, context) + validated_data_dict, errors = _validate(data_dict, schema, context) if errors: model.Session.rollback() raise ValidationError(errors) # Don't let a user follow a dataset she is already following. - if model.UserFollowingDataset.get(userobj.id, data_dict['id']) is not None: + if model.UserFollowingDataset.is_following(userobj.id, + validated_data_dict['id']): message = _( - 'You are already following {id}').format(id=data_dict['id']) - raise ValidationError({'message': message}) - + 'You are already following {0}').format(data_dict['id']) + raise ValidationError({'message': message}, error_summary=message) - follower = model_save.user_following_dataset_dict_save(data_dict, context) + follower = model_save.user_following_dataset_dict_save( + validated_data_dict, context) activity_dict = { 'user_id': userobj.id, - 'object_id': data_dict['id'], + 'object_id': validated_data_dict['id'], 'activity_type': 'follow dataset', } activity_dict['data'] = { 'dataset': ckan.lib.dictization.table_dictize( - model.Package.get(data_dict['id']), context), + model.Package.get(validated_data_dict['id']), context), } activity_create_context = { 'model': model, diff --git a/ckan/logic/converters.py b/ckan/logic/converters.py index 8526f5da783..beb7e773806 100644 --- a/ckan/logic/converters.py +++ b/ckan/logic/converters.py @@ -105,3 +105,28 @@ def convert_user_name_or_id_to_id(user_name_or_id, context): if not result: raise Invalid('%s: %s' % (_('Not found'), _('User'))) return result.id + +def convert_package_name_or_id_to_id(package_name_or_id, context): + '''Return the package id for the given package name or id. + + The point of this function is to convert package names to ids. If you have + something that may be a package name or id you can pass it into this + function and get the id out either way. + + Also validates that a package with the given name or id exists. + + :returns: the id of the package with the given name or id + :rtype: string + :raises: ckan.lib.navl.dictization_functions.Invalid if there is no + package with the given name or id + + ''' + session = context['session'] + result = session.query(model.Package).filter_by( + id=package_name_or_id).first() + if not result: + result = session.query(model.Package).filter_by( + name=package_name_or_id).first() + if not result: + raise Invalid('%s: %s' % (_('Not found'), _('Dataset'))) + return result.id diff --git a/ckan/logic/schema.py b/ckan/logic/schema.py index 975d6009fe4..f8b8a946257 100644 --- a/ckan/logic/schema.py +++ b/ckan/logic/schema.py @@ -40,7 +40,8 @@ activity_type_exists, tag_not_in_vocabulary, url_validator) -from ckan.logic.converters import (convert_user_name_or_id_to_id,) +from ckan.logic.converters import (convert_user_name_or_id_to_id, + convert_package_name_or_id_to_id,) from formencode.validators import OneOf import ckan.model @@ -425,5 +426,5 @@ def default_follow_user_schema(): def default_follow_dataset_schema(): schema = {'id': [not_missing, not_empty, unicode, - package_id_or_name_exists]} + convert_package_name_or_id_to_id]} return schema