feat(market): enable/disable like any other games

This commit is contained in:
2026-10-16 00:23:27 +02:00
parent 107fe8b69b
commit 919e611895
17 changed files with 112 additions and 97 deletions
-1
View File
@@ -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=
+2 -2
View File
@@ -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=""),
),
]
+1
View File
@@ -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)
+1
View File
@@ -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
+9
View File
@@ -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),
]
+23 -1
View File
@@ -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)
+2
View File
@@ -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")
+2 -16
View File
@@ -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,9 +53,7 @@ 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"])
api.add_router("", market_router, tags=["market"])
if settings.MARKET_ENABLED:
api.add_router("", market_router, tags=["market"])
# Health check endpoint # Health check endpoint
@@ -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):
+3 -3
View File
@@ -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",
+5 -32
View File
@@ -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
+1 -6
View File
@@ -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 -26
View File
@@ -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;
-5
View File
@@ -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"
}, },