Skip to content

Commit 05a2da3

Browse files
committed
Refactor update_visibility
Refactor update_visibility Add VisibilityMixin to Package Optimize Package visibility from versions querying Use tuple instead of bitstring for comparing to original visibility
1 parent 35898ee commit 05a2da3

10 files changed

+270
-166
lines changed

django/thunderstore/community/migrations/0037_create_default_visibility_for_existing_listings.py

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,15 @@ def create_default_visibility_for_existing_records(apps, schema_editor):
2424

2525

2626
def update_visibility(listing):
27-
listing.visibility.public_detail = True
28-
listing.visibility.public_list = True
29-
listing.visibility.owner_detail = True
30-
listing.visibility.owner_list = True
31-
listing.visibility.moderator_detail = True
32-
listing.visibility.moderator_list = True
33-
34-
if not listing.package.is_active:
35-
listing.visibility.public_detail = False
36-
listing.visibility.public_list = False
37-
listing.visibility.owner_detail = False
38-
listing.visibility.owner_list = False
39-
listing.visibility.moderator_detail = False
40-
listing.visibility.moderator_list = False
27+
package = listing.package
28+
listing.visibility.public_detail = package.visibility.public_detail
29+
listing.visibility.public_list = package.visibility.public_list
30+
listing.visibility.owner_detail = package.visibility.owner_detail
31+
listing.visibility.owner_list = package.visibility.owner_list
32+
listing.visibility.moderator_detail = package.visibility.moderator_detail
33+
listing.visibility.moderator_list = package.visibility.moderator_list
34+
listing.visibility.admin_detail = package.visibility.admin_detail
35+
listing.visibility.admin_list = package.visibility.admin_list
4136

4237
if listing.review_status == PackageListingReviewStatus.rejected:
4338
listing.visibility.public_detail = False
@@ -50,28 +45,15 @@ def update_visibility(listing):
5045
listing.visibility.public_detail = False
5146
listing.visibility.public_list = False
5247

53-
versions = listing.package.versions.filter(is_active=True).all()
54-
if versions.exclude(visibility__public_detail=False).count() == 0:
55-
listing.visibility.public_detail = False
56-
if versions.exclude(visibility__public_list=False).count() == 0:
57-
listing.visibility.public_list = False
58-
if versions.exclude(visibility__owner_detail=False).count() == 0:
59-
listing.visibility.owner_detail = False
60-
if versions.exclude(visibility__owner_list=False).count() == 0:
61-
listing.visibility.owner_list = False
62-
if versions.exclude(visibility__moderator_detail=False).count() == 0:
63-
listing.visibility.moderator_detail = False
64-
if versions.exclude(visibility__moderator_list=False).count() == 0:
65-
listing.visibility.moderator_list = False
66-
6748
listing.visibility.save()
6849

6950

7051
class Migration(migrations.Migration):
7152

7253
dependencies = [
7354
("community", "0036_packagelisting_visibility"),
74-
("repository", "0058_create_default_visibility_for_existing_versions"),
55+
("repository", "0058_package_visibility"),
56+
("repository", "0059_create_default_visibility_for_existing_records"),
7557
]
7658

7759
operations = [

django/thunderstore/community/models/package_listing.py

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -407,32 +407,7 @@ def is_visible_to_user(self, user: Optional[UserType]) -> bool:
407407

408408
return False
409409

410-
@transaction.atomic
411-
def update_visibility(self):
412-
"""
413-
Updates the package listing's visibility based on whether its package is active, its review status,
414-
and the visibility of its active versions.
415-
416-
By default, listings are visible to everyone (for now). Rejected listings aren't publicly visible,
417-
and listings with inactive packages aren't visible at all.
418-
"""
419-
original_visibility_bitstring = self.visibility.bitstring()
420-
421-
self.visibility.public_detail = True
422-
self.visibility.public_list = True
423-
self.visibility.owner_detail = True
424-
self.visibility.owner_list = True
425-
self.visibility.moderator_detail = True
426-
self.visibility.moderator_list = True
427-
428-
if not self.package.is_active:
429-
self.visibility.public_detail = False
430-
self.visibility.public_list = False
431-
self.visibility.owner_detail = False
432-
self.visibility.owner_list = False
433-
self.visibility.moderator_detail = False
434-
self.visibility.moderator_list = False
435-
410+
def set_visibility_from_review_status(self):
436411
if self.review_status == PackageListingReviewStatus.rejected:
437412
self.visibility.public_detail = False
438413
self.visibility.public_list = False
@@ -444,22 +419,13 @@ def update_visibility(self):
444419
self.visibility.public_detail = False
445420
self.visibility.public_list = False
446421

447-
versions = self.package.versions.filter(is_active=True).all()
448-
if versions.exclude(visibility__public_detail=False).count() == 0:
449-
self.visibility.public_detail = False
450-
if versions.exclude(visibility__public_list=False).count() == 0:
451-
self.visibility.public_list = False
452-
if versions.exclude(visibility__owner_detail=False).count() == 0:
453-
self.visibility.owner_detail = False
454-
if versions.exclude(visibility__owner_list=False).count() == 0:
455-
self.visibility.owner_list = False
456-
if versions.exclude(visibility__moderator_detail=False).count() == 0:
457-
self.visibility.moderator_detail = False
458-
if versions.exclude(visibility__moderator_list=False).count() == 0:
459-
self.visibility.moderator_list = False
460-
461-
if self.visibility.bitstring != original_visibility_bitstring:
462-
self.visibility.save()
422+
@transaction.atomic
423+
def update_visibility(self):
424+
self.visibility.copy_from(self.package.visibility)
425+
426+
self.set_visibility_from_review_status()
427+
428+
self.visibility.save()
463429

464430

465431
signals.post_save.connect(PackageListing.post_save, sender=PackageListing)

django/thunderstore/permissions/mixins.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ class VisibilityMixin(models.Model):
5757
def update_visibility(self):
5858
pass
5959

60+
def set_default_visibility(self):
61+
self.visibility.public_detail = True
62+
self.visibility.public_list = True
63+
self.visibility.owner_detail = True
64+
self.visibility.owner_list = True
65+
self.visibility.moderator_detail = True
66+
self.visibility.moderator_list = True
67+
self.visibility.admin_detail = True
68+
self.visibility.admin_list = True
69+
6070
@transaction.atomic
6171
def save(self, *args, **kwargs):
6272
if not self.pk and not self.visibility:

django/thunderstore/permissions/models/visibility.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ def __str__(self) -> str:
3636
)
3737
return ", ".join(flag_fields) or "None"
3838

39-
def bitstring(self) -> str:
40-
fields = [
39+
def as_tuple(self):
40+
return (
4141
self.public_list,
4242
self.public_detail,
4343
self.owner_list,
@@ -46,5 +46,14 @@ def bitstring(self) -> str:
4646
self.moderator_detail,
4747
self.admin_list,
4848
self.admin_detail,
49-
]
50-
return "".join("1" if field else "0" for field in fields)
49+
)
50+
51+
def copy_from(self, from_visibility):
52+
self.public_detail = from_visibility.public_detail
53+
self.public_list = from_visibility.public_list
54+
self.owner_detail = from_visibility.owner_detail
55+
self.owner_list = from_visibility.owner_list
56+
self.moderator_detail = from_visibility.moderator_detail
57+
self.moderator_list = from_visibility.moderator_list
58+
self.admin_detail = from_visibility.admin_detail
59+
self.admin_list = from_visibility.admin_list

django/thunderstore/repository/migrations/0058_create_default_visibility_for_existing_versions.py

Lines changed: 0 additions & 62 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Generated by Django 3.1.7 on 2025-05-09 21:32
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
("permissions", "0001_initial"),
11+
("repository", "0057_packageversion_review_status"),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name="package",
17+
name="visibility",
18+
field=models.OneToOneField(
19+
blank=True,
20+
null=True,
21+
on_delete=django.db.models.deletion.PROTECT,
22+
to="permissions.visibilityflags",
23+
),
24+
),
25+
]
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
from django.db import migrations
2+
3+
from thunderstore.repository.consts import PackageVersionReviewStatus
4+
5+
6+
def create_default_visibility_for_existing_records(apps, schema_editor):
7+
PackageVersion = apps.get_model("repository", "PackageVersion")
8+
Package = apps.get_model("repository", "Package")
9+
VisibilityFlags = apps.get_model("permissions", "VisibilityFlags")
10+
11+
for instance in PackageVersion.objects.filter(visibility__isnull=True):
12+
visibility_flags = VisibilityFlags.objects.create(
13+
public_list=False,
14+
public_detail=False,
15+
owner_list=True,
16+
owner_detail=True,
17+
moderator_list=True,
18+
moderator_detail=True,
19+
admin_list=True,
20+
admin_detail=True,
21+
)
22+
instance.visibility = visibility_flags
23+
instance.save()
24+
update_version_visibility(instance)
25+
26+
for instance in Package.objects.filter(visibility__isnull=True):
27+
visibility_flags = VisibilityFlags.objects.create(
28+
public_list=False,
29+
public_detail=False,
30+
owner_list=True,
31+
owner_detail=True,
32+
moderator_list=True,
33+
moderator_detail=True,
34+
admin_list=True,
35+
admin_detail=True,
36+
)
37+
instance.visibility = visibility_flags
38+
instance.save()
39+
update_package_visibility(instance)
40+
41+
42+
def update_version_visibility(version):
43+
version.visibility.public_detail = True
44+
version.visibility.public_list = True
45+
version.visibility.owner_detail = True
46+
version.visibility.owner_list = True
47+
version.visibility.moderator_detail = True
48+
version.visibility.moderator_list = True
49+
50+
if not version.is_active or not version.package.is_active:
51+
version.visibility.public_detail = False
52+
version.visibility.public_list = False
53+
version.visibility.owner_detail = False
54+
version.visibility.owner_list = False
55+
version.visibility.moderator_detail = False
56+
version.visibility.moderator_list = False
57+
58+
if (
59+
version.review_status == PackageVersionReviewStatus.rejected
60+
or version.review_status == PackageVersionReviewStatus.pending
61+
):
62+
version.visibility.public_detail = False
63+
version.visibility.public_list = False
64+
65+
version.visibility.save()
66+
67+
68+
def update_package_visibility(package):
69+
package.visibility.public_detail = True
70+
package.visibility.public_list = True
71+
package.visibility.owner_detail = True
72+
package.visibility.owner_list = True
73+
package.visibility.moderator_detail = True
74+
package.visibility.moderator_list = True
75+
76+
if not package.is_active:
77+
package.visibility.public_detail = False
78+
package.visibility.public_list = False
79+
package.visibility.owner_detail = False
80+
package.visibility.owner_list = False
81+
package.visibility.moderator_detail = False
82+
package.visibility.moderator_list = False
83+
84+
visibility_fields = [
85+
"public_detail",
86+
"public_list",
87+
"owner_detail",
88+
"owner_list",
89+
"moderator_detail",
90+
"moderator_list",
91+
]
92+
93+
versions = list(
94+
package.versions.filter(is_active=True).values(
95+
*[f"visibility__{field}" for field in visibility_fields]
96+
)
97+
)
98+
99+
any_version_visible = {field: False for field in visibility_fields}
100+
101+
for field in visibility_fields:
102+
for version in versions:
103+
if version[f"visibility__{field}"]:
104+
any_version_visible[field] = True
105+
break
106+
107+
for field, exists in any_version_visible.items():
108+
if not exists:
109+
setattr(package.visibility, field, False)
110+
111+
package.visibility.save()
112+
113+
114+
class Migration(migrations.Migration):
115+
116+
dependencies = [
117+
("repository", "0058_package_visibility"),
118+
]
119+
120+
operations = [
121+
migrations.RunPython(
122+
create_default_visibility_for_existing_records, migrations.RunPython.noop
123+
),
124+
]

0 commit comments

Comments
 (0)