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

rafalp / Misago / 17496798327

05 Sep 2025 02:59PM UTC coverage: 96.509% (-0.3%) from 96.769%
17496798327

Pull #1995

github

web-flow
Merge 17284d7d7 into 6bb938c90
Pull Request #1995: Move `Post` model from `misago.threads` to `misago.posts`

1884 of 1974 new or added lines in 149 files covered. (95.44%)

305 existing lines in 16 files now uncovered.

66716 of 69129 relevant lines covered (96.51%)

0.97 hits per line

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

88.1
/misago/conftest.py
1
import random
1✔
2
import os
1✔
3
from datetime import timedelta
1✔
4

5
import pytest
1✔
6
from django.core.files.uploadedfile import SimpleUploadedFile
1✔
7
from django.utils import timezone
1✔
8

9
from .acl import ACL_CACHE, useracl
1✔
10
from .admin.auth import authorize_admin
1✔
11
from .attachments.models import Attachment
1✔
12
from .attachments.filetypes import filetypes
1✔
13
from .cache.enums import CacheName
1✔
14
from .categories.models import Category
1✔
15
from .conf import SETTINGS_CACHE
1✔
16
from .conf.dynamicsettings import DynamicSettings
1✔
17
from .conf.staticsettings import StaticSettings
1✔
18
from .core.utils import slugify
1✔
19
from .menus import MENU_ITEMS_CACHE
1✔
20
from .notifications.models import WatchedThread
1✔
21
from .permissions.models import Moderator
1✔
22
from .privatethreadmembers.models import PrivateThreadMember
1✔
23
from .socialauth import SOCIALAUTH_CACHE
1✔
24
from .socialauth.models import SocialAuthProvider
1✔
25
from .test import (
1✔
26
    IMAGE_INVALID,
27
    IMAGE_LARGE,
28
    IMAGE_SMALL,
29
    TEXT_FILE,
30
    MisagoClient,
31
    teardown_attachments,
32
)
33
from .test.categories import category_relations_factory
1✔
34
from .test.time import *
1✔
35
from .test.polls import *
1✔
36
from .test.posts import *
1✔
37
from .test.threads import thread_factory, thread_relations_factory
1✔
38
from .test.threadupdates import *
1✔
39
from .test.userpermissions import *
1✔
40
from .themes import THEME_CACHE
1✔
41
from .threads.models import Thread
1✔
42
from .users import BANS_CACHE
1✔
43
from .users.enums import DefaultGroupId
1✔
44
from .users.models import AnonymousUser, Group, GroupDescription
1✔
45
from .users.test import create_test_superuser, create_test_user
1✔
46

47

48
def get_cache_versions():
1✔
49
    return {
1✔
50
        CacheName.CATEGORIES: "abcdefgh",
51
        CacheName.GROUPS: "abcdefgh",
52
        CacheName.MODERATORS: "abcdefgh",
53
        CacheName.PERMISSIONS: "abcdefgh",
54
        ACL_CACHE: "abcdefgh",
55
        BANS_CACHE: "abcdefgh",
56
        SETTINGS_CACHE: "abcdefgh",
57
        SOCIALAUTH_CACHE: "abcdefgh",
58
        THEME_CACHE: "abcdefgh",
59
        MENU_ITEMS_CACHE: "abcdefgh",
60
    }
61

62

63
@pytest.fixture
1✔
64
def cache_versions():
1✔
65
    return get_cache_versions()
1✔
66

67

68
@pytest.fixture
1✔
69
def dynamic_settings(db, cache_versions):
1✔
70
    return DynamicSettings(cache_versions)
1✔
71

72

73
@pytest.fixture
1✔
74
def settings():
1✔
75
    return StaticSettings()
1✔
76

77

78
@pytest.fixture
1✔
79
def user_password():
1✔
80
    return "p4ssw0rd!"
1✔
81

82

83
@pytest.fixture
1✔
84
def anonymous_user():
1✔
85
    return AnonymousUser()
1✔
86

87

88
@pytest.fixture
1✔
89
def anonymous_user_acl(anonymous_user, cache_versions):
1✔
90
    return useracl.get_user_acl(anonymous_user, cache_versions)
×
91

92

93
@pytest.fixture
1✔
94
def user(db, user_password):
1✔
95
    return create_test_user("User", "user@example.com", user_password)
1✔
96

97

98
@pytest.fixture
1✔
99
def user_acl(user, cache_versions):
1✔
100
    return useracl.get_user_acl(user, cache_versions)
1✔
101

102

103
@pytest.fixture
1✔
104
def other_user(db, user_password):
1✔
105
    return create_test_user("Other_User", "otheruser@example.com", user_password)
1✔
106

107

108
@pytest.fixture
1✔
109
def other_user_acl(other_user, cache_versions):
1✔
110
    return useracl.get_user_acl(other_user, cache_versions)
×
111

112

113
@pytest.fixture
1✔
114
def category_moderator(db, user_password, default_category):
1✔
115
    user = create_test_user("Moderator", "moderator@example.com", user_password)
×
116

117
    Moderator.objects.create(
×
118
        user=user,
119
        is_global=False,
120
        categories=[default_category.id],
121
    )
122

123
    return user
×
124

125

126
@pytest.fixture
1✔
127
def moderator(db, user_password, moderators_group):
1✔
128
    user = create_test_user("Moderator", "moderator@example.com", user_password)
1✔
129
    user.set_groups(moderators_group)
1✔
130
    user.save()
1✔
131
    return user
1✔
132

133

134
@pytest.fixture
1✔
135
def staffuser(db, user_password):
1✔
136
    return create_test_user(
1✔
137
        "Staff_User", "staffuser@example.com", user_password, is_staff=True
138
    )
139

140

141
@pytest.fixture
1✔
142
def staffuser_acl(staffuser, cache_versions):
1✔
143
    return useracl.get_user_acl(staffuser, cache_versions)
×
144

145

146
@pytest.fixture
1✔
147
def other_staffuser(db, user_password):
1✔
148
    return create_test_user(
×
149
        "Other_Staff_User", "otherstaffuser@example.com", user_password, is_staff=False
150
    )
151

152

153
@pytest.fixture
1✔
154
def superuser(db, user_password):
1✔
155
    return create_test_user(
1✔
156
        "Super_User",
157
        "superuser@example.com",
158
        user_password,
159
        is_staff=True,
160
        is_superuser=True,
161
    )
162

163

164
@pytest.fixture
1✔
165
def admin(db, user_password):
1✔
166
    user = create_test_superuser("Admin_User", "adminuser@example.com", user_password)
1✔
167
    user.is_staff = False
1✔
168
    user.is_superuser = False
1✔
169
    user.is_misago_root = False
1✔
170
    user.save()
1✔
171
    return user
1✔
172

173

174
@pytest.fixture
1✔
175
def other_admin(db, user_password):
1✔
176
    user = create_test_superuser("Other_Admin", "otheradmin@example.com", user_password)
1✔
177
    user.is_staff = False
1✔
178
    user.is_superuser = False
1✔
179
    user.is_misago_root = False
1✔
180
    user.save()
1✔
181
    return user
1✔
182

183

184
@pytest.fixture
1✔
185
def secondary_admin(db, user_password, admins_group, members_group):
1✔
186
    user = create_test_user("Second_Admin", "secondary@example.com", user_password)
1✔
187
    user.set_groups(members_group, [admins_group])
1✔
188
    user.save()
1✔
189
    return user
1✔
190

191

192
@pytest.fixture
1✔
193
def root_admin(db, user_password):
1✔
194
    user = create_test_superuser("Root_Admin", "rootadmin@example.com", user_password)
1✔
195
    user.is_staff = False
1✔
196
    user.is_superuser = False
1✔
197
    user.save()
1✔
198
    return user
1✔
199

200

201
@pytest.fixture
1✔
202
def other_root_admin(db, user_password):
1✔
203
    user = create_test_superuser("Other_Root", "otherroot@example.com", user_password)
1✔
204
    user.is_staff = False
1✔
205
    user.is_superuser = False
1✔
206
    user.save()
1✔
207
    return user
1✔
208

209

210
@pytest.fixture
1✔
211
def inactive_user(db, user_password):
1✔
212
    return create_test_user(
1✔
213
        "Inactive_User", "inactiveuser@example.com", user_password, is_active=False
214
    )
215

216

217
@pytest.fixture
1✔
218
def admins_group(db):
1✔
219
    return Group.objects.get(id=DefaultGroupId.ADMINS)
1✔
220

221

222
@pytest.fixture
1✔
223
def moderators_group(db):
1✔
224
    return Group.objects.get(id=DefaultGroupId.MODERATORS)
1✔
225

226

227
@pytest.fixture
1✔
228
def members_group(db):
1✔
229
    return Group.objects.get(id=DefaultGroupId.MEMBERS)
1✔
230

231

232
@pytest.fixture
1✔
233
def guests_group(db):
1✔
234
    return Group.objects.get(id=DefaultGroupId.GUESTS)
1✔
235

236

237
@pytest.fixture
1✔
238
def custom_group(db):
1✔
239
    group = Group.objects.create(
1✔
240
        name="Custom Group",
241
        slug="custom-group",
242
        ordering=4,
243
    )
244
    group.description = GroupDescription.objects.create(group=group)
1✔
245
    return group
1✔
246

247

248
@pytest.fixture
1✔
249
def client():
1✔
250
    return MisagoClient()
1✔
251

252

253
@pytest.fixture
1✔
254
def user_client(client, user):
1✔
255
    client.force_login(user)
1✔
256
    session = client.session
1✔
257
    session.save()
1✔
258
    return client
1✔
259

260

261
@pytest.fixture
1✔
262
def other_user_client(client, other_user):
1✔
263
    client.force_login(other_user)
1✔
264
    session = client.session
1✔
265
    session.save()
1✔
266
    return client
1✔
267

268

269
@pytest.fixture
1✔
270
def moderator_client(client, moderator):
1✔
271
    client.force_login(moderator)
1✔
272
    session = client.session
1✔
273
    session.save()
1✔
274
    return client
1✔
275

276

277
@pytest.fixture
1✔
278
def admin_client(mocker, client, admin):
1✔
279
    client.force_login(admin)
1✔
280
    session = client.session
1✔
281
    authorize_admin(mocker.Mock(session=session, user=admin))
1✔
282
    session.save()
