def follow(user, obj, send_action=True, actor_only=True, **kwargs): """ Creates a relationship allowing the object's activities to appear in the user's stream. Returns the created ``Follow`` instance. If ``send_action`` is ``True`` (the default) then a ``<user> started following <object>`` action signal is sent. Extra keyword arguments are passed to the action.send call. If ``actor_only`` is ``True`` (the default) then only actions where the object is the actor will appear in the user's activity stream. Set to ``False`` to also include actions where this object is the action_object or the target. Example:: follow(request.user, group, actor_only=False) """ check(obj) instance, created = get_model('actstream', 'follow').objects.get_or_create( user=user, object_id=obj.pk, content_type=ContentType.objects.get_for_model(obj), actor_only=actor_only) if send_action and created: action.send(user, verb=_('started following'), target=obj, **kwargs) return instance
def action_handler(verb, **kwargs): """ Handler function to create Action instance upon action signal call. """ kwargs.pop('signal', None) actor = kwargs.pop('sender') # We must store the unstranslated string # If verb is an ugettext_lazyed string, fetch the original string if hasattr(verb, '_proxy____args'): verb = verb._proxy____args[0] newaction = get_model('actstream', 'action')( actor_content_type=ContentType.objects.get_for_model(actor), actor_object_id=actor.pk, verb=text_type(verb), public=bool(kwargs.pop('public', True)), description=kwargs.pop('description', None), timestamp=kwargs.pop('timestamp', now()) ) for opt in ('target', 'action_object'): obj = kwargs.pop(opt, None) if obj is not None: check(obj) setattr(newaction, '%s_object_id' % opt, obj.pk) setattr(newaction, '%s_content_type' % opt, ContentType.objects.get_for_model(obj)) if settings.USE_JSONFIELD and len(kwargs): newaction.data = kwargs newaction.save(force_insert=True) return newaction
def setup_generic_relations(model_class): """ Set up GenericRelations for actionable models. """ Action = get_model('actstream', 'action') if Action is None: raise RegistrationError( 'Unable get actstream.Action. Potential circular imports ' 'in initialisation. Try moving actstream app to come after the ' 'apps which have models to register in the INSTALLED_APPS setting.' ) related_attr_name = 'related_name' related_attr_value = 'actions_with_%s' % label(model_class) if django.VERSION[:2] >= (1, 7): related_attr_name = 'related_query_name' relations = {} for field in ('actor', 'target', 'action_object'): attr = '%s_actions' % field attr_value = '%s_as_%s' % (related_attr_value, field) kwargs = { 'content_type_field': '%s_content_type' % field, 'object_id_field': '%s_object_id' % field, related_attr_name: attr_value } rel = generic.GenericRelation('actstream.Action', **kwargs) rel.contribute_to_class(model_class, attr) relations[field] = rel # @@@ I'm not entirely sure why this works setattr(Action, attr_value, None) return relations
def action_handler(verb, **kwargs): """ Handler function to create Action instance upon action signal call. """ kwargs.pop('signal', None) actor = kwargs.pop('sender') # We must store the unstranslated string # If verb is an ugettext_lazyed string, fetch the original string if hasattr(verb, '_proxy____args'): verb = verb._proxy____args[0] newaction = get_model('actstream', 'action')( actor_content_type=ContentType.objects.get_for_model(actor), actor_object_id=actor.pk, verb=text_type(verb), public=bool(kwargs.pop('public', True)), description=kwargs.pop('description', None), timestamp=kwargs.pop('timestamp', now())) for opt in ('target', 'action_object'): obj = kwargs.pop(opt, None) if obj is not None: check(obj) setattr(newaction, '%s_object_id' % opt, obj.pk) setattr(newaction, '%s_content_type' % opt, ContentType.objects.get_for_model(obj)) if settings.USE_JSONFIELD and len(kwargs): if not settings.USE_POSTGRES: newaction.data = json.dumps(kwargs) else: newaction.data = kwargs newaction.save(force_insert=True) return newaction
def setup_generic_relations(model_class): """ Set up GenericRelations for actionable models. """ Action = get_model('actstream', 'action') if Action is None: raise RegistrationError('Unable get actstream.Action. Potential circular imports ' 'in initialisation. Try moving actstream app to come after the ' 'apps which have models to register in the INSTALLED_APPS setting.') related_attr_name = 'related_name' related_attr_value = 'actions_with_%s' % label(model_class) if django.VERSION[:2] >= (1, 7): related_attr_name = 'related_query_name' relations = {} for field in ('actor', 'target', 'action_object'): attr = '%s_actions' % field attr_value = '%s_as_%s' % (related_attr_value, field) kwargs = { 'content_type_field': '%s_content_type' % field, 'object_id_field': '%s_object_id' % field, related_attr_name: attr_value } rel = generic.GenericRelation('actstream.Action', **kwargs) rel = rel.contribute_to_class(model_class, attr) relations[field] = rel # @@@ I'm not entirely sure why this works setattr(Action, attr_value, None) return relations
def tearDown(self): for model in self.actstream_models: model = get_model(*model.split('.')) unregister(model) model.objects.all().delete() Action.objects.all().delete() Follow.objects.all().delete() self.User.objects.all().delete()
def unfollow(user, obj, send_action=False): """ Removes a "follow" relationship. Set ``send_action`` to ``True`` (``False is default) to also send a ``<user> stopped following <object>`` action signal. Example:: unfollow(request.user, other_user) """ check(obj) get_model('actstream', 'follow').objects.filter( user=user, object_id=obj.pk, content_type=ContentType.objects.get_for_model(obj) ).delete() if send_action: action.send(user, verb=_('stopped following'), target=obj)
def unfollow(user, obj, send_action=False): """ Removes a "follow" relationship. Set ``send_action`` to ``True`` (``False is default) to also send a ``<user> stopped following <object>`` action signal. Example:: unfollow(request.user, other_user) """ check(obj) get_model('actstream', 'follow').objects.filter( user=user, object_id=obj.pk, content_type=ContentType.objects.get_for_model(obj)).delete() if send_action: action.send(user, verb=_('stopped following'), target=obj)
def validate(model_class, exception_class=ImproperlyConfigured): if isinstance(model_class, string_types): model_class = get_model(*model_class.split('.')) if not isinstance(model_class, ModelBase): raise exception_class( 'Object %r is not a Model class.' % model_class) if model_class._meta.abstract: raise exception_class( 'The model %r is abstract, so it cannot be registered with ' 'actstream.' % model_class) return model_class
def is_following(user, obj): """ Checks if a "follow" relationship exists. Returns True if exists, False otherwise. Example:: is_following(request.user, group) """ check(obj) return get_model('actstream', 'follow').objects.filter( user=user, object_id=obj.pk, content_type=ContentType.objects.get_for_model(obj) ).exists()
def validate(model_class, exception_class=ImproperlyConfigured): if isinstance(model_class, string_types): model_class = get_model(*model_class.split('.')) if not isinstance(model_class, ModelBase): raise exception_class('Object %r is not a Model class.' % model_class) if model_class._meta.abstract: raise exception_class( 'The model %r is abstract, so it cannot be registered with ' 'actstream.' % model_class) if not is_installed(model_class): raise exception_class( 'The model %r is not installed, please put the app "%s" in your ' 'INSTALLED_APPS setting.' % (model_class, model_class._meta.app_label)) return model_class
def is_following(user, obj): """ Checks if a "follow" relationship exists. Returns True if exists, False otherwise. Example:: is_following(request.user, group) """ check(obj) return get_model('actstream', 'follow').objects.filter( user=user, object_id=obj.pk, content_type=ContentType.objects.get_for_model(obj)).exists()
def validate(model_class, exception_class=ImproperlyConfigured): if isinstance(model_class, string_types): model_class = get_model(*model_class.split('.')) if not isinstance(model_class, ModelBase): raise exception_class( 'Object %r is not a Model class.' % model_class) if model_class._meta.abstract: raise exception_class( 'The model %r is abstract, so it cannot be registered with ' 'actstream.' % model_class) if not is_installed(model_class): raise exception_class( 'The model %r is not installed, please put the app "%s" in your ' 'INSTALLED_APPS setting.' % (model_class, model_class._meta.app_label)) return model_class
def user(self, obj, **kwargs): """ Stream of most recent actions by objects that the passed User obj is following. """ q = Q() qs = self.public() if not obj: return qs.none() check(obj) actors_by_content_type = defaultdict(lambda: []) others_by_content_type = defaultdict(lambda: []) if kwargs.pop('with_user_activity', False): object_content_type = ContentType.objects.get_for_model(obj) actors_by_content_type[object_content_type.id].append(obj.pk) follow_gfks = get_model('actstream', 'follow').objects.filter(user=obj).values_list( 'content_type_id', 'object_id', 'actor_only') for content_type_id, object_id, actor_only in follow_gfks.iterator(): actors_by_content_type[content_type_id].append(object_id) if not actor_only: others_by_content_type[content_type_id].append(object_id) if len(actors_by_content_type) + len(others_by_content_type) == 0: return qs.none() for content_type_id, object_ids in actors_by_content_type.items(): q = q | Q( actor_content_type=content_type_id, actor_object_id__in=object_ids, ) for content_type_id, object_ids in others_by_content_type.items(): q = q | Q( target_content_type=content_type_id, target_object_id__in=object_ids, ) | Q( action_object_content_type=content_type_id, action_object_object_id__in=object_ids, ) return qs.filter(q, **kwargs)
def user(self, obj, **kwargs): """ Stream of most recent actions by objects that the passed User obj is following. """ q = Q() qs = self.public() if not obj: return qs.none() check(obj) actors_by_content_type = defaultdict(lambda: []) others_by_content_type = defaultdict(lambda: []) if kwargs.pop('with_user_activity', False): object_content_type = ContentType.objects.get_for_model(obj) actors_by_content_type[object_content_type.id].append(obj.pk) follow_gfks = get_model('actstream', 'follow').objects.filter( user=obj).values_list('content_type_id', 'object_id', 'actor_only') for content_type_id, object_id, actor_only in follow_gfks.iterator(): actors_by_content_type[content_type_id].append(object_id) if not actor_only: others_by_content_type[content_type_id].append(object_id) if len(actors_by_content_type) + len(others_by_content_type) == 0: return qs.none() for content_type_id, object_ids in actors_by_content_type.items(): q = q | Q( actor_content_type=content_type_id, actor_object_id__in=object_ids, ) for content_type_id, object_ids in others_by_content_type.items(): q = q | Q( target_content_type=content_type_id, target_object_id__in=object_ids, ) | Q( action_object_content_type=content_type_id, action_object_object_id__in=object_ids, ) return qs.filter(q, **kwargs)