Integrate Wagtail CMS and set up landing page structure (#2014)

This commit is contained in:
Greg Kaleka
2025-11-18 15:53:27 -05:00
parent 1e56c838b6
commit e0fe6d61e1
36 changed files with 1103 additions and 252 deletions

View File

@@ -39,7 +39,7 @@ class EmailUserAdmin(UserAdmin):
{
"fields": (
"can_update_image",
"image",
"profile_image",
)
},
),

View File

@@ -119,11 +119,11 @@ class CustomClearableFileInput(forms.ClearableFileInput):
class UserProfilePhotoForm(forms.ModelForm):
image = forms.FileField(widget=CustomClearableFileInput, required=False)
profile_image = forms.FileField(widget=CustomClearableFileInput, required=False)
class Meta:
model = User
fields = ["image"]
fields = ["profile_image"]
def clean(self):
"""Ensure a user can't update their photo if they
@@ -137,25 +137,24 @@ class UserProfilePhotoForm(forms.ModelForm):
def save(self, commit=True):
# Temporarily store the old image
old_image = self.instance.image
old_image = self.instance.profile_image
# Save the new image
user = super().save(commit=False)
if not old_image:
# reset image on image delete checked
user.image_uploaded = False
elif self.cleaned_data["image"] != old_image:
elif self.cleaned_data["profile_image"] != old_image:
# Delete the old image file if there's a new image being uploaded
old_image.delete(save=False)
if self.cleaned_data.get("image"):
new_image = self.cleaned_data["image"]
if new_image := self.cleaned_data.get("profile_image"):
_, file_extension = os.path.splitext(new_image.name)
# Strip the leading period from the file extension.
file_extension = file_extension.lstrip(".")
new_image.name = f"{user.profile_image_filename_root}.{file_extension}"
user.image = new_image
user.profile_image = new_image
user.image_uploaded = True
if commit:

View File

@@ -18,11 +18,11 @@ class Command(BaseCommand):
see your photo in the admin for whoever your first user is.
"""
user = User.objects.first()
user.image = None
user.profile_image = None
user.github_username = "testing"
user.save()
user.refresh_from_db()
assert bool(user.image) is False
assert bool(user.profile_image) is False
user.save_image_from_github()
user.refresh_from_db()
assert bool(user.image) is True
assert bool(user.profile_image) is True

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.2.8 on 2025-11-10 17:00
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("users", "0019_user_image_uploaded"),
]
operations = [
migrations.RenameField(
model_name="user",
old_name="image",
new_name="profile_image",
),
]

View File

@@ -204,14 +204,14 @@ class User(BaseUser):
is_commit_author_name_overridden = models.BooleanField(
default=False, help_text="Select to override the commit author with Username"
)
image = models.FileField(
profile_image = models.FileField(
upload_to="profile-images",
null=True,
blank=True,
validators=[image_validator, max_file_size_validator],
)
image_thumbnail = ImageSpecField(
source="image",
source="profile_image",
processors=[ResizeToFill(100, 100)],
format="JPEG",
options={"quality": 90},
@@ -269,7 +269,7 @@ class User(BaseUser):
response = requests.get(avatar_url)
filename = f"{self.profile_image_filename_root}.png"
self.image.save(filename, ContentFile(response.content), save=True)
self.profile_image.save(filename, ContentFile(response.content), save=True)
@cached_property
def profile_image_filename_root(self):
@@ -285,7 +285,7 @@ class User(BaseUser):
def get_thumbnail_url(self):
# convenience method for templates
if self.image and self.image_thumbnail:
if self.profile_image and self.image_thumbnail:
with suppress(AttributeError, MissingSource):
return getattr(self.image_thumbnail, "url", None)
@@ -324,9 +324,9 @@ class User(BaseUser):
self.last_name = "Doe"
self.display_name = "John Doe"
self.email = "deleted-{}@example.com".format(uuid.uuid4())
image = self.image
image = self.profile_image
transaction.on_commit(lambda: image.delete())
self.image = None
self.profile_image = None
self.image_thumbnail = None
self.delete_permanently_at = None
self.save()

View File

@@ -32,14 +32,14 @@ class CurrentUserSerializer(serializers.ModelSerializer):
"id",
"email",
"display_name",
"image",
"profile_image",
"date_joined",
"data",
)
read_only_fields = (
"id",
"email", # Users shouldn't change their email this way
"image",
"profile_image",
"date_joined",
)

View File

@@ -25,7 +25,7 @@ def user(db):
image = Image.new("RGBA", size=(100, 100), color=(155, 0, 0))
image.save(file, "png")
file.seek(0)
user.image.save(filename, file)
user.profile_image.save(filename, file)
user.set_password("password")
user.save()
@@ -50,7 +50,7 @@ def staff_user(db):
image = Image.new("RGBA", size=(100, 100), color=(155, 0, 0))
image.save(file, "png")
file.seek(0)
user.image.save(filename, file)
user.profile_image.save(filename, file)
user.set_password("password")
user.save()
@@ -76,7 +76,7 @@ def super_user(db):
image = Image.new("RGBA", size=(100, 100), color=(155, 0, 0))
image.save(file, "png")
file.seek(0)
user.image.save(filename, file)
user.profile_image.save(filename, file)
user.set_password("password")
user.save()

View File

@@ -189,10 +189,10 @@ def test_user_profile_photo_form_save(user):
return file
old_image = ImageFile(create_test_image_file(filename="initial_image.png"))
user.image.save("initial_image.png", old_image)
user.profile_image.save("initial_image.png", old_image)
# Make sure the initial image was saved
initial_path = user.image.path
initial_path = user.profile_image.path
assert initial_path is not None
# Create new image for upload
@@ -202,8 +202,8 @@ def test_user_profile_photo_form_save(user):
content_type="image/jpeg",
)
form = UserProfilePhotoForm({"image": new_image}, instance=user)
form = UserProfilePhotoForm({"profile_image": new_image}, instance=user)
assert form.is_valid()
updated_user = form.save()
updated_user.refresh_from_db()
assert str(user.pk) in updated_user.image.path
assert str(user.pk) in updated_user.profile_image.path

View File

@@ -40,7 +40,7 @@ def test_user_model_image_validator(user):
valid_image = SimpleUploadedFile(
"test.jpg", b"file_content", content_type="image/jpeg"
)
user.image = valid_image
user.profile_image = valid_image
# This should not raise any errors
user.full_clean()
@@ -48,7 +48,7 @@ def test_user_model_image_validator(user):
invalid_image = SimpleUploadedFile(
"test.pdf", b"file_content", content_type="application/pdf"
)
user.image = invalid_image
user.profile_image = invalid_image
# This should raise a ValidationError
with pytest.raises(ValidationError):
user.full_clean()
@@ -61,7 +61,7 @@ def test_user_model_image_file_size(user):
valid_image = SimpleUploadedFile(
"test.jpg", b"a" * (1 * 1024 * 1024 - 1), content_type="image/jpeg"
)
user.image = valid_image
user.profile_image = valid_image
# This should not raise any errors
user.full_clean()
@@ -69,7 +69,7 @@ def test_user_model_image_file_size(user):
invalid_image = SimpleUploadedFile(
"too_large.jpg", b"a" * (1 * 1024 * 1024 + 1), content_type="image/jpeg"
)
user.image = invalid_image
user.profile_image = invalid_image
# This should raise a ValidationError for file size
with pytest.raises(ValidationError):
user.full_clean()

View File

@@ -130,7 +130,7 @@ def test_current_user_profile_view_post_valid_photo(user, tp):
)
assert response.status_code == 200
user.refresh_from_db()
assert user.image
assert user.profile_image
# confirm that password was not changed, as these are on the same screen
assert user.check_password("password")