1✔
283
    return client
1✔
284

285

286
@pytest.fixture
1✔
287
def root_admin_client(mocker, client, root_admin):
1✔
288
    client.force_login(root_admin)
1✔
289
    session = client.session
1✔
290
    authorize_admin(mocker.Mock(session=session, user=root_admin))
1✔
291
    session.save()
1✔
292
    return client
1✔
293

294

295
@pytest.fixture
1✔
296
def staff_client(mocker, client, staffuser):
1✔
297
    client.force_login(staffuser)
1✔
298
    session = client.session
1✔
299
    authorize_admin(mocker.Mock(session=session, user=staffuser))
1✔
300
    session.save()
1✔
301
    return client
1✔
302

303

304
@pytest.fixture
1✔
305
def root_category(db):
1✔
306
    return Category.objects.root_category()
1✔
307

308

309
@pytest.fixture
1✔
310
def private_threads_category(db):
1✔
311
    return Category.objects.private_threads()
1✔
312

313

314
@pytest.fixture
1✔
315
def default_category(db):
1✔
316
    return Category.objects.get(slug="first-category")
1✔
317

318

319
@pytest.fixture
1✔
320
def thread(thread_factory, default_category):
1✔
321
    thread = thread_factory(default_category)
1✔
322

323
    default_category.synchronize()
1✔
324
    default_category.save()
1✔
325

326
    return thread
1✔
327

328

329
@pytest.fixture
1✔
330
def other_thread(thread_factory, default_category):
1✔
331
    thread = thread_factory(default_category)
1✔
332

333
    default_category.synchronize()
1✔
334
    default_category.save()
1✔
335

336
    return thread
1✔
337

338

339
@pytest.fixture
1✔
340
def hidden_thread(thread_factory, default_category):
1✔
341
    thread = thread_factory(default_category, is_hidden=True)
1✔
342

343
    default_category.synchronize()
1✔
344
    default_category.save()
1✔
345

346
    return thread
1✔
347

348

349
@pytest.fixture
1✔
350
def unapproved_thread(thread_factory, default_category):
1✔
NEW
351
    thread = thread_factory(default_category, is_unapproved=True)
×
352

NEW
353
    default_category.synchronize()
×
NEW
354
    default_category.save()
×
355

NEW
356
    return thread
×
357

358

359
@pytest.fixture
1✔
360
def post(thread):
1✔
361
    return thread.first_post
1✔
362

363

364
@pytest.fixture
1✔
365
def reply(thread_reply_factory, thread):
1✔
366
    reply = thread_reply_factory(
1✔
367
        thread,
368
        poster="Reply",
369
        original="I am reply",
370
    )
371

372
    reply.category.synchronize()
1✔
373
    reply.category.save()
1✔
374

375
    return reply
1✔
376

377

378
@pytest.fixture
1✔
379
def hidden_reply(thread_reply_factory, thread):
1✔
380
    reply = thread_reply_factory(
1✔
381
        thread,
382
        poster="HiddenPoster",
383
        original="I am hidden reply",
384
        is_hidden=True,
385
    )
386

387
    reply.category.synchronize()
1✔
388
    reply.category.save()
1✔
389

390
    return reply
1✔
391

392

393
@pytest.fixture
1✔
394
def unapproved_reply(thread_reply_factory, thread):
1✔
395
    reply = thread_reply_factory(
1✔
396
        thread,
397
        poster="UnapprovedPoster",
398
        original="I am unapproved reply",
399
        is_unapproved=True,
400
    )
401

402
    reply.category.synchronize()
1✔
403
    reply.category.save()
1✔
404

405
    return reply
1✔
406

407

408
@pytest.fixture
1✔
409
def user_reply(thread_reply_factory, thread, user):
1✔
410
    reply = thread_reply_factory(
1✔
411
        thread,
412
        poster=user,
413
        original="I am user reply",
414
    )
415

416
    reply.category.synchronize()
1✔
417
    reply.category.save()
1✔
418

419
    return reply
1✔
420

421

422
@pytest.fixture
1✔
423
def user_hidden_reply(thread_reply_factory, thread, user):
1✔
424
    reply = thread_reply_factory(
1✔
425
        thread,
426
        poster=user,
427
        original="I am user hidden reply",
428
        is_hidden=True,
429
    )
430

431
    reply.category.synchronize()
1✔
432
    reply.category.save()
1✔
433

434
    return reply
1✔
435

436

437
@pytest.fixture
1✔
438
def user_unapproved_reply(thread_reply_factory, thread, user):
1✔
439
    reply = thread_reply_factory(
1✔
440
        thread,
441
        poster=user,
442
        original="I am user unapproved reply",
443
        is_unapproved=True,
444
    )
445

446
    reply.category.synchronize()
1✔
447
    reply.category.save()
1✔
448

449
    return reply
1✔
450

451

452
@pytest.fixture
1✔
453
def other_user_reply(thread_reply_factory, thread, other_user):
1✔
454
    reply = thread_reply_factory(
1✔
455
        thread,
456
        poster=other_user,
457
        original="I am other user reply",
458
    )
459

460
    reply.category.synchronize()
1✔
461
    reply.category.save()
1✔
462

463
    return reply
1✔
464

465

466
@pytest.fixture
1✔
467
def other_user_hidden_reply(thread_reply_factory, thread, other_user):
1✔
468
    reply = thread_reply_factory(
1✔
469
        thread,
470
        poster=other_user,
471
        original="I am user hidden reply",
472
        is_hidden=True,
473
    )
474

475
    reply.category.synchronize()
1✔
476
    reply.category.save()
1✔
477

478
    return reply
1✔
479

480

481
@pytest.fixture
1✔
482
def other_user_unapproved_reply(thread_reply_factory, thread, other_user):
1✔
483
    reply = thread_reply_factory(
1✔
484
        thread,
485
        poster=other_user,
486
        original="I am other user unapproved reply",
487
        is_unapproved=True,
488
    )
489

490
    reply.category.synchronize()
1✔
491
    reply.category.save()
1✔
492

493
    return reply
1✔
494

495

496
@pytest.fixture
1✔
497
def user_thread(thread_factory, default_category, user):
1✔
498
    thread = thread_factory(default_category, starter=user)
1✔
499

500
    default_category.synchronize()
1✔
501
    default_category.save()
1✔
502

503
    return thread
1✔
504

505

506
@pytest.fixture
1✔
507
def user_hidden_thread(thread_factory, default_category, user):
1✔
NEW
508
    thread = thread_factory(default_category, starter=user, is_hidden=True)
×
509

NEW
510
    default_category.synchronize()
×
NEW
511
    default_category.save()
×
512

NEW
513
    return thread
×
514

515

516
@pytest.fixture
1✔
517
def user_unapproved_thread(thread_factory, default_category, user):
1✔
NEW
518
    thread = thread_factory(default_category, starter=user, is_unapproved=True)
×
519

NEW
520
    default_category.synchronize()
×
NEW
521
    default_category.save()
×
522

NEW
523
    return thread
×
524

525

526
@pytest.fixture
1✔
527
def other_user_thread(thread_factory, default_category, other_user):
1✔
528
    thread = thread_factory(default_category, starter=other_user)
1✔
529

530
    default_category.synchronize()
1✔
531
    default_category.save()
1✔
532

533
    return thread
1✔
534

535

536
@pytest.fixture
1✔
537
def other_user_hidden_thread(thread_factory, default_category, other_user):
1✔
NEW
538
    thread = thread_factory(default_category, starter=other_user, is_hidden=True)
×
539

NEW
540
    default_category.synchronize()
×
NEW
541
    default_category.save()
×
542

NEW
543
    return thread
×
544

545

546
@pytest.fixture
1✔
547
def other_user_unapproved_thread(thread_factory, default_category, other_user):
1✔
NEW
548
    thread = thread_factory(default_category, starter=other_user, is_unapproved=True)
×
549

NEW
550
    default_category.synchronize()
×
NEW
551
    default_category.save()
×
552

NEW
553
    return thread
×
554

555

556
@pytest.fixture
1✔
557
def old_thread(thread_factory, default_category):
1✔
558
    thread = thread_factory(default_category, started_on=-3600)
1✔
559

560
    default_category.synchronize()
1✔
561
    default_category.save()
1✔
562

563
    return thread
1✔
564

565

566
@pytest.fixture
1✔
567
def old_user_thread(thread_factory, default_category, user):
1✔
NEW
568
    thread = thread_factory(default_category, started_on=-3600, starter=user)
×
569

NEW
570
    default_category.synchronize()
×
NEW
571
    default_category.save()
×
572

NEW
573
    return thread
×
574

575

576
@pytest.fixture
1✔
577
def old_other_user_thread(thread_factory, default_category, other_user):
1✔
578
    thread = thread_factory(default_category, started_on=-3600, starter=other_user)
1✔
579

580
    default_category.synchronize()
1✔
581
    default_category.save()
1✔
582

583
    return thread
1✔
584

585

586
@pytest.fixture
1✔
587
def old_thread_reply(thread_reply_factory, old_thread):
1✔
NEW
588
    reply = thread_reply_factory(old_thread)
×
589

NEW
590
    reply.category.synchronize()
×
NEW
591
    reply.category.save()
×
592

NEW
593
    return reply
×
594

595

596
@pytest.fixture
1✔
597
def old_thread_user_reply(thread_reply_factory, old_thread, user):
1✔
598
    reply = thread_reply_factory(old_thread, poster=user)
1✔
599

600
    reply.category.synchronize()
1✔
601
    reply.category.save()
1✔
602

603
    return reply
1✔
604

605

606
@pytest.fixture
1✔
607
def old_thread_other_user_reply(thread_reply_factory, old_thread, other_user):
1✔
NEW
608
    reply = thread_reply_factory(old_thread, poster=other_user)
×
609

NEW
610
    reply.category.synchronize()
×
NEW
611
    reply.category.save()
×
612

NEW
613
    return reply
×
614

615

616
@pytest.fixture
1✔
617
def old_user_thread_reply(thread_reply_factory, old_user_thread):
1✔
NEW
618
    reply = thread_reply_factory(old_user_thread)
×
619

NEW
620
    reply.category.synchronize()
×
NEW
621
    reply.category.save()
×
622

NEW
623
    return reply
×
624

625

626
@pytest.fixture
1✔
627
def old_user_thread_user_reply(thread_reply_factory, old_user_thread, user):
1✔
NEW
628
    reply = thread_reply_factory(old_user_thread, poster=user)
×
629

NEW
630
    reply.category.synchronize()
×
NEW
631
    reply.category.save()
×
632

NEW
633
    return reply
×
634

635

636
@pytest.fixture
1✔
637
def old_user_thread_other_user_reply(thread_reply_factory, old_user_thread, other_user):
1✔
NEW
638
    reply = thread_reply_factory(old_user_thread, poster=other_user)
×
639

NEW
640
    reply.category.synchronize()
×
NEW
641
    reply.category.save()
×
642

NEW
643
    return reply
×
644

645

646
@pytest.fixture
1✔
647
def old_other_user_thread_reply(thread_reply_factory, old_other_user_thread):
1✔
NEW
648
    reply = thread_reply_factory(old_other_user_thread)
×
649

NEW
650
    reply.category.synchronize()
×
NEW
651
    reply.category.save()
×
652

NEW
653
    return reply
×
654

655

656
@pytest.fixture
1✔
657
def old_other_user_thread_user_reply(thread_reply_factory, old_other_user_thread, user):
1✔
658
    reply = thread_reply_factory(old_other_user_thread, poster=user)
1✔
659

660
    reply.category.synchronize()
1✔
661
    reply.category.save()
1✔
662

663
    return reply
1✔
664

665

666
@pytest.fixture
1✔
667
def old_other_user_thread_other_user_reply(
1✔
668
    thread_reply_factory, old_other_user_thread, other_user
669
):
NEW
670
    reply = thread_reply_factory(old_other_user_thread, poster=other_user)
×
671

NEW
672
    reply.category.synchronize()
×
NEW
673
    reply.category.save()
×
674

NEW
675
    return reply
×
676

677

678
@pytest.fixture
1✔
679
def private_thread(thread_factory, private_threads_category):
1✔
680
    thread = thread_factory(private_threads_category)
1✔
681

682
    private_threads_category.synchronize()
1✔
683
    private_threads_category.save()
1✔
684

685
    return thread
1✔
686

687

688
@pytest.fixture
1✔
689
def private_thread_post(private_thread):
1✔
690
    return private_thread.first_post
1✔
691

692

693
@pytest.fixture
1✔
694
def private_thread_reply(thread_reply_factory, private_thread):
1✔
695
    reply = thread_reply_factory(private_thread, poster="Ghost")
1✔
696

697
    reply.category.synchronize()
1✔
698
    reply.category.save()
1✔
699

700
    return reply
1✔
701

702

703
@pytest.fixture
1✔
704
def private_thread_user_reply(thread_reply_factory, private_thread, user):
1✔
705
    reply = thread_reply_factory(private_thread, poster=user)
1✔
706

707
    reply.category.synchronize()
1✔
708
    reply.category.save()
1✔
709

710
    return reply
1✔
711

712

713
@pytest.fixture
1✔
714
def user_private_thread(
1✔
715
    thread_factory, private_threads_category, user, other_user, moderator
716
):
717
    thread = thread_factory(
1✔
718
        private_threads_category,
719
        title="User Private Thread",
720
        starter=user,
721
    )
722

723
    PrivateThreadMember.objects.create(thread=thread, user=user, is_owner=True)
1✔
724
    PrivateThreadMember.objects.create(thread=thread, user=other_user, is_owner=False)
1✔
725
    PrivateThreadMember.objects.create(thread=thread, user=moderator, is_owner=False)
1✔
726

727
    private_threads_category.synchronize()
1✔
728
    private_threads_category.save()
1✔
729

730
    return thread
1✔
731

732

733
@pytest.fixture
1✔
734
def other_user_private_thread(
1✔
735
    thread_factory, private_threads_category, user, other_user, moderator
736
):
737
    thread = thread_factory(
1✔
738
        private_threads_category,
739
        title="Other User Private Thread",
740
        starter=other_user,
741
    )
742

743
    PrivateThreadMember.objects.create(thread=thread, user=other_user, is_owner=True)
1✔
744
    PrivateThreadMember.objects.create(thread=thread, user=user, is_owner=False)
1✔
745
    PrivateThreadMember.objects.create(thread=thread, user=moderator, is_owner=False)
1✔
746

747
    private_threads_category.synchronize()
1✔
748
    private_threads_category.save()
1✔
749

750
    return thread
1✔
751

752

753
@pytest.fixture
1✔
754
def old_private_thread(thread_factory, private_threads_category):
1✔
755
    thread = thread_factory(private_threads_category, started_on=-3600)
1✔
756

757
    private_threads_category.synchronize()
1✔
758
    private_threads_category.save()
1✔
759

760
    return thread
1✔
761

762

763
@pytest.fixture
1✔
764
def old_private_thread_user_reply(thread_reply_factory, old_private_thread, user):
1✔
765
    reply = thread_reply_factory(old_private_thread, poster=user)
1✔
766

767
    reply.category.synchronize()
1✔
768
    reply.category.save()
1✔
769

770
    return reply
1✔
771

772

773
@pytest.fixture
1✔
774
def categories_tree(root_category):
1✔
775
    sibling_category = Category(
1✔
776
        name="Sibling Category",
777
        slug="sibling-category",
778
    )
