Skip to content

Commit

Permalink
[#3005] Add model and API for following groups
Browse files Browse the repository at this point in the history
This implements everything required at the model and API level for following
and unfollowing of groups, getting a group's number of followers or a list of a
group's followers, and getting the number of groups that a user follows or a
list of the groups that a user follows.

Tests need to be added.

Frontend for following groups needs to be added.

+ Add UserFollowingGroup model class and user_following_group_dictize().

+ Add "{actor} started following {group}" activity stream activity.

+ Refactor user_following_user_dict_save() and
  user_following_dataset_dict_save(), replace with a single
  follower_dict_save() that can be used for UserFollowingUser,
  UserFollowingDataset, or UserFollowingGroup.

+ Add follow_group() and unfollow_group() logic action functions in create.py
  and delete.py.

+ Add group_follower_count(), group_follower_list(), am_following_group(),
  group_followee_count() and group_followee_list() logic action functions in
  get.py.

  Also refactor some code in logic/action/get.py to remove duplication between
  follower functions.

+ Add convert_group_name_or_id_to_id() converter function

+ Add default_follow_group_schema()

+ Add migration script
  • Loading branch information
Sean Hammond committed Oct 23, 2012
1 parent 1311da8 commit 4145f00
Show file tree
Hide file tree
Showing 12 changed files with 360 additions and 63 deletions.
5 changes: 5 additions & 0 deletions ckan/lib/activity_streams.py
Expand Up @@ -110,6 +110,9 @@ def activity_stream_string_follow_dataset():
def activity_stream_string_follow_user():
return _("{actor} started following {user}")

def activity_stream_string_follow_group():
return _("{actor} started following {group}")

def activity_stream_string_new_related_item():
return _("{actor} created the link to related {related_type} {related_item}")

Expand Down Expand Up @@ -148,6 +151,7 @@ def activity_stream_string_new_related_item():
'deleted related item': activity_stream_string_deleted_related_item,
'follow dataset': activity_stream_string_follow_dataset,
'follow user': activity_stream_string_follow_user,
'follow group': activity_stream_string_follow_group,
'new related item': activity_stream_string_new_related_item,
}

Expand All @@ -172,6 +176,7 @@ def activity_stream_string_new_related_item():
'deleted related item': 'picture',
'follow dataset': 'sitemap',
'follow user': 'user',
'follow group': 'groups',
'new related item': 'picture',
}

Expand Down
3 changes: 3 additions & 0 deletions ckan/lib/dictization/model_dictize.py
Expand Up @@ -575,3 +575,6 @@ def user_following_user_dictize(follower, context):

def user_following_dataset_dictize(follower, context):
return d.table_dictize(follower, context)

def user_following_group_dictize(follower, context):
return d.table_dictize(follower, context)
13 changes: 2 additions & 11 deletions ckan/lib/dictization/model_save.py
Expand Up @@ -594,19 +594,10 @@ def tag_dict_save(tag_dict, context):
tag = d.table_dict_save(tag_dict, model.Tag, context)
return tag

def user_following_user_dict_save(data_dict, context):
def follower_dict_save(data_dict, context, FollowerClass):
model = context['model']
session = context['session']
follower_obj = model.UserFollowingUser(
follower_id=model.User.get(context['user']).id,
object_id=data_dict['id'])
session.add(follower_obj)
return follower_obj

def user_following_dataset_dict_save(data_dict, context):
model = context['model']
session = context['session']
follower_obj = model.UserFollowingDataset(
follower_obj = FollowerClass(
follower_id=model.User.get(context['user']).id,
object_id=data_dict['id'])
session.add(follower_obj)
Expand Down
79 changes: 75 additions & 4 deletions ckan/logic/action/create.py
Expand Up @@ -924,8 +924,8 @@ def follow_user(context, data_dict):
'You are already following {0}').format(data_dict['id'])
raise ValidationError({'message': message}, error_summary=message)

follower = model_save.user_following_user_dict_save(validated_data_dict,
context)
follower = model_save.follower_dict_save(validated_data_dict, context,
model.UserFollowingUser)

