Enable avatar functionality for user profiles and create new migrations

Enable the avatar field in the UserProfile model and associated event tracking, alongside new migrations for core, parks, and rides modules.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: eff39de1-3afa-446d-a965-acaf61837fc7
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/d6d61dac-164d-45dd-929f-7dcdfd771b64/eff39de1-3afa-446d-a965-acaf61837fc7/RPze4Xv
This commit is contained in:
pac7
2025-09-21 01:32:33 +00:00
committed by pacnpal
parent 31b7e5ee53
commit 9e0259f739
10 changed files with 5285 additions and 49 deletions

View File

@@ -34,3 +34,7 @@ outputType = "webview"
[[ports]] [[ports]]
localPort = 5000 localPort = 5000
externalPort = 80 externalPort = 80
[[ports]]
localPort = 32787
externalPort = 3000

View File

@@ -1,4 +1,4 @@
# Generated by Django 5.2.6 on 2025-09-21 01:19 # Generated by Django 5.2.6 on 2025-09-21 01:29
import apps.core.choices.fields import apps.core.choices.fields
import django.contrib.auth.models import django.contrib.auth.models

View File

@@ -0,0 +1,77 @@
# Generated by Django 5.2.6 on 2025-09-21 01:29
import django.db.models.deletion
import pgtrigger.compiler
import pgtrigger.migrations
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("accounts", "0001_initial"),
("django_cloudflareimages_toolkit", "0001_initial"),
]
operations = [
pgtrigger.migrations.RemoveTrigger(
model_name="userprofile",
name="insert_insert",
),
pgtrigger.migrations.RemoveTrigger(
model_name="userprofile",
name="update_update",
),
migrations.AddField(
model_name="userprofile",
name="avatar",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="django_cloudflareimages_toolkit.cloudflareimage",
),
),
migrations.AddField(
model_name="userprofileevent",
name="avatar",
field=models.ForeignKey(
blank=True,
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
related_query_name="+",
to="django_cloudflareimages_toolkit.cloudflareimage",
),
),
pgtrigger.migrations.AddTrigger(
model_name="userprofile",
trigger=pgtrigger.compiler.Trigger(
name="insert_insert",
sql=pgtrigger.compiler.UpsertTriggerSql(
func='INSERT INTO "accounts_userprofileevent" ("avatar_id", "bio", "coaster_credits", "dark_ride_credits", "discord", "display_name", "flat_ride_credits", "id", "instagram", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "profile_id", "pronouns", "twitter", "user_id", "water_ride_credits", "youtube") VALUES (NEW."avatar_id", NEW."bio", NEW."coaster_credits", NEW."dark_ride_credits", NEW."discord", NEW."display_name", NEW."flat_ride_credits", NEW."id", NEW."instagram", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."profile_id", NEW."pronouns", NEW."twitter", NEW."user_id", NEW."water_ride_credits", NEW."youtube"); RETURN NULL;',
hash="a7ecdb1ac2821dea1fef4ec917eeaf6b8e4f09c8",
operation="INSERT",
pgid="pgtrigger_insert_insert_c09d7",
table="accounts_userprofile",
when="AFTER",
),
),
),
pgtrigger.migrations.AddTrigger(
model_name="userprofile",
trigger=pgtrigger.compiler.Trigger(
name="update_update",
sql=pgtrigger.compiler.UpsertTriggerSql(
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
func='INSERT INTO "accounts_userprofileevent" ("avatar_id", "bio", "coaster_credits", "dark_ride_credits", "discord", "display_name", "flat_ride_credits", "id", "instagram", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "profile_id", "pronouns", "twitter", "user_id", "water_ride_credits", "youtube") VALUES (NEW."avatar_id", NEW."bio", NEW."coaster_credits", NEW."dark_ride_credits", NEW."discord", NEW."display_name", NEW."flat_ride_credits", NEW."id", NEW."instagram", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."profile_id", NEW."pronouns", NEW."twitter", NEW."user_id", NEW."water_ride_credits", NEW."youtube"); RETURN NULL;',
hash="81607e492ffea2a4c741452b860ee660374cc01d",
operation="UPDATE",
pgid="pgtrigger_update_update_87ef6",
table="accounts_userprofile",
when="AFTER",
),
),
),
]