779

780
    sibling_category.insert_at(root_category, position="last-child", save=True)
1✔
781

782
    child_category = Category(
1✔
783
        name="Child Category",
784
        slug="child-category",
785
        color="#FF0000",
786
    )
787

788
    child_category.insert_at(sibling_category, position="last-child", save=True)
1✔
789

790
    other_category = Category(
1✔
791
        name="Other Category",
792
        slug="other-category",
793
        short_name="Other",
794
    )
795

796
    other_category.insert_at(root_category, position="last-child", save=True)
1✔
797

798

799
@pytest.fixture
1✔
800
def sibling_category(categories_tree):
1✔
801
    return Category.objects.get(slug="sibling-category")
1✔
802

803

804
@pytest.fixture
1✔
805
def child_category(categories_tree):
1✔
806
    return Category.objects.get(slug="child-category")
1✔
807

808

809
@pytest.fixture
1✔
810
def other_category(categories_tree):
1✔
811
    return Category.objects.get(slug="other-category")
1✔
812

813

814
@pytest.fixture
1✔
815
def watched_thread_factory():
1✔
816
    def create_watched_thread(user: "User", thread: "Thread", send_emails: bool):
1✔
817
        thread_age = timezone.now() - thread.started_on
1✔
818
        if thread_age.total_seconds() < 10:
1✔
NEW
819
            raise ValueError(
×
820
                "'thread' passed to 'watched_thread_factory' must be "
821
                "at least 10 seconds old"
822
            )
823

824
        read_time = thread.started_on + timedelta(
1✔
825
            seconds=random.randint(1, int(thread_age.total_seconds()) - 1),
826
        )
827

828
        return WatchedThread.objects.create(
1✔
829
            user=user,
830
            category_id=thread.category_id,
831
            thread=thread,
832
            send_emails=send_emails,
833
            read_time=read_time,
834
        )
835

836
    return create_watched_thread
1✔
837

838

839
@pytest.fixture
1✔
840
def attachment_factory(db, teardown_attachments):
1✔
841
    def _attachment_factory(
1✔
842
        file_path: str,
843
        *,
844
        name=None,
845
        uploader=None,
846
        post=None,
847
        thumbnail_path=None,
848
        is_deleted=False,
849
    ):
850
        name = name or str(os.path.split(file_path)[-1])
1✔
851
        filetype = filetypes.match_filetype(name)
1✔
852
        content_type = filetype.content_types[0]
1✔
853
        assert filetype, f"'{name}' is not supported"
1✔
854

855
        with open(file_path, "rb") as fp:
1✔
856
            upload = SimpleUploadedFile(name, fp.read(), content_type)
1✔
857

858
        if thumbnail_path:
1✔
859
            thumbnail_filename = str(os.path.split(thumbnail_path)[-1])
1✔
860
            thumbnail_filetype = filetypes.match_filetype(name)
1✔
861
            thumbnail_content_type = thumbnail_filetype.content_types[0]
1✔
862
            assert thumbnail_filetype, f"'{thumbnail_filename}' is not supported"
1✔
863

864
            with open(thumbnail_path, "rb") as fp:
1✔
865
                thumbnail = SimpleUploadedFile(
1✔
866
                    thumbnail_filename, fp.read(), thumbnail_content_type
867
                )
868
                thumbnail_size = thumbnail.size
1✔
869
        else:
870
            thumbnail = None
1✔
871
            thumbnail_size = 0
1✔
872

873
        return Attachment.objects.create(
1✔
874
            category_id=post.category_id if post else None,
875
            thread_id=post.thread_id if post else None,
876
            post=post,
877
            uploader=uploader,
878
            uploader_name=uploader.username if uploader else "Anonymous",
879
            uploader_slug=uploader.slug if uploader else "anonymous",
880
            uploaded_at=timezone.now(),
881
            name=name,
882
            slug=slugify(name),
883
            filetype_id=filetype.id,
884
            upload=upload,
885
            size=upload.size,
886
            thumbnail=thumbnail,
887
            thumbnail_size=thumbnail_size,
888
            is_deleted=is_deleted,
889
        )
890

891
    return _attachment_factory
1✔
892

893

894
@pytest.fixture
1✔
895
def image_invalid():
1✔
896
    return IMAGE_INVALID
1✔
897

898

899
@pytest.fixture
1✔
900
def image_large():
1✔
901
    return IMAGE_LARGE
1✔
902

903

904
@pytest.fixture
1✔
905
def image_small():
1✔
906
    return IMAGE_SMALL
1✔
907

908

909
@pytest.fixture
1✔
910
def text_file():
1✔
911
    return TEXT_FILE
1✔
912

913

914
@pytest.fixture
1✔
915
def text_attachment(db):
1✔
916
    return Attachment.objects.create(
1✔
917
        uploader_name="Anonymous",
918
        uploader_slug="anonymous",
919
        uploaded_at=timezone.now(),
920
        name="text.txt",
921
        slug="text-txt",
922
        upload="attachments/text.txt",
923
        size=1024 * 1024,
924
        filetype_id="txt",
925
    )
926

927

