Skip to content

Commit 7efd1af

Browse files
committed
Make it compatible with fsm-log
1 parent 58095a0 commit 7efd1af

File tree

8 files changed

+118
-5
lines changed

8 files changed

+118
-5
lines changed

django_fsm/admin.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
from dataclasses import dataclass
4+
from functools import partial
45
from typing import Any
56

67
from django.conf import settings
@@ -15,6 +16,13 @@
1516

1617
import django_fsm as fsm
1718

19+
try:
20+
import django_fsm_log # noqa: F401
21+
except ModuleNotFoundError:
22+
FSM_LOG_ENABLED = False
23+
else:
24+
FSM_LOG_ENABLED = True
25+
1826

1927
@dataclass
2028
class FSMObjectTransition:
@@ -127,7 +135,20 @@ def response_change(self, request: HttpRequest, obj: Any) -> HttpResponse:
127135
)
128136

129137
try:
130-
transition_func()
138+
if FSM_LOG_ENABLED:
139+
for fn in [
140+
partial(transition_func, request=request, by=request.user),
141+
partial(transition_func, by=request.user),
142+
transition_func,
143+
]:
144+
try:
145+
fn()
146+
except TypeError: # noqa: PERF203
147+
pass
148+
else:
149+
break
150+
else:
151+
transition_func()
131152
except fsm.TransitionNotAllowed:
132153
self.message_user(
133154
request=request,

tests/settings.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"django.contrib.sessions",
4444
"django.contrib.messages",
4545
"django.contrib.staticfiles",
46+
"django_fsm_log",
4647
"guardian",
4748
*PROJECT_APPS,
4849
]
@@ -135,3 +136,35 @@
135136
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
136137

137138
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
139+
140+
141+
# Django FSM-log settings
142+
DJANGO_FSM_LOG_IGNORED_MODELS = (
143+
"tests.testapp.models.AdminBlogPost",
144+
"tests.testapp.models.Application",
145+
"tests.testapp.models.BlogPost",
146+
"tests.testapp.models.DbState",
147+
"tests.testapp.models.FKApplication",
148+
"tests.testapp.tests.SimpleBlogPost",
149+
"tests.testapp.tests.test_abstract_inheritance.BaseAbstractModel",
150+
"tests.testapp.tests.test_abstract_inheritance.InheritedFromAbstractModel",
151+
"tests.testapp.tests.test_access_deferred_fsm_field.DeferrableModel",
152+
"tests.testapp.tests.test_basic_transitions.SimpleBlogPost",
153+
"tests.testapp.tests.test_conditions.BlogPostWithConditions",
154+
"tests.testapp.tests.test_custom_data.BlogPostWithCustomData",
155+
"tests.testapp.tests.test_exception_transitions.ExceptionalBlogPost",
156+
"tests.testapp.tests.test_graph_transitions.VisualBlogPost",
157+
"tests.testapp.tests.test_integer_field.BlogPostWithIntegerField",
158+
"tests.testapp.tests.test_lock_mixin.ExtendedBlogPost",
159+
"tests.testapp.tests.test_lock_mixin.LockedBlogPost",
160+
"tests.testapp.tests.test_mixin_support.MixinSupportTestModel",
161+
"tests.testapp.tests.test_multi_resultstate.MultiResultTest",
162+
"tests.testapp.tests.test_multidecorators.TestModel",
163+
"tests.testapp.tests.test_protected_field.ProtectedAccessModel",
164+
"tests.testapp.tests.test_protected_fields.RefreshableProtectedAccessModel",
165+
"tests.testapp.tests.test_proxy_inheritance.InheritedModel",
166+
"tests.testapp.tests.test_state_transitions.Caterpillar",
167+
"tests.testapp.tests.test_string_field_parameter.BlogPostWithStringField",
168+
"tests.testapp.tests.test_transition_all_except_target.TestExceptTargetTransitionShortcut",
169+
"tests.testapp.tests.test_key_field.FKBlogPost",
170+
)

tests/testapp/admin.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
from django.contrib import admin
4+
from django_fsm_log.admin import StateLogInline
45

56
from django_fsm.admin import FSMAdminMixin
67

@@ -20,3 +21,5 @@ class AdminBlogPostAdmin(FSMAdminMixin, admin.ModelAdmin):
2021
"state",
2122
"step",
2223
]
24+
25+
inlines = [StateLogInline]

