diff --git a/polylan_submitter/market/admin.py b/polylan_submitter/market/admin.py index ed40306..b67fca8 100644 --- a/polylan_submitter/market/admin.py +++ b/polylan_submitter/market/admin.py @@ -23,16 +23,29 @@ class MarketAdmin(admin.ModelAdmin): inlines = [MarketOptionInline] fieldsets = ( ("Info", {"fields": ["uuid", "title", "description"]}), - ("Configuration", {"fields": ["end_date"]}), + ("Configuration", {"fields": ["end_date", "multiplier"]}), ("Status", {"fields": ["status", "winning_option"]}), ("Metadata", {"fields": ["created_by", "created_at", "updated_at"]}), ) + def has_change_permission(self, request, obj=None): + # Prevent any changes to resolved markets + if obj and obj.status == Market.Status.RESOLVED: + return False + return super().has_change_permission(request, obj) + def save_model(self, request, obj, form, change): if not change: # Creating new market obj.created_by = request.user super().save_model(request, obj, form, change) + @admin.action(description="Publish selected draft markets") + def publish_markets(self, request, queryset): + updated = queryset.filter(status=Market.Status.DRAFT).update( + status=Market.Status.OPEN + ) + self.message_user(request, f"Published {updated} market(s).") + @admin.action(description="Close selected markets") def close_markets(self, request, queryset): updated = queryset.filter(status=Market.Status.OPEN).update( @@ -40,7 +53,7 @@ class MarketAdmin(admin.ModelAdmin): ) self.message_user(request, f"Closed {updated} market(s).") - actions = ["close_markets"] + actions = ["publish_markets", "close_markets"] @admin.register(MarketOption) diff --git a/polylan_submitter/market/api.py b/polylan_submitter/market/api.py index 89e1c07..f41be0f 100644 --- a/polylan_submitter/market/api.py +++ b/polylan_submitter/market/api.py @@ -20,8 +20,8 @@ router = Router(tags=["market"]) @router.get("/", response=List[MarketListSchema]) def list_markets(request): - """List all markets.""" - markets = Market.objects.all() + """List all markets (excludes draft markets).""" + markets = Market.objects.exclude(status=Market.Status.DRAFT) # Prefetch options with total_bets annotation sorted by total_bets desc, then text asc options_queryset = MarketOption.objects.annotate( total_bets=Coalesce(Sum("user_bets__amount"), 0) @@ -52,7 +52,7 @@ def close_market(request, market_uuid: str): market = get_object_or_404(Market, uuid=market_uuid) market.status = Market.Status.CLOSED market.save(update_fields=["status", "updated_at"]) - return {"status": "closed"} + return {"status": Market.Status.CLOSED} @router.post("/{market_uuid}/actions/resolve", response=MarketListSchema) @@ -91,10 +91,12 @@ def resolve_market(request, market_uuid: str, payload: ResolveMarketSchema): users_to_update = [] with transaction.atomic(): - # Award payouts to winners + # Award payouts to winners with multiplier if total_winning > 0: for bet in winning_bets: - payout = round(bet.amount / total_winning * total_pot) + payout = round( + bet.amount / total_winning * total_pot * market.multiplier + ) bet.user.points += payout users_to_update.append(bet.user) point_changes.append( diff --git a/polylan_submitter/market/migrations/0005_market_multiplier.py b/polylan_submitter/market/migrations/0005_market_multiplier.py new file mode 100644 index 0000000..36f7feb --- /dev/null +++ b/polylan_submitter/market/migrations/0005_market_multiplier.py @@ -0,0 +1,17 @@ +# Generated by Django 5.2.7 on 2026-05-23 18:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("market", "0004_alter_marketoption_options_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="market", + name="multiplier", + field=models.FloatField(default=1.0), + ), + ] diff --git a/polylan_submitter/market/migrations/0006_alter_market_status.py b/polylan_submitter/market/migrations/0006_alter_market_status.py new file mode 100644 index 0000000..aa6f876 --- /dev/null +++ b/polylan_submitter/market/migrations/0006_alter_market_status.py @@ -0,0 +1,26 @@ +# Generated by Django 5.2.7 on 2026-05-23 18:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("market", "0005_market_multiplier"), + ] + + operations = [ + migrations.AlterField( + model_name="market", + name="status", + field=models.CharField( + choices=[ + ("draft", "Draft"), + ("open", "Open"), + ("closed", "Closed"), + ("resolved", "Resolved"), + ], + default="draft", + max_length=10, + ), + ), + ] diff --git a/polylan_submitter/market/models.py b/polylan_submitter/market/models.py index 574315e..ce94a92 100644 --- a/polylan_submitter/market/models.py +++ b/polylan_submitter/market/models.py @@ -13,6 +13,7 @@ class BaseModel(models.Model): class Market(BaseModel): class Status(models.TextChoices): + DRAFT = "draft", "Draft" OPEN = "open", "Open" CLOSED = "closed", "Closed" RESOLVED = "resolved", "Resolved" @@ -20,9 +21,10 @@ class Market(BaseModel): title = models.CharField(max_length=255) description = models.TextField(blank=True) status = models.CharField( - max_length=10, choices=Status.choices, default=Status.OPEN + max_length=10, choices=Status.choices, default=Status.DRAFT ) end_date = models.DateTimeField() + multiplier = models.FloatField(default=1.0) created_by = models.ForeignKey("accounts.CustomUser", on_delete=models.PROTECT) winning_option = models.ForeignKey( "MarketOption", diff --git a/polylan_submitter/market/schemas.py b/polylan_submitter/market/schemas.py index 1d49f0e..c10da3e 100644 --- a/polylan_submitter/market/schemas.py +++ b/polylan_submitter/market/schemas.py @@ -21,6 +21,7 @@ class MarketListSchema(Schema): description: str status: str end_date: datetime + multiplier: float = 1.0 created_at: datetime options: List[MarketOptionSchema] winning_option: Optional[MarketOptionSchema] = None diff --git a/polylan_submitter/polylan_submitter/api.py b/polylan_submitter/polylan_submitter/api.py index 9bbfa74..6a3f383 100644 --- a/polylan_submitter/polylan_submitter/api.py +++ b/polylan_submitter/polylan_submitter/api.py @@ -67,20 +67,10 @@ def get_user_info(request): user = request.user if user.is_authenticated: - return { - "id": user.id, - "username": user.username, - "first_name": user.first_name, - "last_name": user.last_name, - "email": user.email, - "is_authenticated": True, - "is_staff": user.is_staff, - "is_superuser": user.is_superuser, - "cas_groups": getattr(user, "cas_groups", []), - } - else: - return { - "is_authenticated": False, - "is_staff": False, - "is_superuser": False, - } + return user + + return { + "is_authenticated": False, + "is_staff": False, + "is_superuser": False, + } diff --git a/polylan_submitter/src/Market.vue b/polylan_submitter/src/Market.vue index b7752a3..838bde1 100644 --- a/polylan_submitter/src/Market.vue +++ b/polylan_submitter/src/Market.vue @@ -77,19 +77,31 @@ onMounted(async () => {
{{ market.description }}