928
@pytest.fixture
1✔
929
def image_attachment(db):
1✔
930
    return Attachment.objects.create(
1✔
931
        uploader_name="Anonymous",
932
        uploader_slug="anonymous",
933
        uploaded_at=timezone.now(),
934
        name="image.png",
935
        slug="image-png",
936
        upload="attachments/image.png",
937
        size=1024 * 1024,
938
        dimensions="200x200",
939
        filetype_id="png",
940
    )
941

942

943
@pytest.fixture
1✔
944
def image_thumbnail_attachment(db):
1✔
945
    return Attachment.objects.create(
1✔
946
        uploader_name="Anonymous",
947
        uploader_slug="anonymous",
948
        uploaded_at=timezone.now(),
949
        name="image-with-thumbnail.png",
950
        slug="image-with-thumbnail-png",
951
        upload="attachments/image-with-thumbnail.png",
952
        size=1024 * 1024,
953
        dimensions="200x200",
954
        thumbnail="attachments/image-thumbnail.png",
955
        thumbnail_size=128 * 1024,
956
        thumbnail_dimensions="50x50",
957
        filetype_id="png",
958
    )
959

960

961
@pytest.fixture
1✔
962
def video_attachment(db):
1✔
963
    return Attachment.objects.create(
1✔
964
        uploader_name="Anonymous",
965
        uploader_slug="anonymous",
966
        uploaded_at=timezone.now(),
967
        name="video.mp4",
968
        slug="video-mp4",
969
        upload="attachments/video.mp4",
970
        size=1024 * 1024,
971
        filetype_id="mp4",
972
    )
973

974

975
@pytest.fixture
1✔
976
def broken_text_attachment(db):
1✔
977
    return Attachment.objects.create(
1✔
978
        uploader_name="Anonymous",
979
        uploader_slug="anonymous",
980
        uploaded_at=timezone.now(),
981
        name="text.txt",
982
        slug="text-txt",
983
        size=1024 * 1024,
984
        filetype_id="txt",
985
    )
986

987

988
@pytest.fixture
1✔
989
def broken_image_attachment(db):
1✔
990
    return Attachment.objects.create(
1✔
991
        uploader_name="Anonymous",
992
        uploader_slug="anonymous",
993
        uploaded_at=timezone.now(),
994
        name="image.png",
995
        slug="image-png",
996
        size=1024 * 1024,
997
        dimensions="200x200",
998
        filetype_id="png",
999
    )
1000

1001

1002
@pytest.fixture
1✔
1003
def broken_video_attachment(db):
1✔
1004
    return Attachment.objects.create(
1✔
1005
        uploader_name="Anonymous",
1006
        uploader_slug="anonymous",
1007
        uploaded_at=timezone.now(),
1008
        name="video.mp4",
1009
        slug="video-mp4",
1010
        size=1024 * 1024,
1011
        filetype_id="mp4",
1012
    )
1013

1014

1015
@pytest.fixture
1✔
1016
def user_text_attachment(user):
1✔
1017
    return Attachment.objects.create(
1✔
1018
        uploader=user,
1019
        uploader_name=user.username,
1020
        uploader_slug=user.slug,
1021
        uploaded_at=timezone.now(),
1022
        name="user-text.txt",
1023
        slug="user-text-txt",
1024
        upload="attachments/user-text.txt",
1025
        size=1024 * 1024,
1026
        filetype_id="txt",
1027
    )
1028

1029

1030
@pytest.fixture
1✔
1031
def user_image_attachment(user):
1✔
1032
    return Attachment.objects.create(
1✔
1033
        uploader=user,
1034
        uploader_name=user.username,
1035
        uploader_slug=user.slug,
1036
        uploaded_at=timezone.now(),
1037
        name="user-image.png",
1038
        slug="user-image-png",
1039
        upload="attachments/user-image.png",
1040
        size=1024 * 1024,
1041
        dimensions="200x200",
1042
        filetype_id="png",
1043
    )
1044

1045

1046
@pytest.fixture
1✔
1047
def user_image_thumbnail_attachment(user):
1✔
1048
    return Attachment.objects.create(
1✔
1049
        uploader=user,
1050
        uploader_name=user.username,
1051
        uploader_slug=user.slug,
1052
        uploaded_at=timezone.now(),
1053
        name="user-image-with-thumbnail.png",
1054
        slug="user-image-with-thumbnail-png",
1055
        upload="attachments/user-image-with-thumbnail.png",
1056
        size=1024 * 1024,
1057
        dimensions="200x200",
1058
        thumbnail="attachments/user-image-thumbnail.png",
1059
        thumbnail_size=128 * 1024,
1060
        thumbnail_dimensions="50x50",
1061
        filetype_id="png",
1062
    )
1063

1064

1065
@pytest.fixture
1✔
1066
def user_video_attachment(user):
1✔
1067
    return Attachment.objects.create(
1✔
1068
        uploader=user,
1069
        uploader_name=user.username,
1070
        uploader_slug=user.slug,
1071
        uploaded_at=timezone.now(),
1072
        name="user-video.mp4",
1073
        slug="user-video-mp4",
1074
        upload="attachments/user-video.mp4",
1075
        size=1024 * 1024,
1076
        filetype_id="mp4",
1077
    )
1078

1079