View File

@@ -149,12 +149,12 @@ class UserProfile(models.Model):
blank=True, blank=True,
help_text="Legacy display name field - use User.display_name instead", help_text="Legacy display name field - use User.display_name instead",
) )
# avatar = models.ForeignKey( avatar = models.ForeignKey(
# 'django_cloudflareimages_toolkit.CloudflareImage', 'django_cloudflareimages_toolkit.CloudflareImage',
# on_delete=models.SET_NULL, on_delete=models.SET_NULL,
# null=True, null=True,
# blank=True blank=True
# ) )
pronouns = models.CharField(max_length=50, blank=True) pronouns = models.CharField(max_length=50, blank=True)
bio = models.TextField(max_length=500, blank=True) bio = models.TextField(max_length=500, blank=True)
@@ -175,27 +175,26 @@ class UserProfile(models.Model):
""" """
Return the avatar URL or generate a default letter-based avatar URL Return the avatar URL or generate a default letter-based avatar URL
""" """
# Avatar field temporarily disabled - return default avatar if self.avatar and self.avatar.is_uploaded:
# if self.avatar and self.avatar.is_uploaded: # Try to get avatar variant first, fallback to public
# # Try to get avatar variant first, fallback to public avatar_url = self.avatar.get_url('avatar')
# avatar_url = self.avatar.get_url('avatar') if avatar_url:
# if avatar_url: return avatar_url
# return avatar_url
# # Fallback to public variant # Fallback to public variant
# public_url = self.avatar.get_url('public') public_url = self.avatar.get_url('public')
# if public_url: if public_url:
# return public_url return public_url
# # Last fallback - try any available variant # Last fallback - try any available variant
# if self.avatar.variants: if self.avatar.variants:
# if isinstance(self.avatar.variants, list) and self.avatar.variants: if isinstance(self.avatar.variants, list) and self.avatar.variants:
# return self.avatar.variants[0] return self.avatar.variants[0]
# elif isinstance(self.avatar.variants, dict): elif isinstance(self.avatar.variants, dict):
# # Return first available variant # Return first available variant
# for variant_url in self.avatar.variants.values(): for variant_url in self.avatar.variants.values():
# if variant_url: if variant_url:
# return variant_url return variant_url
# Generate default letter-based avatar using first letter of username # Generate default letter-based avatar using first letter of username
first_letter = self.user.username[0].upper() if self.user.username else "U" first_letter = self.user.username[0].upper() if self.user.username else "U"
@@ -206,33 +205,32 @@ class UserProfile(models.Model):
""" """
Return avatar variants for different use cases Return avatar variants for different use cases
""" """
# Avatar field temporarily disabled - return default variants if self.avatar and self.avatar.is_uploaded:
# if self.avatar and self.avatar.is_uploaded: variants = {}
# variants = {}
# # Try to get specific variants # Try to get specific variants
# thumbnail_url = self.avatar.get_url('thumbnail') thumbnail_url = self.avatar.get_url('thumbnail')
# avatar_url = self.avatar.get_url('avatar') avatar_url = self.avatar.get_url('avatar')
# large_url = self.avatar.get_url('large') large_url = self.avatar.get_url('large')
# public_url = self.avatar.get_url('public') public_url = self.avatar.get_url('public')
# # Use specific variants if available, otherwise fallback to public or first available # Use specific variants if available, otherwise fallback to public or first available
# fallback_url = public_url fallback_url = public_url
# if not fallback_url and self.avatar.variants: if not fallback_url and self.avatar.variants:
# if isinstance(self.avatar.variants, list) and self.avatar.variants: if isinstance(self.avatar.variants, list) and self.avatar.variants:
# fallback_url = self.avatar.variants[0] fallback_url = self.avatar.variants[0]
# elif isinstance(self.avatar.variants, dict): elif isinstance(self.avatar.variants, dict):
# fallback_url = next(iter(self.avatar.variants.values()), None) fallback_url = next(iter(self.avatar.variants.values()), None)
# variants = { variants = {
# "thumbnail": thumbnail_url or fallback_url, "thumbnail": thumbnail_url or fallback_url,
# "avatar": avatar_url or fallback_url, "avatar": avatar_url or fallback_url,
# "large": large_url or fallback_url, "large": large_url or fallback_url,
# } }
# # Only return variants if we have at least one valid URL # Only return variants if we have at least one valid URL
# if any(variants.values()): if any(variants.values()):
# return variants return variants
# For default avatars, return the same URL for all variants # For default avatars, return the same URL for all variants
default_url = self.get_avatar_url() default_url = self.get_avatar_url()

View File

@@ -0,0 +1,292 @@
# Generated by Django 5.2.6 on 2025-09-21 01:27
import django.db.models.deletion
import pgtrigger.compiler
import pgtrigger.migrations
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
("contenttypes", "0002_remove_content_type_name"),
("pghistory", "0007_auto_20250421_0444"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="PageView",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("object_id", models.PositiveIntegerField()),
("timestamp", models.DateTimeField(auto_now_add=True, db_index=True)),
("ip_address", models.GenericIPAddressField()),
("user_agent", models.CharField(blank=True, max_length=512)),
(
"content_type",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="page_views",
to="contenttypes.contenttype",
),
),
],
),
migrations.CreateModel(
name="PageViewEvent",
fields=[
("pgh_id", models.AutoField(primary_key=True, serialize=False)),
("pgh_created_at", models.DateTimeField(auto_now_add=True)),
("pgh_label", models.TextField(help_text="The event label.")),
("id", models.BigIntegerField()),
("object_id", models.PositiveIntegerField()),
("timestamp", models.DateTimeField(auto_now_add=True)),
("ip_address", models.GenericIPAddressField()),
("user_agent", models.CharField(blank=True, max_length=512)),
(
"content_type",
models.ForeignKey(
db_constraint=False,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
related_query_name="+",
to="contenttypes.contenttype",
),
),
(
"pgh_context",
models.ForeignKey(
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="pghistory.context",
),
),
(
"pgh_obj",
models.ForeignKey(
db_constraint=False,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="events",
to="core.pageview",
),
),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="SlugHistory",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("object_id", models.CharField(max_length=50)),
("old_slug", models.SlugField(max_length=200)),
("created_at", models.DateTimeField(auto_now_add=True)),
(
"content_type",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="contenttypes.contenttype",
),
),
],
options={
"verbose_name_plural": "Slug histories",
"ordering": ["-created_at"],
},
),
migrations.CreateModel(
name="SlugHistoryEvent",
fields=[
("pgh_id", models.AutoField(primary_key=True, serialize=False)),
("pgh_created_at", models.DateTimeField(auto_now_add=True)),
("pgh_label", models.TextField(help_text="The event label.")),
("id", models.BigIntegerField()),
("object_id", models.CharField(max_length=50)),
("old_slug", models.SlugField(db_index=False, max_length=200)),
("created_at", models.DateTimeField(auto_now_add=True)),
(
"content_type",
models.ForeignKey(
db_constraint=False,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
related_query_name="+",
to="contenttypes.contenttype",
),
),
(
"pgh_context",
models.ForeignKey(
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="pghistory.context",
),
),
(
"pgh_obj",
models.ForeignKey(
db_constraint=False,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="events",
to="core.slughistory",
),
),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="HistoricalSlug",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("object_id", models.PositiveIntegerField()),
("slug", models.SlugField(max_length=255)),
("created_at", models.DateTimeField(auto_now_add=True)),
(
"content_type",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="contenttypes.contenttype",
),
),
(
"user",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="historical_slugs",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"indexes": [
models.Index(
fields=["content_type", "object_id"],
name="core_histor_content_b4c470_idx",
),
models.Index(fields=["slug"], name="core_histor_slug_8fd7b3_idx"),
],
"unique_together": {("content_type", "slug")},
},
),
migrations.AddIndex(
model_name="pageview",
index=models.Index(
fields=["timestamp"], name="core_pagevi_timesta_757ebb_idx"
),
),
migrations.AddIndex(
model_name="pageview",
index=models.Index(
fields=["content_type", "object_id"],
name="core_pagevi_content_eda7ad_idx",
),
),
pgtrigger.migrations.AddTrigger(
model_name="pageview",
trigger=pgtrigger.compiler.Trigger(
name="insert_insert",
sql=pgtrigger.compiler.UpsertTriggerSql(
func='INSERT INTO "core_pageviewevent" ("content_type_id", "id", "ip_address", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "timestamp", "user_agent") VALUES (NEW."content_type_id", NEW."id", NEW."ip_address", NEW."object_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."timestamp", NEW."user_agent"); RETURN NULL;',
hash="1682d124ea3ba215e630c7cfcde929f7444cf247",
operation="INSERT",
pgid="pgtrigger_insert_insert_ee1e1",
table="core_pageview",
when="AFTER",
),
),
),
pgtrigger.migrations.AddTrigger(
model_name="pageview",
trigger=pgtrigger.compiler.Trigger(
name="update_update",
sql=pgtrigger.compiler.UpsertTriggerSql(
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
func='INSERT INTO "core_pageviewevent" ("content_type_id", "id", "ip_address", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "timestamp", "user_agent") VALUES (NEW."content_type_id", NEW."id", NEW."ip_address", NEW."object_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."timestamp", NEW."user_agent"); RETURN NULL;',
hash="4221b2dd6636cae454f8d69c0c1841c40c47e6a6",
operation="UPDATE",
pgid="pgtrigger_update_update_3c505",
table="core_pageview",
when="AFTER",
),
),
),
migrations.AddIndex(
model_name="slughistory",
index=models.Index(
fields=["content_type", "object_id"],
name="core_slughi_content_8bbf56_idx",
),
),
migrations.AddIndex(
model_name="slughistory",
index=models.Index(
fields=["old_slug"], name="core_slughi_old_slu_aaef7f_idx"
),
),
pgtrigger.migrations.AddTrigger(
model_name="slughistory",
trigger=pgtrigger.compiler.Trigger(
name="insert_insert",
sql=pgtrigger.compiler.UpsertTriggerSql(
func='INSERT INTO "core_slughistoryevent" ("content_type_id", "created_at", "id", "object_id", "old_slug", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id") VALUES (NEW."content_type_id", NEW."created_at", NEW."id", NEW."object_id", NEW."old_slug", _pgh_attach_context(), NOW(), \'insert\', NEW."id"); RETURN NULL;',
hash="2a2a05025693c165b88e5eba7fcc23214749a78b",
operation="INSERT",
pgid="pgtrigger_insert_insert_3002a",
table="core_slughistory",
when="AFTER",
),
),
),
pgtrigger.migrations.AddTrigger(
model_name="slughistory",
trigger=pgtrigger.compiler.Trigger(
name="update_update",
sql=pgtrigger.compiler.UpsertTriggerSql(
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
func='INSERT INTO "core_slughistoryevent" ("content_type_id", "created_at", "id", "object_id", "old_slug", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id") VALUES (NEW."content_type_id", NEW."created_at", NEW."id", NEW."object_id", NEW."old_slug", _pgh_attach_context(), NOW(), \'update\', NEW."id"); RETURN NULL;',
hash="3ad197ccb6178668e762720341e45d3fd3216776",
operation="UPDATE",
pgid="pgtrigger_update_update_52030",
table="core_slughistory",
when="AFTER",
),
),
),
]

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff