fix: multiple fixes + event for market
This commit is contained in:
@@ -6,7 +6,6 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|||||||
@@ -58,7 +58,9 @@ class ClockTimer(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
class Press(models.Model):
|
class Press(models.Model):
|
||||||
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="clock_presses")
|
event = models.ForeignKey(
|
||||||
|
Event, on_delete=models.CASCADE, related_name="clock_presses"
|
||||||
|
)
|
||||||
player = models.ForeignKey(
|
player = models.ForeignKey(
|
||||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="clock_presses"
|
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="clock_presses"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ EVENT_PATH = os.environ.get("PLACE_EVENT_PATH", "loadtest")
|
|||||||
USER_COUNT = int(os.environ.get("LOAD_TEST_USER_COUNT", "500"))
|
USER_COUNT = int(os.environ.get("LOAD_TEST_USER_COUNT", "500"))
|
||||||
USER_PREFIX = os.environ.get("LOAD_TEST_USER_PREFIX", "loadtest")
|
USER_PREFIX = os.environ.get("LOAD_TEST_USER_PREFIX", "loadtest")
|
||||||
PASSWORD = os.environ.get("LOAD_TEST_PASSWORD", "loadtest-only-password")
|
PASSWORD = os.environ.get("LOAD_TEST_PASSWORD", "loadtest-only-password")
|
||||||
RELOAD_ON_FAILURE_PROBABILITY = float(os.environ.get("RELOAD_ON_FAILURE_PROBABILITY", "0.7"))
|
RELOAD_ON_FAILURE_PROBABILITY = float(
|
||||||
|
os.environ.get("RELOAD_ON_FAILURE_PROBABILITY", "0.7")
|
||||||
|
)
|
||||||
|
|
||||||
# Mirrors place/models.py::PALETTE - kept as a plain constant here since
|
# Mirrors place/models.py::PALETTE - kept as a plain constant here since
|
||||||
# loadtest runs standalone, without Django settings loaded.
|
# loadtest runs standalone, without Django settings loaded.
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ class MarketOptionInline(admin.TabularInline):
|
|||||||
|
|
||||||
@admin.register(Market)
|
@admin.register(Market)
|
||||||
class MarketAdmin(DjangoObjectActions, admin.ModelAdmin):
|
class MarketAdmin(DjangoObjectActions, admin.ModelAdmin):
|
||||||
list_display = ["title", "status", "end_date", "created_by", "created_at"]
|
list_display = ["title", "status", "event", "end_date", "created_by", "created_at"]
|
||||||
list_filter = ["status", "created_at"]
|
list_filter = ["status", "created_at", "event"]
|
||||||
search_fields = ["uuid", "title"]
|
search_fields = ["uuid", "title"]
|
||||||
readonly_fields = [
|
readonly_fields = [
|
||||||
"uuid",
|
"uuid",
|
||||||
@@ -27,7 +27,7 @@ class MarketAdmin(DjangoObjectActions, admin.ModelAdmin):
|
|||||||
]
|
]
|
||||||
inlines = [MarketOptionInline]
|
inlines = [MarketOptionInline]
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
("Info", {"fields": ["uuid", "title", "description"]}),
|
("Info", {"fields": ["uuid", "title", "description", "event"]}),
|
||||||
("Configuration", {"fields": ["end_date", "multiplier"]}),
|
("Configuration", {"fields": ["end_date", "multiplier"]}),
|
||||||
("Status", {"fields": ["status", "winning_option"]}),
|
("Status", {"fields": ["status", "winning_option"]}),
|
||||||
("Metadata", {"fields": ["created_by", "created_at", "updated_at"]}),
|
("Metadata", {"fields": ["created_by", "created_at", "updated_at"]}),
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ class PlaceSettingsAdmin(DjangoObjectActions, admin.ModelAdmin):
|
|||||||
def resync_canvas(self, request, obj):
|
def resync_canvas(self, request, obj):
|
||||||
count = rebuild_canvas_from_history(obj.event, obj.width, obj.height)
|
count = rebuild_canvas_from_history(obj.event, obj.width, obj.height)
|
||||||
self.message_user(
|
self.message_user(
|
||||||
request, f"Canvas resynced from {count} placement(s) at {obj.width}x{obj.height}."
|
request,
|
||||||
|
f"Canvas resynced from {count} placement(s) at {obj.width}x{obj.height}.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,9 @@ class PlaceConsumer(AsyncWebsocketConsumer):
|
|||||||
await self.send(text_data=encode("r", "i"))
|
await self.send(text_data=encode("r", "i"))
|
||||||
return
|
return
|
||||||
|
|
||||||
result = await self._record_placement(user, x, y, color_index, place_settings.width)
|
result = await self._record_placement(
|
||||||
|
user, x, y, color_index, place_settings.width
|
||||||
|
)
|
||||||
|
|
||||||
if result["rejected"]:
|
if result["rejected"]:
|
||||||
await self.send(text_data=encode("r", "c", result["next"]))
|
await self.send(text_data=encode("r", "c", result["next"]))
|
||||||
@@ -110,7 +112,9 @@ class PlaceConsumer(AsyncWebsocketConsumer):
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
"rejected": False,
|
"rejected": False,
|
||||||
"next": to_epoch_ms(placement.placed_at + timedelta(seconds=PLACE_COOLDOWN_SECONDS)),
|
"next": to_epoch_ms(
|
||||||
|
placement.placed_at + timedelta(seconds=PLACE_COOLDOWN_SECONDS)
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@database_sync_to_async
|
@database_sync_to_async
|
||||||
|
|||||||
@@ -35,9 +35,11 @@ def build_evolution_gif(event: Event) -> bytes:
|
|||||||
place_settings = PlaceSettings.current(event)
|
place_settings = PlaceSettings.current(event)
|
||||||
width, height = place_settings.width, place_settings.height
|
width, height = place_settings.width, place_settings.height
|
||||||
|
|
||||||
placements = PixelPlacement.objects.filter(event=event).order_by(
|
placements = (
|
||||||
"placed_at"
|
PixelPlacement.objects.filter(event=event)
|
||||||
).values_list("x", "y", "color_index")
|
.order_by("placed_at")
|
||||||
|
.values_list("x", "y", "color_index")
|
||||||
|
)
|
||||||
placements = list(placements)
|
placements = list(placements)
|
||||||
|
|
||||||
grid = bytearray(width * height)
|
grid = bytearray(width * height)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ 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 websocket_urlpatterns as submissions_websocket_urlpatterns
|
from submissions.routing import (
|
||||||
|
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
|
||||||
from place.routing import websocket_urlpatterns as place_websocket_urlpatterns
|
from place.routing import websocket_urlpatterns as place_websocket_urlpatterns
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,9 @@ DEBUG = os.environ.get("DJANGO_DEBUG", "false").lower() == "true"
|
|||||||
|
|
||||||
ALLOWED_HOSTS = [
|
ALLOWED_HOSTS = [
|
||||||
host
|
host
|
||||||
for host in (os.environ.get("DJANGO_ALLOWED_HOSTS") or "127.0.0.1,localhost").split(",")
|
for host in (os.environ.get("DJANGO_ALLOWED_HOSTS") or "127.0.0.1,localhost").split(
|
||||||
|
","
|
||||||
|
)
|
||||||
if host
|
if host
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -222,7 +224,9 @@ CAS_SERVER_URL = "https://polylan.ch/cas/"
|
|||||||
# environment - the "Create load test users" admin action on CustomUser
|
# environment - the "Create load test users" admin action on CustomUser
|
||||||
# (see accounts/admin.py) also hides itself without it, as a second layer
|
# (see accounts/admin.py) also hides itself without it, as a second layer
|
||||||
# of the same guard rail.
|
# of the same guard rail.
|
||||||
LOAD_TEST_LOGIN_ENABLED = (os.environ.get("LOAD_TEST_LOGIN_ENABLED", "false").lower() == "true")
|
LOAD_TEST_LOGIN_ENABLED = (
|
||||||
|
os.environ.get("LOAD_TEST_LOGIN_ENABLED", "false").lower() == "true"
|
||||||
|
)
|
||||||
|
|
||||||
# Steam API Configuration
|
# Steam API Configuration
|
||||||
STEAM_API_KEY = os.environ.get("STEAM_API_KEY") or None # Set via environment variable
|
STEAM_API_KEY = os.environ.get("STEAM_API_KEY") or None # Set via environment variable
|
||||||
@@ -273,7 +277,9 @@ CHANNEL_LAYERS = {
|
|||||||
|
|
||||||
# Redis for place's live pixel canvas (SETRANGE on the hot path - not a fit
|
# Redis for place's live pixel canvas (SETRANGE on the hot path - not a fit
|
||||||
# for django-redis's cache API, so it gets its own raw redis-py client).
|
# for django-redis's cache API, so it gets its own raw redis-py client).
|
||||||
PLACE_REDIS_URL = os.environ.get("PLACE_REDIS_URL") or f"redis://{REDIS_HOST}:{REDIS_PORT}/15"
|
PLACE_REDIS_URL = (
|
||||||
|
os.environ.get("PLACE_REDIS_URL") or f"redis://{REDIS_HOST}:{REDIS_PORT}/15"
|
||||||
|
)
|
||||||
|
|
||||||
# Django Tasks Configuration (with RQ backend)
|
# Django Tasks Configuration (with RQ backend)
|
||||||
TASKS = {
|
TASKS = {
|
||||||
@@ -318,6 +324,7 @@ LOGOUT_REDIRECT_URL = "/"
|
|||||||
DJANGO_VITE = {
|
DJANGO_VITE = {
|
||||||
"default": {
|
"default": {
|
||||||
"dev_mode": DEBUG,
|
"dev_mode": DEBUG,
|
||||||
|
"dev_server_port": 5273,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
STATIC_URL = "/static/"
|
STATIC_URL = "/static/"
|
||||||
@@ -331,7 +338,9 @@ STATICFILES_DIRS = [
|
|||||||
# that, so these must be set (via env) wherever the app runs, dev included.
|
# that, so these must be set (via env) wherever the app runs, dev included.
|
||||||
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "")
|
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "")
|
||||||
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "")
|
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "")
|
||||||
AWS_S3_ENDPOINT_URL = os.environ.get("AWS_S3_ENDPOINT_URL") or "https://storage.polylan.ch"
|
AWS_S3_ENDPOINT_URL = (
|
||||||
|
os.environ.get("AWS_S3_ENDPOINT_URL") or "https://storage.polylan.ch"
|
||||||
|
)
|
||||||
AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_STORAGE_BUCKET_NAME") or "dev-submissions"
|
AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_STORAGE_BUCKET_NAME") or "dev-submissions"
|
||||||
|
|
||||||
_s3_storage_options = {
|
_s3_storage_options = {
|
||||||
@@ -356,9 +365,12 @@ STORAGES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SENTRY_ENVIRONMENT = os.environ.get("SENTRY_ENVIRONMENT") or ("development" if DEBUG else "production")
|
SENTRY_ENVIRONMENT = os.environ.get("SENTRY_ENVIRONMENT") or (
|
||||||
|
"development" if DEBUG else "production"
|
||||||
|
)
|
||||||
SENTRY_DSN = (
|
SENTRY_DSN = (
|
||||||
os.environ.get("SENTRY_DSN") or "https://cc62a4ce3f3470890b43accf02cc6d8c@sentry2.polylan.ch/12"
|
os.environ.get("SENTRY_DSN")
|
||||||
|
or "https://cc62a4ce3f3470890b43accf02cc6d8c@sentry2.polylan.ch/12"
|
||||||
)
|
)
|
||||||
|
|
||||||
import sentry_sdk # noqa
|
import sentry_sdk # noqa
|
||||||
|
|||||||
@@ -117,7 +117,9 @@ urlpatterns = [
|
|||||||
# URL itself doesn't exist unless explicitly enabled, so it 404s rather than
|
# URL itself doesn't exist unless explicitly enabled, so it 404s rather than
|
||||||
# 403s in every environment that hasn't opted in.
|
# 403s in every environment that hasn't opted in.
|
||||||
if settings.LOAD_TEST_LOGIN_ENABLED:
|
if settings.LOAD_TEST_LOGIN_ENABLED:
|
||||||
urlpatterns.append(path("testing/login/", TestLoginView.as_view(), name="testing.login"))
|
urlpatterns.append(
|
||||||
|
path("testing/login/", TestLoginView.as_view(), name="testing.login")
|
||||||
|
)
|
||||||
|
|
||||||
# Serve media files in development
|
# Serve media files in development
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
|
|||||||
@@ -31,7 +31,10 @@ def list_my_scopes(request: HttpRequest, event_path: str, game_path: str):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get(f"{PREFIX}/{{game_path}}/available-scopes", response={200: list[ScopeOut], 403: dict})
|
@router.get(
|
||||||
|
f"{PREFIX}/{{game_path}}/available-scopes",
|
||||||
|
response={200: list[ScopeOut], 403: dict},
|
||||||
|
)
|
||||||
def list_available_scopes(request: HttpRequest, event_path: str, game_path: str):
|
def list_available_scopes(request: HttpRequest, event_path: str, game_path: str):
|
||||||
"""Scopes the current user may submit to for this game - superusers see
|
"""Scopes the current user may submit to for this game - superusers see
|
||||||
every active scope, everyone else only the ones assigned to them. Used
|
every active scope, everyone else only the ones assigned to them. Used
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ from django.db import migrations
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("submissions", "0007_submission_scope"),
|
("submissions", "0007_submission_scope"),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export default defineConfig({
|
|||||||
// server, so dev-mode asset URLs (e.g. @font-face url()s injected
|
// server, so dev-mode asset URLs (e.g. @font-face url()s injected
|
||||||
// via JS-imported CSS) must be absolute, not root-relative, or the
|
// via JS-imported CSS) must be absolute, not root-relative, or the
|
||||||
// browser resolves them against Django's origin instead of Vite's.
|
// browser resolves them against Django's origin instead of Vite's.
|
||||||
origin: 'http://localhost:5173',
|
origin: 'http://localhost:5273',
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
|
|||||||
Reference in New Issue
Block a user