• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rafalp / Misago / 15760070102

19 Jun 2025 02:18PM UTC coverage: 97.286% (+0.07%) from 97.214%
15760070102

Pull #1944

github

web-flow
Merge 1e99a089b into 7565eefd3
Pull Request #1944: Replace thread events with updates

2828 of 2914 new or added lines in 89 files covered. (97.05%)

13 existing lines in 4 files now uncovered.

74124 of 76192 relevant lines covered (97.29%)

0.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.35
/misago/threadupdates/hooks/create_thread_update.py
1
from typing import TYPE_CHECKING, Protocol, Union
1✔
2

3
from django.db.models import Model
1✔
4
from django.http import HttpRequest
1✔
5

6
from ...plugins.hooks import FilterHook
1✔
7

8
if TYPE_CHECKING:
1✔
NEW
9
    from ...threads.models import Thread
×
NEW
10
    from ...users.models import User
×
NEW
11
    from ..models import ThreadUpdate
×
12

13

14
class CreateThreadUpdateHookAction(Protocol):
1✔
15
    """
16
    A standard Misago function used to create a `ThreadUpdate` object.
17

18
    # Arguments
19

20
    ## `thread: Thread`
21

22
    A `Thread` instance.
23

24
    ## `action_name: str`
25

26
    A `str` with the name of the action that updated the thread.
27

28
    ## `actor: Union["User", None, str] = None`
29

30
    The actor who performed the action: a `User` instance, a `str` with a name,
31
    or `None` if not available.
32

33
    ## `request: HttpRequest | None = None`
34

35
    The request object or `None` if not available.
36

37
    ## `context: str | None = None`
38

39
    A `str` with context, e.g., a previous thread title or the name of
40
    `context_object`. `None` if not available or not used for this `action_name`.
41

42
    ## `context_object: Model | None = None`
43

44
    A `Model` instance that this update object should store a generic relation to.
45

46
    ## `is_hidden: bool = False`
47

48
    Controls whether the newly created update should be hidden. Hidden updates
49
    are only visible to moderators but can be made visible to all users.
50
    Defaults to `False`.
51

52
    ## `plugin_data: dict`
53

54
    A plugin data `dict` that will be saved on the `ThreadUpdate.plugin_data` attribute.
55

56
    # Return value
57

58
    A newly created `ThreadUpdate` instance.
59
    """
60

61
    def __call__(
1✔
62
        self,
63
        thread: "Thread",
64
        action_name: str,
65
        actor: Union["User", None, str] = None,
66
        *,
67
        request: HttpRequest | None = None,
68
        context: str | None = None,
69
        context_object: Model | None = None,
70
        is_hidden: bool = False,
71
        plugin_data: dict,
72
    ) -> "ThreadUpdate": ...
73

74

75
class CreateThreadUpdateHookFilter(Protocol):
1✔
76
    """
77
    A function implemented by a plugin that can be registered in this hook.
78

79
    # Arguments
80

81
    ## `action: CreateThreadUpdateHookAction`
82

83
    A standard Misago function used to create a `ThreadUpdate` object.
84

85
    ## `thread: Thread`
86

87
    A `Thread` instance.
88

89
    ## `action_name: str`
90

91
    A `str` with the name of the action that updated the thread.
92

93
    ## `actor: Union["User", None, str] = None`
94

95
    A `str` with context, e.g., a previous thread title or the name of
96
    `context_object`. `None` if not available or not used for this `action_name`.
97

98
    ## `request: HttpRequest | None = None`
99

100
    The request object or `None` if not available.
101

102
    ## `context: str | None = None`
103

104
    A `str` with context, e.g., a previous thread title or the name of
105
    `context_object`. `None` if not available or not used for this `action_name`.
106

107
    ## `context_object: Model | None = None`
108

109
    A `Model` instance that this update object should store a generic relation to.
110

111
    ## `is_hidden: bool = False`
112

113
    Controls whether the newly created update should be hidden. Hidden updates
114
    are only visible to moderators but can be made visible to all users.
115
    Defaults to `False`.
116

117
    ## `plugin_data: dict`
118

119
    A plugin data `dict` that will be saved on the `ThreadUpdate.plugin_data` attribute.
120

121
    # Return value
122

123
    A newly created `ThreadUpdate` instance.
124
    """
125

126
    def __call__(
1✔
127
        self,
128
        action: CreateThreadUpdateHookAction,
129
        thread: "Thread",
130
        action_name: str,
131
        actor: Union["User", None, str] = None,
132
        *,
133
        request: HttpRequest | None = None,
134
        context: str | None = None,
135
        context_object: Model | None = None,
136
        is_hidden: bool = False,
137
        plugin_data: dict,
138
    ) -> "ThreadUpdate": ...
139

140

141
class CreateThreadUpdateHook(
1✔
142
    FilterHook[
143
        CreateThreadUpdateHookAction,
144
        CreateThreadUpdateHookFilter,
145
    ]
146
):
147
    """
148
    This hook wraps a standard Misago function used to create a `ThreadUpdate` object.
149

150
    # Example
151

152
    The code below implements a custom filter function that stores the actor's IP
153
    address on the update object:
154

155
    ```python
156
    from django.http import HttpRequest
157
    from misago.threads.hooks import create_thread_update_hook
158
    from misago.threads.models import Thread, ThreadUpdate
159
    from misago.users.models import User
160

161

162
    @create_thread_update_hook.append_filter
163
    def set_actor_ip_on_thread_update(
164
        action,
165
        thread: "Thread",
166
        action_name: str,
167
        actor: Union["User", None, str] = None,
168
        *,
169
        request: HttpRequest | None = None,
170
        context: str | None = None,
171
        context_object: Model | None = None,
172
        is_hidden: bool = False,
173
        plugin_data: dict,
174
    ) -> ThreadUpdate:
175
        if request:
176
            plugin_data["actor_id"] = request.user_ip
177

178
        return action(
179
            thread,
180
            action_name,
181
            actor,
182
            request=request,
183
            context=context,
184
            context_object=context_object,
185
            is_hidden=is_hidden,
186
            plugin_data=plugin_data,
187
        )
188
    ```
189
    """
190

191
    __slots__ = FilterHook.__slots__
1✔
192

193
    def __call__(
1✔
194
        self,
195
        action: CreateThreadUpdateHookAction,
196
        thread: "Thread",
197
        action_name: str,
198
        actor: Union["User", None, str] = None,
199
        *,
200
        request: HttpRequest | None = None,
201
        context: str | None = None,
202
        context_object: Model | None = None,
203
        is_hidden: bool = False,
204
        plugin_data: dict,
205
    ) -> "ThreadUpdate":
206
        return super().__call__(
1✔
207
            action,
208
            thread,
209
            action_name,
210
            actor,
211
            request=request,
212
            context=context,
213
            context_object=context_object,
214
            is_hidden=is_hidden,
215
            plugin_data=plugin_data,
216
        )
217

218

219
create_thread_update_hook = CreateThreadUpdateHook()
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc