mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-21 14:11:08 -05:00
feat: Implement Entity Suggestion Manager and Modal components
- Added EntitySuggestionManager.vue to manage entity suggestions and authentication. - Created EntitySuggestionModal.vue for displaying suggestions and adding new entities. - Integrated AuthManager for user authentication within the suggestion modal. - Enhanced signal handling in start-servers.sh for graceful shutdown of servers. - Improved server startup script to ensure proper cleanup and responsiveness to termination signals. - Added documentation for signal handling fixes and usage instructions.
This commit is contained in:
603
backend/apps/rides/migrations/0006_add_ride_rankings.py
Normal file
603
backend/apps/rides/migrations/0006_add_ride_rankings.py
Normal file
@@ -0,0 +1,603 @@
|
||||
# Generated by Django 5.2.5 on 2025-08-25 00:50
|
||||
|
||||
import django.core.validators
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("pghistory", "0007_auto_20250421_0444"),
|
||||
("rides", "0005_ridelocationevent_ridelocation_insert_insert_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="RidePairComparison",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_a_wins",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of mutual riders who rated ride_a higher",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_b_wins",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of mutual riders who rated ride_b higher",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ties",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of mutual riders who rated both rides equally",
|
||||
),
|
||||
),
|
||||
(
|
||||
"mutual_riders_count",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Total number of users who have rated both rides",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_a_avg_rating",
|
||||
models.DecimalField(
|
||||
blank=True,
|
||||
decimal_places=2,
|
||||
help_text="Average rating of ride_a from mutual riders",
|
||||
max_digits=3,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_b_avg_rating",
|
||||
models.DecimalField(
|
||||
blank=True,
|
||||
decimal_places=2,
|
||||
help_text="Average rating of ride_b from mutual riders",
|
||||
max_digits=3,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"last_calculated",
|
||||
models.DateTimeField(
|
||||
auto_now=True,
|
||||
help_text="When this comparison was last calculated",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_a",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="comparisons_as_a",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_b",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="comparisons_as_b",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="RidePairComparisonEvent",
|
||||
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()),
|
||||
(
|
||||
"ride_a_wins",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of mutual riders who rated ride_a higher",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_b_wins",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of mutual riders who rated ride_b higher",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ties",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of mutual riders who rated both rides equally",
|
||||
),
|
||||
),
|
||||
(
|
||||
"mutual_riders_count",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Total number of users who have rated both rides",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_a_avg_rating",
|
||||
models.DecimalField(
|
||||
blank=True,
|
||||
decimal_places=2,
|
||||
help_text="Average rating of ride_a from mutual riders",
|
||||
max_digits=3,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_b_avg_rating",
|
||||
models.DecimalField(
|
||||
blank=True,
|
||||
decimal_places=2,
|
||||
help_text="Average rating of ride_b from mutual riders",
|
||||
max_digits=3,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"last_calculated",
|
||||
models.DateTimeField(
|
||||
auto_now=True,
|
||||
help_text="When this comparison was last calculated",
|
||||
),
|
||||
),
|
||||
(
|
||||
"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="rides.ridepaircomparison",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_a",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride_b",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="RideRanking",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"rank",
|
||||
models.PositiveIntegerField(
|
||||
db_index=True, help_text="Overall rank position (1 = best)"
|
||||
),
|
||||
),
|
||||
(
|
||||
"wins",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of rides this ride beats in pairwise comparisons",
|
||||
),
|
||||
),
|
||||
(
|
||||
"losses",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of rides that beat this ride in pairwise comparisons",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ties",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of rides with equal preference in pairwise comparisons",
|
||||
),
|
||||
),
|
||||
(
|
||||
"winning_percentage",
|
||||
models.DecimalField(
|
||||
db_index=True,
|
||||
decimal_places=4,
|
||||
help_text="Win percentage where ties count as 0.5",
|
||||
max_digits=5,
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(0),
|
||||
django.core.validators.MaxValueValidator(1),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"mutual_riders_count",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Total number of users who have rated this ride",
|
||||
),
|
||||
),
|
||||
(
|
||||
"comparison_count",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of other rides this was compared against",
|
||||
),
|
||||
),
|
||||
(
|
||||
"average_rating",
|
||||
models.DecimalField(
|
||||
blank=True,
|
||||
decimal_places=2,
|
||||
help_text="Average rating from all users who have rated this ride",
|
||||
max_digits=3,
|
||||
null=True,
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(1),
|
||||
django.core.validators.MaxValueValidator(10),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"last_calculated",
|
||||
models.DateTimeField(
|
||||
default=django.utils.timezone.now,
|
||||
help_text="When this ranking was last calculated",
|
||||
),
|
||||
),
|
||||
(
|
||||
"calculation_version",
|
||||
models.CharField(
|
||||
default="1.0",
|
||||
help_text="Algorithm version used for calculation",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride",
|
||||
models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="ranking",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["rank"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="RideRankingEvent",
|
||||
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()),
|
||||
(
|
||||
"rank",
|
||||
models.PositiveIntegerField(
|
||||
help_text="Overall rank position (1 = best)"
|
||||
),
|
||||
),
|
||||
(
|
||||
"wins",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of rides this ride beats in pairwise comparisons",
|
||||
),
|
||||
),
|
||||
(
|
||||
"losses",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of rides that beat this ride in pairwise comparisons",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ties",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of rides with equal preference in pairwise comparisons",
|
||||
),
|
||||
),
|
||||
(
|
||||
"winning_percentage",
|
||||
models.DecimalField(
|
||||
decimal_places=4,
|
||||
help_text="Win percentage where ties count as 0.5",
|
||||
max_digits=5,
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(0),
|
||||
django.core.validators.MaxValueValidator(1),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"mutual_riders_count",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Total number of users who have rated this ride",
|
||||
),
|
||||
),
|
||||
(
|
||||
"comparison_count",
|
||||
models.PositiveIntegerField(
|
||||
default=0,
|
||||
help_text="Number of other rides this was compared against",
|
||||
),
|
||||
),
|
||||
(
|
||||
"average_rating",
|
||||
models.DecimalField(
|
||||
blank=True,
|
||||
decimal_places=2,
|
||||
help_text="Average rating from all users who have rated this ride",
|
||||
max_digits=3,
|
||||
null=True,
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(1),
|
||||
django.core.validators.MaxValueValidator(10),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"last_calculated",
|
||||
models.DateTimeField(
|
||||
default=django.utils.timezone.now,
|
||||
help_text="When this ranking was last calculated",
|
||||
),
|
||||
),
|
||||
(
|
||||
"calculation_version",
|
||||
models.CharField(
|
||||
default="1.0",
|
||||
help_text="Algorithm version used for calculation",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
(
|
||||
"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="rides.rideranking",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride",
|
||||
models.ForeignKey(
|
||||
db_constraint=False,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
related_name="+",
|
||||
related_query_name="+",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="RankingSnapshot",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("rank", models.PositiveIntegerField()),
|
||||
(
|
||||
"winning_percentage",
|
||||
models.DecimalField(decimal_places=4, max_digits=5),
|
||||
),
|
||||
(
|
||||
"snapshot_date",
|
||||
models.DateField(
|
||||
db_index=True,
|
||||
help_text="Date when this ranking snapshot was taken",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ride",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="ranking_history",
|
||||
to="rides.ride",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["-snapshot_date", "rank"],
|
||||
"indexes": [
|
||||
models.Index(
|
||||
fields=["snapshot_date", "rank"],
|
||||
name="rides_ranki_snapsho_8e2657_idx",
|
||||
),
|
||||
models.Index(
|
||||
fields=["ride", "-snapshot_date"],
|
||||
name="rides_ranki_ride_id_827bb9_idx",
|
||||
),
|
||||
],
|
||||
"unique_together": {("ride", "snapshot_date")},
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="ridepaircomparison",
|
||||
index=models.Index(
|
||||
fields=["ride_a", "ride_b"], name="rides_ridep_ride_a__eb0674_idx"
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="ridepaircomparison",
|
||||
index=models.Index(
|
||||
fields=["last_calculated"], name="rides_ridep_last_ca_bd9f6c_idx"
|
||||
),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name="ridepaircomparison",
|
||||
unique_together={("ride_a", "ride_b")},
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="ridepaircomparison",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_ridepaircomparisonevent" ("id", "last_calculated", "mutual_riders_count", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "ride_a_avg_rating", "ride_a_id", "ride_a_wins", "ride_b_avg_rating", "ride_b_id", "ride_b_wins", "ties") VALUES (NEW."id", NEW."last_calculated", NEW."mutual_riders_count", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."ride_a_avg_rating", NEW."ride_a_id", NEW."ride_a_wins", NEW."ride_b_avg_rating", NEW."ride_b_id", NEW."ride_b_wins", NEW."ties"); RETURN NULL;',
|
||||
hash="6a640e10fcfd58c48029ee5b84ea7f0826f50022",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_9ad59",
|
||||
table="rides_ridepaircomparison",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="ridepaircomparison",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "rides_ridepaircomparisonevent" ("id", "last_calculated", "mutual_riders_count", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "ride_a_avg_rating", "ride_a_id", "ride_a_wins", "ride_b_avg_rating", "ride_b_id", "ride_b_wins", "ties") VALUES (NEW."id", NEW."last_calculated", NEW."mutual_riders_count", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."ride_a_avg_rating", NEW."ride_a_id", NEW."ride_a_wins", NEW."ride_b_avg_rating", NEW."ride_b_id", NEW."ride_b_wins", NEW."ties"); RETURN NULL;',
|
||||
hash="a77eee0b791bada3f84f008dabd7486c66b03fa6",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_73b31",
|
||||
table="rides_ridepaircomparison",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="rideranking",
|
||||
index=models.Index(fields=["rank"], name="rides_rider_rank_ea4706_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="rideranking",
|
||||
index=models.Index(
|
||||
fields=["winning_percentage", "-mutual_riders_count"],
|
||||
name="rides_rider_winning_d9b3e8_idx",
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="rideranking",
|
||||
index=models.Index(
|
||||
fields=["ride", "last_calculated"],
|
||||
name="rides_rider_ride_id_ece73d_idx",
|
||||
),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="rideranking",
|
||||
constraint=models.CheckConstraint(
|
||||
condition=models.Q(
|
||||
("winning_percentage__gte", 0), ("winning_percentage__lte", 1)
|
||||
),
|
||||
name="rideranking_winning_percentage_range",
|
||||
violation_error_message="Winning percentage must be between 0 and 1",
|
||||
),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="rideranking",
|
||||
constraint=models.CheckConstraint(
|
||||
condition=models.Q(
|
||||
("average_rating__isnull", True),
|
||||
models.Q(("average_rating__gte", 1), ("average_rating__lte", 10)),
|
||||
_connector="OR",
|
||||
),
|
||||
name="rideranking_average_rating_range",
|
||||
violation_error_message="Average rating must be between 1 and 10",
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="rideranking",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "rides_riderankingevent" ("average_rating", "calculation_version", "comparison_count", "id", "last_calculated", "losses", "mutual_riders_count", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rank", "ride_id", "ties", "winning_percentage", "wins") VALUES (NEW."average_rating", NEW."calculation_version", NEW."comparison_count", NEW."id", NEW."last_calculated", NEW."losses", NEW."mutual_riders_count", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."rank", NEW."ride_id", NEW."ties", NEW."winning_percentage", NEW."wins"); RETURN NULL;',
|
||||
hash="c5f9dced5824a55e6f36e476eb382ed770aa5716",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_01af3",
|
||||
table="rides_rideranking",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="rideranking",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "rides_riderankingevent" ("average_rating", "calculation_version", "comparison_count", "id", "last_calculated", "losses", "mutual_riders_count", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rank", "ride_id", "ties", "winning_percentage", "wins") VALUES (NEW."average_rating", NEW."calculation_version", NEW."comparison_count", NEW."id", NEW."last_calculated", NEW."losses", NEW."mutual_riders_count", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."rank", NEW."ride_id", NEW."ties", NEW."winning_percentage", NEW."wins"); RETURN NULL;',
|
||||
hash="363e44ce3c87e8b66406d63d6f1b26ad604c79d2",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_c3f27",
|
||||
table="rides_rideranking",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user