tests/testapp/tests/test_admin.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ def test_transition_applied(self, mock_message_user):
139139
path="/",
140140
data={"_fsm_transition_to": "moderate"},
141141
)
142+
request.user = MockSuperUser()
142143

143144
blog_post = AdminBlogPost.objects.create(title="Article name")
144145
assert blog_post.state == AdminBlogPostState.CREATED
@@ -162,6 +163,7 @@ def test_transition_not_allowed_exception(self, mock_message_user):
162163
path="/",
163164
data={"_fsm_transition_to": "publish"},
164165
)
166+
request.user = MockSuperUser()
165167

166168
blog_post = AdminBlogPost.objects.create(title="Article name")
167169
assert blog_post.state == AdminBlogPostState.CREATED
@@ -185,6 +187,7 @@ def test_concurrent_transition_exception(self, mock_message_user):
185187
path="/",
186188
data={"_fsm_transition_to": "moderate"},
187189
)
190+
request.user = MockSuperUser()
188191

189192
blog_post = AdminBlogPost.objects.create(title="Article name")
190193
assert blog_post.state == AdminBlogPostState.CREATED
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
from django.contrib.auth import get_user_model
5+
from django.db import models
6+
from django.test import TestCase
7+
from django_fsm_log.decorators import fsm_log_by
8+
from django_fsm_log.models import StateLog
9+
10+
from django_fsm import FSMField
11+
from django_fsm import TransitionNotAllowed
12+
from django_fsm import transition
13+
14+
15+
class LoggableModel(models.Model):
16+
state = FSMField(default="new")
17+
18+
@transition(field=state, source="new", target="published")
19+
def publish(self):
20+
pass
21+
22+
@fsm_log_by
23+
@transition(field=state, source="new", target="published")
24+
def publish_by(self, by=None):
25+
pass
26+
27+
@transition(source="published", target="hidden", field=state)
28+
def hide(self):
29+
pass
30+
31+
32+
class PluginFsmLogTests(TestCase):
33+
def setUp(self):
34+
self.model = LoggableModel.objects.create()
35+
self.user = get_user_model().objects.create_user(username="jacob", password="password") # noqa: S106
36+
37+
def test_fsm_log_simple(self):
38+
assert StateLog.objects.count() == 0
39+
self.model.publish()
40+
assert StateLog.objects.count() == 1
41+
42+
def test_fsm_log_by(self):
43+
assert StateLog.objects.count() == 0
44+
self.model.publish_by(by=self.user)
45+
assert StateLog.objects.count() == 1
46+
assert StateLog.objects.get().by is not None
47+
48+
def test_signals_not_called_on_invalid_transition(self):
49+
assert StateLog.objects.count() == 0
50+
with pytest.raises(TransitionNotAllowed):
51+
self.model.hide()
52+
assert StateLog.objects.count() == 0

tests/testapp/tests/test_multidecorators.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from django_fsm.signals import post_transition
99

1010

11-
class TestModel(models.Model):
11+
class MultiDecoratedModel(models.Model):
1212
counter = models.IntegerField(default=0)
1313
signal_counter = models.IntegerField(default=0)
1414
state = FSMField(default="SUBMITTED_BY_USER")
@@ -24,12 +24,12 @@ def count_calls(sender, instance, name, source, target, **kwargs):
2424
instance.signal_counter += 1
2525

2626

27-
post_transition.connect(count_calls, sender=TestModel)
27+
post_transition.connect(count_calls, sender=MultiDecoratedModel)
2828

2929

3030
class TestStateProxy(TestCase):
3131
def test_transition_method_called_once(self):
32-
model = TestModel()
32+
model = MultiDecoratedModel.objects.create()
3333
model.review()
3434
assert model.counter == 1
3535
assert model.signal_counter == 1

tests/wsgi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@
1212

1313
from django.core.wsgi import get_wsgi_application
1414

15-
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "silvr.settings")
15+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.settings")
1616

1717
application = get_wsgi_application()

tox.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ deps =
1313
dj51: Django==5.1
1414
dj52: Django==5.2
1515

16+
django-fsm-log
1617
django-guardian
1718
graphviz
1819
pep8

0 commit comments

Comments
 (0)