feat(market): enable/disable like any other games
This commit is contained in:
@@ -35,7 +35,6 @@ AWS_STORAGE_BUCKET_NAME=
|
|||||||
SENTRY_ENVIRONMENT=production
|
SENTRY_ENVIRONMENT=production
|
||||||
SENTRY_DSN=
|
SENTRY_DSN=
|
||||||
|
|
||||||
MARKET_ENABLED=true
|
|
||||||
STEAM_API_KEY=
|
STEAM_API_KEY=
|
||||||
AANDT_API_BASE_URL=
|
AANDT_API_BASE_URL=
|
||||||
SUBMITTER_BASE_URL=
|
SUBMITTER_BASE_URL=
|
||||||
|
|||||||
@@ -50,12 +50,12 @@ class EventAvailabilityTests(TestCase):
|
|||||||
|
|
||||||
def test_unavailable_event_is_404_for_regular_user(self):
|
def test_unavailable_event_is_404_for_regular_user(self):
|
||||||
self.client.force_login(self.user)
|
self.client.force_login(self.user)
|
||||||
response = self.client.get(f"/{self.hidden.path}/market")
|
response = self.client.get(f"/{self.hidden.path}/")
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
def test_unavailable_event_is_visible_to_staff(self):
|
def test_unavailable_event_is_visible_to_staff(self):
|
||||||
self.client.force_login(self.staff)
|
self.client.force_login(self.staff)
|
||||||
response = self.client.get(f"/{self.hidden.path}/market")
|
response = self.client.get(f"/{self.hidden.path}/")
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_available_to_filters_for_regular_user_only(self):
|
def test_available_to_filters_for_regular_user_only(self):
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 6.0.5 on 2026-10-15 22:19
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("games", "0008_game_custom_path"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="game",
|
||||||
|
name="description",
|
||||||
|
field=models.TextField(blank=True, default=""),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -14,6 +14,7 @@ class Game(models.Model):
|
|||||||
path = models.CharField(max_length=100)
|
path = models.CharField(max_length=100)
|
||||||
custom_path = models.BooleanField(default=False)
|
custom_path = models.BooleanField(default=False)
|
||||||
image = models.URLField(null=True, blank=True)
|
image = models.URLField(null=True, blank=True)
|
||||||
|
description = models.TextField(blank=True, default="")
|
||||||
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ class GameOut(Schema):
|
|||||||
path: str
|
path: str
|
||||||
custom_path: bool
|
custom_path: bool
|
||||||
image: Optional[str] = None
|
image: Optional[str] = None
|
||||||
|
description: str
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
from ninja import Router
|
from ninja import Router
|
||||||
|
from ninja.decorators import decorate_view
|
||||||
from ninja.errors import HttpError
|
from ninja.errors import HttpError
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.db.models import Sum, Prefetch
|
from django.db.models import Sum, Prefetch
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
|
from games.decorators import require_game_enabled
|
||||||
from market.models import (
|
from market.models import (
|
||||||
Market,
|
Market,
|
||||||
MarketOption,
|
MarketOption,
|
||||||
@@ -29,6 +31,7 @@ PREFIX = "/events/{event_path}/market"
|
|||||||
|
|
||||||
|
|
||||||
@router.get(f"{PREFIX}/", response=List[MarketListSchema])
|
@router.get(f"{PREFIX}/", response=List[MarketListSchema])
|
||||||
|
@decorate_view(require_game_enabled(path="market"))
|
||||||
def list_markets(request, event_path: str):
|
def list_markets(request, event_path: str):
|
||||||
"""List all markets (excludes draft markets)."""
|
"""List all markets (excludes draft markets)."""
|
||||||
markets = Market.for_event.exclude(status=Market.Status.DRAFT)
|
markets = Market.for_event.exclude(status=Market.Status.DRAFT)
|
||||||
@@ -41,6 +44,7 @@ def list_markets(request, event_path: str):
|
|||||||
|
|
||||||
|
|
||||||
@router.get(f"{PREFIX}/user/bets", response=List[UserBetSchema])
|
@router.get(f"{PREFIX}/user/bets", response=List[UserBetSchema])
|
||||||
|
@decorate_view(require_game_enabled(path="market"))
|
||||||
def list_user_bets(request, event_path: str):
|
def list_user_bets(request, event_path: str):
|
||||||
"""List all bets placed by the current user."""
|
"""List all bets placed by the current user."""
|
||||||
if not request.user.is_authenticated:
|
if not request.user.is_authenticated:
|
||||||
@@ -54,6 +58,7 @@ def list_user_bets(request, event_path: str):
|
|||||||
|
|
||||||
|
|
||||||
@router.get(f"{PREFIX}/user/points", response=UserPointsSchema)
|
@router.get(f"{PREFIX}/user/points", response=UserPointsSchema)
|
||||||
|
@decorate_view(require_game_enabled(path="market"))
|
||||||
def get_user_points(request, event_path: str):
|
def get_user_points(request, event_path: str):
|
||||||
"""Get the current user's points balance for this event."""
|
"""Get the current user's points balance for this event."""
|
||||||
if not request.user.is_authenticated:
|
if not request.user.is_authenticated:
|
||||||
@@ -63,6 +68,7 @@ def get_user_points(request, event_path: str):
|
|||||||
|
|
||||||
|
|
||||||
@router.get(f"{PREFIX}/{{market_uuid}}/history", response=List[BetHistoryPointSchema])
|
@router.get(f"{PREFIX}/{{market_uuid}}/history", response=List[BetHistoryPointSchema])
|
||||||
|
@decorate_view(require_game_enabled(path="market"))
|
||||||
def bet_history(request, event_path: str, market_uuid: str):
|
def bet_history(request, event_path: str, market_uuid: str):
|
||||||
"""Points added to each option over time (anonymous, one entry per bet placed/increased)."""
|
"""Points added to each option over time (anonymous, one entry per bet placed/increased)."""
|
||||||
market = get_object_or_404(
|
market = get_object_or_404(
|
||||||
@@ -93,6 +99,7 @@ def bet_history(request, event_path: str, market_uuid: str):
|
|||||||
|
|
||||||
|
|
||||||
@router.post(f"{PREFIX}/{{market_uuid}}/actions/close")
|
@router.post(f"{PREFIX}/{{market_uuid}}/actions/close")
|
||||||
|
@decorate_view(require_game_enabled(path="market"))
|
||||||
def close_market(request, event_path: str, market_uuid: str):
|
def close_market(request, event_path: str, market_uuid: str):
|
||||||
"""Close a market. Admin only."""
|
"""Close a market. Admin only."""
|
||||||
if not request.user.is_staff:
|
if not request.user.is_staff:
|
||||||
@@ -105,6 +112,7 @@ def close_market(request, event_path: str, market_uuid: str):
|
|||||||
|
|
||||||
|
|
||||||
@router.post(f"{PREFIX}/{{market_uuid}}/actions/resolve", response=MarketListSchema)
|
@router.post(f"{PREFIX}/{{market_uuid}}/actions/resolve", response=MarketListSchema)
|
||||||
|
@decorate_view(require_game_enabled(path="market"))
|
||||||
def resolve_market(
|
def resolve_market(
|
||||||
request, event_path: str, market_uuid: str, payload: ResolveMarketSchema
|
request, event_path: str, market_uuid: str, payload: ResolveMarketSchema
|
||||||
):
|
):
|
||||||
@@ -172,6 +180,7 @@ def resolve_market(
|
|||||||
|
|
||||||
|
|
||||||
@router.post(f"{PREFIX}/{{market_uuid}}/bets", response=UserBetSchema)
|
@router.post(f"{PREFIX}/{{market_uuid}}/bets", response=UserBetSchema)
|
||||||
|
@decorate_view(require_game_enabled(path="market"))
|
||||||
def create_bet(
|
def create_bet(
|
||||||
request, event_path: str, market_uuid: str, payload: UserBetCreateSchema
|
request, event_path: str, market_uuid: str, payload: UserBetCreateSchema
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
MARKET_PATH = "market"
|
||||||
|
|
||||||
|
|
||||||
|
def seed_market_game(apps, schema_editor):
|
||||||
|
"""The market used to be toggled globally (MARKET_ENABLED); it's now a
|
||||||
|
custom Game like clock/place, enabled per event through EventGame. Enable
|
||||||
|
it for every existing event so nothing disappears on deploy."""
|
||||||
|
Event = apps.get_model("events", "Event")
|
||||||
|
Game = apps.get_model("games", "Game")
|
||||||
|
EventGame = apps.get_model("games", "EventGame")
|
||||||
|
|
||||||
|
game, _ = Game.objects.get_or_create(
|
||||||
|
path=MARKET_PATH,
|
||||||
|
custom_path=True,
|
||||||
|
defaults={
|
||||||
|
"name": "Market",
|
||||||
|
"description": "Place your bets and compete",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
for event in Event.objects.all():
|
||||||
|
EventGame.objects.get_or_create(event=event, game=game)
|
||||||
|
|
||||||
|
|
||||||
|
def unseed_market_game(apps, schema_editor):
|
||||||
|
Game = apps.get_model("games", "Game")
|
||||||
|
Game.objects.filter(path=MARKET_PATH, custom_path=True).delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("events", "0003_event_is_available"),
|
||||||
|
("games", "0009_game_description"),
|
||||||
|
("market", "0009_event_required"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(seed_market_game, reverse_code=unseed_market_game),
|
||||||
|
]
|
||||||
@@ -1 +1,23 @@
|
|||||||
# Create your tests here.
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from accounts.models import CustomUser
|
||||||
|
from events.models import Event
|
||||||
|
from games.models import EventGame, Game
|
||||||
|
|
||||||
|
|
||||||
|
class MarketGameGatingTests(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.event = Event.objects.create(name="Event", path="event")
|
||||||
|
self.game = Game.objects.get(path="market", custom_path=True)
|
||||||
|
self.user = CustomUser.objects.create_user(username="user", password="x")
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
|
||||||
|
def test_market_is_403_when_not_enabled_for_event(self):
|
||||||
|
response = self.client.get(f"/api/events/{self.event.path}/market/")
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
def test_market_is_reachable_when_enabled_for_event(self):
|
||||||
|
EventGame.objects.create(event=self.event, game=self.game)
|
||||||
|
response = self.client.get(f"/api/events/{self.event.path}/market/")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(self.client.get(f"/{self.event.path}/market").status_code, 200)
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ from django.shortcuts import get_object_or_404, render
|
|||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
|
|
||||||
from events.models import Event
|
from events.models import Event
|
||||||
|
from games.decorators import require_game_enabled
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@require_game_enabled(path="market")
|
||||||
def market_home(request: HttpRequest, event_path: str):
|
def market_home(request: HttpRequest, event_path: str):
|
||||||
get_object_or_404(Event, path=event_path)
|
get_object_or_404(Event, path=event_path)
|
||||||
return render(request, "app.html")
|
return render(request, "app.html")
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
from ninja import NinjaAPI, Schema
|
from ninja import NinjaAPI
|
||||||
from django.conf import settings
|
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from opus_magnum.api import router as opus_magnum_router
|
from opus_magnum.api import router as opus_magnum_router
|
||||||
@@ -54,8 +53,6 @@ api.add_router("", games_event_router, tags=["games"])
|
|||||||
api.add_router("", submissions_router, tags=["submissions"])
|
api.add_router("", submissions_router, tags=["submissions"])
|
||||||
api.add_router("", clock_router, tags=["clock"])
|
api.add_router("", clock_router, tags=["clock"])
|
||||||
api.add_router("", place_router, tags=["place"])
|
api.add_router("", place_router, tags=["place"])
|
||||||
|
|
||||||
if settings.MARKET_ENABLED:
|
|
||||||
api.add_router("", market_router, tags=["market"])
|
api.add_router("", market_router, tags=["market"])
|
||||||
|
|
||||||
|
|
||||||
@@ -66,17 +63,6 @@ def health_check(request):
|
|||||||
return {"status": "healthy", "service": "polylan-submitter-api"}
|
return {"status": "healthy", "service": "polylan-submitter-api"}
|
||||||
|
|
||||||
|
|
||||||
class ConfigOut(Schema):
|
|
||||||
market_enabled: bool
|
|
||||||
|
|
||||||
|
|
||||||
# Site-wide config the SPA needs but that isn't tied to any one event
|
|
||||||
# (e.g. whether to render the market card at all on the home page).
|
|
||||||
@api.get("/config", response=ConfigOut)
|
|
||||||
def get_config(request):
|
|
||||||
return {"market_enabled": settings.MARKET_ENABLED}
|
|
||||||
|
|
||||||
|
|
||||||
# Cache management endpoint
|
# Cache management endpoint
|
||||||
@api.post("/cache/clear")
|
@api.post("/cache/clear")
|
||||||
def clear_cache(request: HttpRequest, event_path: str | None = None):
|
def clear_cache(request: HttpRequest, event_path: str | None = None):
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "polylan_submitter.settings")
|
|||||||
|
|
||||||
django_asgi_app = get_asgi_application()
|
django_asgi_app = get_asgi_application()
|
||||||
|
|
||||||
from submissions.routing import (
|
from submissions.routing import ( # noqa: E402
|
||||||
websocket_urlpatterns as submissions_websocket_urlpatterns,
|
websocket_urlpatterns as submissions_websocket_urlpatterns,
|
||||||
)
|
)
|
||||||
from clock.routing import websocket_urlpatterns as clock_websocket_urlpatterns
|
from clock.routing import websocket_urlpatterns as clock_websocket_urlpatterns # noqa: E402
|
||||||
from place.routing import websocket_urlpatterns as place_websocket_urlpatterns
|
from place.routing import websocket_urlpatterns as place_websocket_urlpatterns # noqa: E402
|
||||||
|
|
||||||
websocket_urlpatterns = [
|
websocket_urlpatterns = [
|
||||||
*submissions_websocket_urlpatterns,
|
*submissions_websocket_urlpatterns,
|
||||||
|
|||||||
@@ -307,9 +307,6 @@ ALLOWED_SUBMISSION_TYPES = [
|
|||||||
"video/webm",
|
"video/webm",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Market app settings
|
|
||||||
MARKET_ENABLED = (os.environ.get("MARKET_ENABLED") or "true").lower() == "true"
|
|
||||||
|
|
||||||
# Authentication backends
|
# Authentication backends
|
||||||
AUTHENTICATION_BACKENDS = [
|
AUTHENTICATION_BACKENDS = [
|
||||||
"django.contrib.auth.backends.ModelBackend",
|
"django.contrib.auth.backends.ModelBackend",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { ref, onMounted, computed } from "vue";
|
|||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useTitle } from "@vueuse/core";
|
import { useTitle } from "@vueuse/core";
|
||||||
import { gamesApiListEventGames, polylanSubmitterApiGetConfig } from "./api";
|
import { gamesApiListEventGames } from "./api";
|
||||||
import type { GamesApiListEventGamesResponse } from "./api/types.gen";
|
import type { GamesApiListEventGamesResponse } from "./api/types.gen";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -19,7 +19,6 @@ useTitle(computed(() => t("home.title")));
|
|||||||
const games = ref<GamesApiListEventGamesResponse | undefined>();
|
const games = ref<GamesApiListEventGamesResponse | undefined>();
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const imageErrors = ref<Set<number>>(new Set());
|
const imageErrors = ref<Set<number>>(new Set());
|
||||||
const marketEnabled = ref(false);
|
|
||||||
|
|
||||||
const getHeaderImage = (game: GamesApiListEventGamesResponse[number]) => {
|
const getHeaderImage = (game: GamesApiListEventGamesResponse[number]) => {
|
||||||
if (game.image) {
|
if (game.image) {
|
||||||
@@ -35,26 +34,18 @@ const onImageError = (gameId: number) => {
|
|||||||
imageErrors.value.add(gameId);
|
imageErrors.value.add(gameId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const goToMarket = () => {
|
|
||||||
router.push(`/${props.eventPath}/market`);
|
|
||||||
};
|
|
||||||
|
|
||||||
const goToGame = (game: GamesApiListEventGamesResponse[number]) => {
|
const goToGame = (game: GamesApiListEventGamesResponse[number]) => {
|
||||||
const path = game.custom_path ? `/${game.path}` : `/submissions/${game.path}`;
|
const path = game.custom_path ? `/${game.path}` : `/submissions/${game.path}`;
|
||||||
router.push(`/${props.eventPath}${path}`);
|
router.push(`/${props.eventPath}${path}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const [gamesResponse, configResponse] = await Promise.all([
|
const gamesResponse = await gamesApiListEventGames({
|
||||||
gamesApiListEventGames({ path: { event_path: props.eventPath } }),
|
path: { event_path: props.eventPath },
|
||||||
polylanSubmitterApiGetConfig(),
|
});
|
||||||
]);
|
|
||||||
if (gamesResponse.data) {
|
if (gamesResponse.data) {
|
||||||
games.value = gamesResponse.data;
|
games.value = gamesResponse.data;
|
||||||
}
|
}
|
||||||
if (configResponse.data) {
|
|
||||||
marketEnabled.value = configResponse.data.market_enabled;
|
|
||||||
}
|
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@@ -77,25 +68,6 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<!-- Cards Grid -->
|
<!-- Cards Grid -->
|
||||||
<div v-else class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
<div v-else class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
<!-- Market Card -->
|
|
||||||
<div v-if="marketEnabled" @click="goToMarket"
|
|
||||||
class="card card-xl bg-base-200 shadow-xl hover:shadow-2xl transition-all cursor-pointer transform hover:-translate-y-2 hover:scale-[1.05] hover:bg-base-100 overflow-hidden">
|
|
||||||
<figure class="relative h-60 bg-gradient-to-br from-purple-600 to-blue-600 flex items-center justify-center">
|
|
||||||
<i class="mdi mdi-chart-box text-6xl text-white opacity-80"></i>
|
|
||||||
<div class="absolute inset-0 bg-black/30 group-hover:bg-black/20 transition-colors"></div>
|
|
||||||
</figure>
|
|
||||||
<div class="card-body">
|
|
||||||
<h2 class="card-title text-2xl">{{ t("home.marketCard.title") }}</h2>
|
|
||||||
<p class="text-base-content/70">{{ t("home.marketCard.description") }}</p>
|
|
||||||
<div class="card-actions justify-end mt-4">
|
|
||||||
<button class="btn btn-primary">
|
|
||||||
<i class="mdi mdi-arrow-right mr-2"></i>
|
|
||||||
{{ t("home.marketCard.cta") }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Game Cards -->
|
<!-- Game Cards -->
|
||||||
<div v-for="game in games" :key="game.id"
|
<div v-for="game in games" :key="game.id"
|
||||||
@click="goToGame(game)"
|
@click="goToGame(game)"
|
||||||
@@ -111,6 +83,7 @@ onMounted(async () => {
|
|||||||
</figure>
|
</figure>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="card-title text-2xl">{{ game.name }}</h2>
|
<h2 class="card-title text-2xl">{{ game.name }}</h2>
|
||||||
|
<p v-if="game.description" class="text-base-content/70">{{ game.description }}</p>
|
||||||
<div class="card-actions justify-end mt-4">
|
<div class="card-actions justify-end mt-4">
|
||||||
<button class="btn btn-primary">
|
<button class="btn btn-primary">
|
||||||
<i class="mdi mdi-arrow-right mr-2"></i>
|
<i class="mdi mdi-arrow-right mr-2"></i>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { type Client, formDataBodySerializer, type Options as Options2, type TDataShape } from './client';
|
import { type Client, formDataBodySerializer, type Options as Options2, type TDataShape } from './client';
|
||||||
import { client } from './client.gen';
|
import { client } from './client.gen';
|
||||||
import type { AnimationsApiPuzzleResultsData, AnimationsApiPuzzleResultsResponses, AnimationsApiResultsData, AnimationsApiResultsResponses, AnimationsApiTopSubmissionsData, AnimationsApiTopSubmissionsResponses, ClockApiCurrentStateData, ClockApiCurrentStateResponses, ClockApiMyStatsData, ClockApiMyStatsResponses, GamesApiListEventGamesData, GamesApiListEventGamesResponses, GamesApiListGamesData, GamesApiListGamesResponses, MarketApiBetHistoryData, MarketApiBetHistoryResponses, MarketApiCloseMarketData, MarketApiCloseMarketResponses, MarketApiCreateBetData, MarketApiCreateBetResponses, MarketApiGetUserPointsData, MarketApiGetUserPointsResponses, MarketApiListMarketsData, MarketApiListMarketsResponses, MarketApiListUserBetsData, MarketApiListUserBetsResponses, MarketApiResolveMarketData, MarketApiResolveMarketResponses, NoitaApiGetLeaderboardData, NoitaApiGetLeaderboardResponses, NoitaApiGetResultsData, NoitaApiGetResultsResponses, NoitaApiSubmitLogFileData, NoitaApiSubmitLogFileErrors, NoitaApiSubmitLogFileResponses, OpusMagnumApiCreateSubmissionData, OpusMagnumApiCreateSubmissionResponses, OpusMagnumApiDeleteSubmissionData, OpusMagnumApiDeleteSubmissionResponses, OpusMagnumApiGetCollectionData, OpusMagnumApiGetCollectionResponses, OpusMagnumApiGetStatsData, OpusMagnumApiGetStatsResponses, OpusMagnumApiGetSubmissionData, OpusMagnumApiGetSubmissionResponses, OpusMagnumApiListPuzzlesData, OpusMagnumApiListPuzzlesResponses, OpusMagnumApiListResponsesNeedingValidationData, OpusMagnumApiListResponsesNeedingValidationResponses, OpusMagnumApiListSubmissionsData, OpusMagnumApiListSubmissionsResponses, OpusMagnumApiValidateAutoData, OpusMagnumApiValidateAutoResponses, OpusMagnumApiValidateResponseData, OpusMagnumApiValidateResponseResponses, OpusMagnumApiValidateSubmissionData, OpusMagnumApiValidateSubmissionResponses, PlaceApiCanvasData, PlaceApiCanvasResponses, PlaceApiEvolutionGifData, PlaceApiEvolutionGifResponses, PolylanSubmitterApiClearCacheData, PolylanSubmitterApiClearCacheResponses, PolylanSubmitterApiGetConfigData, PolylanSubmitterApiGetConfigResponses, PolylanSubmitterApiGetUserInfoData, PolylanSubmitterApiGetUserInfoResponses, PolylanSubmitterApiHealthCheckData, PolylanSubmitterApiHealthCheckResponses, SubmissionsApiCreateImageCropData, SubmissionsApiCreateImageCropResponses, SubmissionsApiCreateSubmissionData, SubmissionsApiCreateSubmissionErrors, SubmissionsApiCreateSubmissionResponses, SubmissionsApiDeleteImageCropData, SubmissionsApiDeleteImageCropResponses, SubmissionsApiGetSubmissionData, SubmissionsApiGetSubmissionResponses, SubmissionsApiListAvailableScopesData, SubmissionsApiListAvailableScopesErrors, SubmissionsApiListAvailableScopesResponses, SubmissionsApiListMyScopesData, SubmissionsApiListMyScopesErrors, SubmissionsApiListMyScopesResponses, SubmissionsApiListSubmissionsByGameData, SubmissionsApiListSubmissionsByGameResponses, SubmissionsApiListUserSubmissionsData, SubmissionsApiListUserSubmissionsErrors, SubmissionsApiListUserSubmissionsResponses, SubmissionsApiProcessCropOcrData, SubmissionsApiProcessCropOcrResponses, SubmissionsApiProcessFileOcrData, SubmissionsApiProcessFileOcrResponses } from './types.gen';
|
import type { AnimationsApiPuzzleResultsData, AnimationsApiPuzzleResultsResponses, AnimationsApiResultsData, AnimationsApiResultsResponses, AnimationsApiTopSubmissionsData, AnimationsApiTopSubmissionsResponses, ClockApiCurrentStateData, ClockApiCurrentStateResponses, ClockApiMyStatsData, ClockApiMyStatsResponses, GamesApiListEventGamesData, GamesApiListEventGamesResponses, GamesApiListGamesData, GamesApiListGamesResponses, MarketApiBetHistoryData, MarketApiBetHistoryResponses, MarketApiCloseMarketData, MarketApiCloseMarketResponses, MarketApiCreateBetData, MarketApiCreateBetResponses, MarketApiGetUserPointsData, MarketApiGetUserPointsResponses, MarketApiListMarketsData, MarketApiListMarketsResponses, MarketApiListUserBetsData, MarketApiListUserBetsResponses, MarketApiResolveMarketData, MarketApiResolveMarketResponses, NoitaApiGetLeaderboardData, NoitaApiGetLeaderboardResponses, NoitaApiGetResultsData, NoitaApiGetResultsResponses, NoitaApiSubmitLogFileData, NoitaApiSubmitLogFileErrors, NoitaApiSubmitLogFileResponses, OpusMagnumApiCreateSubmissionData, OpusMagnumApiCreateSubmissionResponses, OpusMagnumApiDeleteSubmissionData, OpusMagnumApiDeleteSubmissionResponses, OpusMagnumApiGetCollectionData, OpusMagnumApiGetCollectionResponses, OpusMagnumApiGetStatsData, OpusMagnumApiGetStatsResponses, OpusMagnumApiGetSubmissionData, OpusMagnumApiGetSubmissionResponses, OpusMagnumApiListPuzzlesData, OpusMagnumApiListPuzzlesResponses, OpusMagnumApiListResponsesNeedingValidationData, OpusMagnumApiListResponsesNeedingValidationResponses, OpusMagnumApiListSubmissionsData, OpusMagnumApiListSubmissionsResponses, OpusMagnumApiValidateAutoData, OpusMagnumApiValidateAutoResponses, OpusMagnumApiValidateResponseData, OpusMagnumApiValidateResponseResponses, OpusMagnumApiValidateSubmissionData, OpusMagnumApiValidateSubmissionResponses, PlaceApiCanvasData, PlaceApiCanvasResponses, PlaceApiEvolutionGifData, PlaceApiEvolutionGifResponses, PolylanSubmitterApiClearCacheData, PolylanSubmitterApiClearCacheResponses, PolylanSubmitterApiGetUserInfoData, PolylanSubmitterApiGetUserInfoResponses, PolylanSubmitterApiHealthCheckData, PolylanSubmitterApiHealthCheckResponses, SubmissionsApiCreateImageCropData, SubmissionsApiCreateImageCropResponses, SubmissionsApiCreateSubmissionData, SubmissionsApiCreateSubmissionErrors, SubmissionsApiCreateSubmissionResponses, SubmissionsApiDeleteImageCropData, SubmissionsApiDeleteImageCropResponses, SubmissionsApiGetSubmissionData, SubmissionsApiGetSubmissionResponses, SubmissionsApiListAvailableScopesData, SubmissionsApiListAvailableScopesErrors, SubmissionsApiListAvailableScopesResponses, SubmissionsApiListMyScopesData, SubmissionsApiListMyScopesErrors, SubmissionsApiListMyScopesResponses, SubmissionsApiListSubmissionsByGameData, SubmissionsApiListSubmissionsByGameResponses, SubmissionsApiListUserSubmissionsData, SubmissionsApiListUserSubmissionsErrors, SubmissionsApiListUserSubmissionsResponses, SubmissionsApiProcessCropOcrData, SubmissionsApiProcessCropOcrResponses, SubmissionsApiProcessFileOcrData, SubmissionsApiProcessFileOcrResponses } from './types.gen';
|
||||||
|
|
||||||
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean, TResponse = unknown> = Options2<TData, ThrowOnError, TResponse> & {
|
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean, TResponse = unknown> = Options2<TData, ThrowOnError, TResponse> & {
|
||||||
/**
|
/**
|
||||||
@@ -25,11 +25,6 @@ export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends
|
|||||||
*/
|
*/
|
||||||
export const polylanSubmitterApiHealthCheck = <ThrowOnError extends boolean = false>(options?: Options<PolylanSubmitterApiHealthCheckData, ThrowOnError>) => (options?.client ?? client).get<PolylanSubmitterApiHealthCheckResponses, unknown, ThrowOnError>({ url: '/api/health', ...options });
|
export const polylanSubmitterApiHealthCheck = <ThrowOnError extends boolean = false>(options?: Options<PolylanSubmitterApiHealthCheckData, ThrowOnError>) => (options?.client ?? client).get<PolylanSubmitterApiHealthCheckResponses, unknown, ThrowOnError>({ url: '/api/health', ...options });
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Config
|
|
||||||
*/
|
|
||||||
export const polylanSubmitterApiGetConfig = <ThrowOnError extends boolean = false>(options?: Options<PolylanSubmitterApiGetConfigData, ThrowOnError>) => (options?.client ?? client).get<PolylanSubmitterApiGetConfigResponses, unknown, ThrowOnError>({ url: '/api/config', ...options });
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear Cache
|
* Clear Cache
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -4,16 +4,6 @@ export type ClientOptions = {
|
|||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* ConfigOut
|
|
||||||
*/
|
|
||||||
export type ConfigOut = {
|
|
||||||
/**
|
|
||||||
* Market Enabled
|
|
||||||
*/
|
|
||||||
market_enabled: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UserInfoOut
|
* UserInfoOut
|
||||||
*
|
*
|
||||||
@@ -90,6 +80,10 @@ export type GameOut = {
|
|||||||
* Image
|
* Image
|
||||||
*/
|
*/
|
||||||
image?: string | null;
|
image?: string | null;
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
description: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1219,22 +1213,6 @@ export type PolylanSubmitterApiHealthCheckResponses = {
|
|||||||
200: unknown;
|
200: unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PolylanSubmitterApiGetConfigData = {
|
|
||||||
body?: never;
|
|
||||||
path?: never;
|
|
||||||
query?: never;
|
|
||||||
url: '/api/config';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PolylanSubmitterApiGetConfigResponses = {
|
|
||||||
/**
|
|
||||||
* OK
|
|
||||||
*/
|
|
||||||
200: ConfigOut;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PolylanSubmitterApiGetConfigResponse = PolylanSubmitterApiGetConfigResponses[keyof PolylanSubmitterApiGetConfigResponses];
|
|
||||||
|
|
||||||
export type PolylanSubmitterApiClearCacheData = {
|
export type PolylanSubmitterApiClearCacheData = {
|
||||||
body?: never;
|
body?: never;
|
||||||
path?: never;
|
path?: never;
|
||||||
|
|||||||
@@ -63,11 +63,6 @@
|
|||||||
"home": {
|
"home": {
|
||||||
"title": "PolyLAN Submitter",
|
"title": "PolyLAN Submitter",
|
||||||
"subtitle": "Choose a game and submit your best solutions",
|
"subtitle": "Choose a game and submit your best solutions",
|
||||||
"marketCard": {
|
|
||||||
"title": "Market",
|
|
||||||
"description": "Place your bets and compete",
|
|
||||||
"cta": "Place bets"
|
|
||||||
},
|
|
||||||
"submitResults": "Submit results",
|
"submitResults": "Submit results",
|
||||||
"footer": "Select a game above to begin submitting"
|
"footer": "Select a game above to begin submitting"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user