Completed
Pull Request — master (#390)
by
unknown
23s
created

AbstractAction.action_object_url()   A

Complexity

Conditions 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
1
from __future__ import unicode_literals
2
3
from django.conf import settings
4
from django.contrib.contenttypes.fields import GenericForeignKey
5
from django.contrib.contenttypes.models import ContentType
6
from django.db import models
7
from django.urls import reverse
8
from django.utils.encoding import python_2_unicode_compatible
9
from django.utils.timesince import timesince as djtimesince
10
from django.utils.timezone import now
11
from django.utils.translation import ugettext as _
12
13
from actstream import get_action_model, get_follow_model
14
from actstream import settings as actstream_settings
15
from actstream.managers import FollowManager
16
17
18
@python_2_unicode_compatible
19
class AbstractFollow(models.Model):
20
    """
21
    Lets a user follow the activities of any specific actor
22
    """
23
    user = models.ForeignKey(
24
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, db_index=True
25
    )
26
27
    content_type = models.ForeignKey(
28
        ContentType, on_delete=models.CASCADE, db_index=True
29
    )
30
    object_id = models.CharField(max_length=255, db_index=True)
31
    follow_object = GenericForeignKey()
32
    actor_only = models.BooleanField(
33
        "Only follow actions where the object is the target.",
34
        default=True
35
    )
36
    flag = models.CharField(max_length=255, blank=True, db_index=True, default='')
37
    started = models.DateTimeField(default=now, db_index=True)
38
    objects = FollowManager()
39
40
    class Meta:
41
        abstract = True
42
        unique_together = ('user', 'content_type', 'object_id', 'flag')
43
44
    def __str__(self):
45
        return '%s -> %s : %s' % (self.user, self.follow_object, self.flag)
46
47
48
@python_2_unicode_compatible
49
class AbstractAction(models.Model):
50
    """
51
    Action model describing the actor acting out a verb (on an optional
52
    target).
53
    Nomenclature based on http://activitystrea.ms/specs/atom/1.0/
54
55
    Generalized Format::
56
57
        <actor> <verb> <time>
58
        <actor> <verb> <target> <time>
59
        <actor> <verb> <action_object> <target> <time>
60
61
    Examples::
62
63
        <justquick> <reached level 60> <1 minute ago>
64
        <brosner> <commented on> <pinax/pinax> <2 hours ago>
65
        <washingtontimes> <started follow> <justquick> <8 minutes ago>
66
        <mitsuhiko> <closed> <issue 70> on <mitsuhiko/flask> <about 2 hours ago>
67
68
    Unicode Representation::
69
70
        justquick reached level 60 1 minute ago
71
        mitsuhiko closed issue 70 on mitsuhiko/flask 3 hours ago
72
73
    HTML Representation::
74
75
        <a href="http://oebfare.com/">brosner</a> commented on <a href="http://github.com/pinax/pinax">pinax/pinax</a> 2 hours ago
76
77
    """
78
    actor_content_type = models.ForeignKey(
79
        ContentType, related_name='actor',
80
        on_delete=models.CASCADE, db_index=True
81
    )
82
    actor_object_id = models.CharField(max_length=255, db_index=True)
83
    actor = GenericForeignKey('actor_content_type', 'actor_object_id')
84
85
    verb = models.CharField(max_length=255, db_index=True)
86
    description = models.TextField(blank=True, null=True)
87
88
    target_content_type = models.ForeignKey(
89
        ContentType, blank=True, null=True,
90
        related_name='target',
91
        on_delete=models.CASCADE, db_index=True
92
    )
93
    target_object_id = models.CharField(
94
        max_length=255, blank=True, null=True, db_index=True
95
    )
96
    target = GenericForeignKey(
97
        'target_content_type',
98
        'target_object_id'
99
    )
100
101
    action_object_content_type = models.ForeignKey(
102
        ContentType, blank=True, null=True,
103
        related_name='action_object',
104
        on_delete=models.CASCADE, db_index=True
105
    )
106
    action_object_object_id = models.CharField(
107
        max_length=255, blank=True, null=True, db_index=True
108
    )
109
    action_object = GenericForeignKey(
110
        'action_object_content_type',
111
        'action_object_object_id'
112
    )
113
114
    timestamp = models.DateTimeField(default=now, db_index=True)
115
116
    public = models.BooleanField(default=True, db_index=True)
117
118
    objects = actstream_settings.get_action_manager()
119
120
    class Meta:
121
        abstract = True
122
        ordering = ('-timestamp',)
123
124
    def __str__(self):
125
        ctx = {
126
            'actor': self.actor,
127
            'verb': self.verb,
128
            'action_object': self.action_object,
129
            'target': self.target,
130
            'timesince': self.timesince()
131
        }
132
        if self.target:
133
            if self.action_object:
134
                return _('%(actor)s %(verb)s %(action_object)s on %(target)s %(timesince)s ago') % ctx
135
            return _('%(actor)s %(verb)s %(target)s %(timesince)s ago') % ctx
136
        if self.action_object:
137
            return _('%(actor)s %(verb)s %(action_object)s %(timesince)s ago') % ctx
138
        return _('%(actor)s %(verb)s %(timesince)s ago') % ctx
139
140
    def actor_url(self):
141
        """
142
        Return the URL to the ``actstream_actor`` view for the current actor.
143
        """
144
        return reverse('actstream_actor', None,
145
                       (self.actor_content_type.pk, self.actor_object_id))
146
147
    def target_url(self):
148
        """
149
        Return the URL to the ``actstream_actor`` view for the current target.
150
        """
151
        return reverse('actstream_actor', None,
152
                       (self.target_content_type.pk, self.target_object_id))
153
154
    def action_object_url(self):
155
        """
156
        Return the URL to the ``actstream_action_object`` view for the current action object.
157
        """
158
        return reverse('actstream_actor', None, (
159
            self.action_object_content_type.pk, self.action_object_object_id))
160
161
    def timesince(self, now=None):
162
        """
163
        Shortcut for the ``django.utils.timesince.timesince`` function of the current timestamp.
164
        """
165
        return djtimesince(self.timestamp, now).encode('utf8').replace(b'\xc2\xa0', b' ').decode('utf8')
166
167
    def get_absolute_url(self):
168
        return reverse(
169
            'actstream.views.detail', [self.pk])
170
171
172
class Follow(AbstractFollow):
173
    class Meta(AbstractFollow.Meta):
174
        swappable = 'ACTSTREAM_FOLLOW_MODEL'
175
176
177
class Action(AbstractAction):
178
    class Meta(AbstractAction.Meta):
179
        swappable = 'ACTSTREAM_ACTION_MODEL'
180
181
182
# convenient accessors
183
actor_stream = get_action_model().objects.actor
184
action_object_stream = get_action_model().objects.action_object
185
target_stream = get_action_model().objects.target
186
user_stream = get_action_model().objects.user
187
model_stream = get_action_model().objects.model_actions
188
any_stream = get_action_model().objects.any
189
followers = get_follow_model().objects.followers
190
following = get_follow_model().objects.following
191