1080
@pytest.fixture
1✔
1081
def user_broken_text_attachment(user):
1✔
1082
    return Attachment.objects.create(
1✔
1083
        uploader=user,
1084
        uploader_name=user.username,
1085
        uploader_slug=user.slug,
1086
        uploaded_at=timezone.now(),
1087
        name="user-text.txt",
1088
        slug="user-text-txt",
1089
        size=1024 * 1024,
1090
        filetype_id="txt",
1091
    )
1092

1093

1094
@pytest.fixture
1✔
1095
def user_broken_image_attachment(user):
1✔
1096
    return Attachment.objects.create(
×
1097
        uploader=user,
1098
        uploader_name=user.username,
1099
        uploader_slug=user.slug,
1100
        uploaded_at=timezone.now(),
1101
        name="user-image.png",
1102
        slug="user-image-png",
1103
        size=1024 * 1024,
1104
        dimensions="200x200",
1105
        filetype_id="png",
1106
    )
1107

1108

1109
@pytest.fixture
1✔
1110
def user_broken_video_attachment(user):
1✔
1111
    return Attachment.objects.create(
×
1112
        uploader=user,
1113
        uploader_name=user.username,
1114
        uploader_slug=user.slug,
1115
        uploaded_at=timezone.now(),
1116
        name="user-video.mp4",
1117
        slug="user-video-mp4",
1118
        size=1024 * 1024,
1119
        filetype_id="mp4",
1120
    )
1121

1122

1123
@pytest.fixture
1✔
1124
def other_user_text_attachment(other_user):
1✔
1125
    return Attachment.objects.create(
1✔
1126
        uploader=other_user,
1127
        uploader_name=other_user.username,
1128
        uploader_slug=other_user.slug,
1129
        uploaded_at=timezone.now(),
1130
        name="other_user-text.txt",
1131
        slug="other_user-text-txt",
1132
        upload="attachments/other_user-text.txt",
1133
        size=1024 * 1024,
1134
        filetype_id="txt",
1135
    )
1136

1137

1138
@pytest.fixture
1✔
1139
def other_user_image_attachment(other_user):
1✔
1140
    return Attachment.objects.create(
×
1141
        uploader=other_user,
1142
        uploader_name=other_user.username,
1143
        uploader_slug=other_user.slug,
1144
        uploaded_at=timezone.now(),
1145
        name="other_user-image.png",
1146
        slug="other_user-image-png",
1147
        upload="attachments/other_user-image.png",
1148
        size=1024 * 1024,
1149
        dimensions="200x200",
1150
        filetype_id="png",
1151
    )
1152

1153

1154
@pytest.fixture
1✔
1155
def other_user_video_attachment(other_user):
1✔
1156
    return Attachment.objects.create(
×
1157
        uploader=other_user,
1158
        uploader_name=other_user.username,
1159
        uploader_slug=other_user.slug,
1160
        uploaded_at=timezone.now(),
1161
        name="other_user-video.mp4",
1162
        slug="other_user-video-mp4",
1163
        upload="attachments/other_user-video.mp4",
1164
        size=1024 * 1024,
1165
        filetype_id="mp4",
1166
    )
1167

1168

1169
@pytest.fixture
1✔
1170
def other_user_broken_text_attachment(other_user):
1✔
1171
    return Attachment.objects.create(
×
1172
        uploader=other_user,
1173
        uploader_name=other_user.username,
1174
        uploader_slug=other_user.slug,
1175
        uploaded_at=timezone.now(),
1176
        name="other_user-text.txt",
1177
        slug="other_user-text-txt",
1178
        size=1024 * 1024,
1179
        filetype_id="txt",
1180
    )
1181

1182

1183
@pytest.fixture
1✔
1184
def other_user_broken_image_attachment(other_user):
1✔
1185
    return Attachment.objects.create(
×
1186
        uploader=other_user,
1187
        uploader_name=other_user.username,
1188
        uploader_slug=other_user.slug,
1189
        uploaded_at=timezone.now(),
1190
        name="other_user-image.png",
1191
        slug="other_user-image-png",
1192
        size=1024 * 1024,
1193
        dimensions="200x200",
1194
        filetype_id="png",
1195
    )
1196

1197

1198
@pytest.fixture
1✔
1199
def other_user_broken_video_attachment(other_user):
1✔
1200
    return Attachment.objects.create(
×
1201
        uploader=other_user,
1202
        uploader_name=other_user.username,
1203
        uploader_slug=other_user.slug,
1204
        uploaded_at=timezone.now(),
1205
        name="other_user-video.mp4",
1206
        slug="other_user-video-mp4",
1207
        size=1024 * 1024,
1208
        filetype_id="mp4",
1209
    )
1210

1211

1212
@pytest.fixture
1✔
1213
def social_auth_github(db):
1✔
1214
    return SocialAuthProvider.objects.create(
1✔
1215
        provider="github",
1216
        is_active=True,
1217
        order=SocialAuthProvider.objects.filter(is_active=True).count(),
1218
    )
1219

1220

1221
@pytest.fixture
1✔
1222
def social_auth_facebook(db):
1✔
1223
    return SocialAuthProvider.objects.create(
1✔
1224
        provider="facebook",
1225
        is_active=True,
1226
        order=SocialAuthProvider.objects.filter(is_active=True).count(),
1227
    )
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