activity_dict = {
'user_id': userobj.id,
Expand Down Expand Up @@ -995,8 +995,8 @@ def follow_dataset(context, data_dict):
'You are already following {0}').format(data_dict['id'])
raise ValidationError({'message': message}, error_summary=message)

follower = model_save.user_following_dataset_dict_save(
validated_data_dict, context)
follower = model_save.follower_dict_save(validated_data_dict, context,
model.UserFollowingDataset)

activity_dict = {
'user_id': userobj.id,
Expand All @@ -1023,3 +1023,74 @@ def follow_dataset(context, data_dict):
follower=follower.follower_id, object=follower.object_id))

return model_dictize.user_following_dataset_dictize(follower, context)


def follow_group(context, data_dict):
'''Start following a group.
You must provide your API key in the Authorization header.
:param id: the id or name of the group to follow, e.g. ``'roger'``
:type id: string
:returns: a representation of the 'follower' relationship between yourself
and the group
:rtype: dictionary
'''
if 'user' not in context:
raise logic.NotAuthorized(
_("You must be logged in to follow a group."))

model = context['model']
session = context['session']

userobj = model.User.get(context['user'])
if not userobj:
raise logic.NotAuthorized(
_("You must be logged in to follow a group."))

schema = context.get('schema',
ckan.logic.schema.default_follow_group_schema())

validated_data_dict, errors = _validate(data_dict, schema, context)

if errors:
model.Session.rollback()
raise ValidationError(errors)

# Don't let a user follow a group she is already following.
if model.UserFollowingGroup.is_following(userobj.id,
validated_data_dict['id']):
message = _(
'You are already following {0}').format(data_dict['id'])
raise ValidationError({'message': message}, error_summary=message)

follower = model_save.follower_dict_save(validated_data_dict, context,
model.UserFollowingGroup)

activity_dict = {
'user_id': userobj.id,
'object_id': validated_data_dict['id'],
'activity_type': 'follow group',
}
activity_dict['data'] = {
'group': ckan.lib.dictization.table_dictize(
model.Group.get(validated_data_dict['id']), context),
}
activity_create_context = {
'model': model,
'user': userobj,
'defer_commit': True,
'session': session
}
logic.get_action('activity_create')(activity_create_context,
activity_dict, ignore_auth=True)

if not context.get('defer_commit'):
model.repo.commit()

log.debug(u'User {follower} started following group {object}'.format(
follower=follower.follower_id, object=follower.object_id))

return model_dictize.user_following_group_dictize(follower, context)
19 changes: 15 additions & 4 deletions ckan/logic/action/delete.py
Expand Up @@ -312,10 +312,6 @@ def package_relationship_delete_rest(context, data_dict):
package_relationship_delete(context, data_dict)

def _unfollow(context, data_dict, schema, FollowerClass):
validated_data_dict, errors = validate(data_dict, schema, context)
if errors:
raise ValidationError(errors)

model = context['model']

if not context.has_key('user'):
Expand All @@ -327,6 +323,9 @@ def _unfollow(context, data_dict, schema, FollowerClass):
_("You must be logged in to unfollow something."))
follower_id = userobj.id

validated_data_dict, errors = validate(data_dict, schema, context)
if errors:
raise ValidationError(errors)
object_id = validated_data_dict.get('id')

follower_obj = FollowerClass.get(follower_id, object_id)
Expand Down Expand Up @@ -359,3 +358,15 @@ def unfollow_dataset(context, data_dict):
ckan.logic.schema.default_follow_dataset_schema())
_unfollow(context, data_dict, schema,
context['model'].UserFollowingDataset)

def unfollow_group(context, data_dict):
'''Stop following a group.
:param id: the id or name of the group to stop following
:type id: string
'''
schema = context.get('schema',
ckan.logic.schema.default_follow_group_schema())
_unfollow(context, data_dict, schema,
context['model'].UserFollowingGroup)

0 comments on commit 4145f00

Please sign in to comment.