Compare commits
13 Commits
01fd047568
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe4f135b92 | ||
|
|
f05e91c2ce | ||
|
|
9587995354 | ||
|
|
93dafb6a81 | ||
|
|
c116f8dcb1 | ||
|
|
24a26bd092 | ||
|
|
6acc708f46 | ||
|
|
4c67b10f75 | ||
|
|
335299c670 | ||
|
|
af95eea265 | ||
|
|
3884864d30 | ||
|
|
787bdede87 | ||
|
|
a3ef6cf84c |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -9,4 +9,11 @@ wheels/
|
|||||||
# Virtual environments
|
# Virtual environments
|
||||||
.venv
|
.venv
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Node modules (only for types definitions)
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Collected static files
|
||||||
staticfiles/
|
staticfiles/
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
# Register your models here.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class ApiConfig(AppConfig):
|
|
||||||
name = 'api'
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# Generated by Django 6.0.2 on 2026-02-10 18:07
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Building',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('geojson_id', models.IntegerField()),
|
|
||||||
('health', models.FloatField()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
|
|
||||||
|
|
||||||
class Building(models.Model):
|
|
||||||
geojson_id = models.IntegerField()
|
|
||||||
health = models.FloatField()
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
from django.contrib.auth import authenticate, get_user_model
|
|
||||||
from django.core.validators import validate_email
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
from rest_framework import serializers
|
|
||||||
from rest_framework_simplejwt.tokens import RefreshToken
|
|
||||||
|
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
|
|
||||||
class RegistrationSerializer(serializers.Serializer):
|
|
||||||
email = serializers.EmailField()
|
|
||||||
password = serializers.CharField(min_length=8, write_only=True)
|
|
||||||
|
|
||||||
def validate_email(self, value):
|
|
||||||
validate_email(value)
|
|
||||||
if User.objects.filter(email__iexact=value).exists():
|
|
||||||
raise serializers.ValidationError(_("Email is already registered."))
|
|
||||||
return value
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
email = validated_data["email"].lower()
|
|
||||||
password = validated_data["password"]
|
|
||||||
user = User.objects.create_user(
|
|
||||||
username=email,
|
|
||||||
email=email,
|
|
||||||
password=password,
|
|
||||||
)
|
|
||||||
return user
|
|
||||||
|
|
||||||
|
|
||||||
class LoginSerializer(serializers.Serializer):
|
|
||||||
email = serializers.EmailField()
|
|
||||||
password = serializers.CharField(write_only=True)
|
|
||||||
|
|
||||||
def validate(self, attrs):
|
|
||||||
email = attrs.get("email", "").lower()
|
|
||||||
password = attrs.get("password")
|
|
||||||
if not email or not password:
|
|
||||||
raise serializers.ValidationError(_("Email and password are required."))
|
|
||||||
|
|
||||||
user = authenticate(
|
|
||||||
request=self.context.get("request"),
|
|
||||||
username=email,
|
|
||||||
password=password,
|
|
||||||
)
|
|
||||||
if user is None:
|
|
||||||
raise serializers.ValidationError(_("Invalid email or password."))
|
|
||||||
if not user.is_active:
|
|
||||||
raise serializers.ValidationError(_("User account is disabled."))
|
|
||||||
|
|
||||||
attrs["user"] = user
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
user = validated_data["user"]
|
|
||||||
refresh = RefreshToken.for_user(user)
|
|
||||||
return {
|
|
||||||
"refresh": str(refresh),
|
|
||||||
"access": str(refresh.access_token),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class LogoutSerializer(serializers.Serializer):
|
|
||||||
refresh = serializers.CharField()
|
|
||||||
|
|
||||||
def validate(self, attrs):
|
|
||||||
refresh = attrs.get("refresh")
|
|
||||||
if not refresh:
|
|
||||||
raise serializers.ValidationError(_("Refresh token is required."))
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
refresh = RefreshToken(validated_data["refresh"])
|
|
||||||
refresh.blacklist()
|
|
||||||
return {}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
|
|
||||||
from .views import LoginView, LogoutView, RegisterView
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path("auth/register", RegisterView.as_view(), name="auth-register"),
|
|
||||||
path("auth/login", LoginView.as_view(), name="auth-login"),
|
|
||||||
path("auth/logout", LogoutView.as_view(), name="auth-logout"),
|
|
||||||
]
|
|
||||||
67
api/views.py
67
api/views.py
@@ -1,67 +0,0 @@
|
|||||||
from rest_framework import permissions, status
|
|
||||||
from rest_framework.response import Response
|
|
||||||
from rest_framework.views import APIView
|
|
||||||
|
|
||||||
from .serializers import LoginSerializer, LogoutSerializer, RegistrationSerializer
|
|
||||||
|
|
||||||
|
|
||||||
class RegisterView(APIView):
|
|
||||||
permission_classes = [permissions.AllowAny]
|
|
||||||
throttle_scope = "auth"
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
serializer = RegistrationSerializer(data=request.data)
|
|
||||||
if not serializer.is_valid():
|
|
||||||
return Response(
|
|
||||||
{"errors": serializer.errors},
|
|
||||||
status=status.HTTP_400_BAD_REQUEST,
|
|
||||||
)
|
|
||||||
user = serializer.save()
|
|
||||||
login_serializer = LoginSerializer(
|
|
||||||
data={
|
|
||||||
"email": user.email,
|
|
||||||
"password": request.data.get("password"),
|
|
||||||
},
|
|
||||||
context={"request": request},
|
|
||||||
)
|
|
||||||
login_serializer.is_valid(raise_exception=True)
|
|
||||||
tokens = login_serializer.save()
|
|
||||||
return Response(
|
|
||||||
{
|
|
||||||
"user": {
|
|
||||||
"id": user.id,
|
|
||||||
"email": user.email,
|
|
||||||
},
|
|
||||||
"tokens": tokens,
|
|
||||||
},
|
|
||||||
status=status.HTTP_201_CREATED,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class LoginView(APIView):
|
|
||||||
permission_classes = [permissions.AllowAny]
|
|
||||||
throttle_scope = "auth"
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
serializer = LoginSerializer(data=request.data, context={"request": request})
|
|
||||||
if not serializer.is_valid():
|
|
||||||
return Response(
|
|
||||||
{"errors": serializer.errors},
|
|
||||||
status=status.HTTP_400_BAD_REQUEST,
|
|
||||||
)
|
|
||||||
tokens = serializer.save()
|
|
||||||
return Response({"tokens": tokens}, status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
class LogoutView(APIView):
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def post(self, request):
|
|
||||||
serializer = LogoutSerializer(data=request.data)
|
|
||||||
if not serializer.is_valid():
|
|
||||||
return Response(
|
|
||||||
{"errors": serializer.errors},
|
|
||||||
status=status.HTTP_400_BAD_REQUEST,
|
|
||||||
)
|
|
||||||
serializer.save()
|
|
||||||
return Response({"detail": "Logged out."}, status=status.HTTP_200_OK)
|
|
||||||
31
build.js
Normal file
31
build.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// build.js
|
||||||
|
import * as esbuild from "esbuild";
|
||||||
|
|
||||||
|
const isDev = process.argv.includes("--dev");
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
entryPoints: ["frontend/static/frontend/ts/main.ts"], // il tuo entry point
|
||||||
|
bundle: true,
|
||||||
|
outdir: "frontend/static/frontend/dist/js",
|
||||||
|
format: "iife", // o 'iife' se serve per un tag <script> classico
|
||||||
|
target: "es2020",
|
||||||
|
sourcemap: isDev,
|
||||||
|
minify: true,
|
||||||
|
logLevel: "info",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isDev) {
|
||||||
|
const ctx = await esbuild.context(config);
|
||||||
|
await ctx.watch();
|
||||||
|
console.log("Watching...");
|
||||||
|
|
||||||
|
const shutdown = async () => {
|
||||||
|
await ctx.dispose();
|
||||||
|
process.exit(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
process.on("SIGINT", shutdown);
|
||||||
|
process.on("SIGTERM", shutdown);
|
||||||
|
} else {
|
||||||
|
await esbuild.build(config);
|
||||||
|
}
|
||||||
128
bun.lock
Normal file
128
bun.lock
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"configVersion": 0,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"@types/maplibre-gl": "^1.14.0",
|
||||||
|
"esbuild": "^0.27.3",
|
||||||
|
"maplibre-gl": "^5.18.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="],
|
||||||
|
|
||||||
|
"@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="],
|
||||||
|
|
||||||
|
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="],
|
||||||
|
|
||||||
|
"@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="],
|
||||||
|
|
||||||
|
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="],
|
||||||
|
|
||||||
|
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="],
|
||||||
|
|
||||||
|
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="],
|
||||||
|
|
||||||
|
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="],
|
||||||
|
|
||||||
|
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="],
|
||||||
|
|
||||||
|
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="],
|
||||||
|
|
||||||
|
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="],
|
||||||
|
|
||||||
|
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="],
|
||||||
|
|
||||||
|
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="],
|
||||||
|
|
||||||
|
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="],
|
||||||
|
|
||||||
|
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="],
|
||||||
|
|
||||||
|
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="],
|
||||||
|
|
||||||
|
"@mapbox/geojson-rewind": ["@mapbox/geojson-rewind@0.5.2", "", { "dependencies": { "get-stream": "^6.0.1", "minimist": "^1.2.6" }, "bin": { "geojson-rewind": "geojson-rewind" } }, "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA=="],
|
||||||
|
|
||||||
|
"@mapbox/jsonlint-lines-primitives": ["@mapbox/jsonlint-lines-primitives@2.0.2", "", {}, "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ=="],
|
||||||
|
|
||||||
|
"@mapbox/point-geometry": ["@mapbox/point-geometry@1.1.0", "", {}, "sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ=="],
|
||||||
|
|
||||||
|
"@mapbox/tiny-sdf": ["@mapbox/tiny-sdf@2.0.7", "", {}, "sha512-25gQLQMcpivjOSA40g3gO6qgiFPDpWRoMfd+G/GoppPIeP6JDaMMkMrEJnMZhKyyS6iKwVt5YKu02vCUyJM3Ug=="],
|
||||||
|
|
||||||
|
"@mapbox/unitbezier": ["@mapbox/unitbezier@0.0.1", "", {}, "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw=="],
|
||||||
|
|
||||||
|
"@mapbox/vector-tile": ["@mapbox/vector-tile@2.0.4", "", { "dependencies": { "@mapbox/point-geometry": "~1.1.0", "@types/geojson": "^7946.0.16", "pbf": "^4.0.1" } }, "sha512-AkOLcbgGTdXScosBWwmmD7cDlvOjkg/DetGva26pIRiZPdeJYjYKarIlb4uxVzi6bwHO6EWH82eZ5Nuv4T5DUg=="],
|
||||||
|
|
||||||
|
"@mapbox/whoots-js": ["@mapbox/whoots-js@3.1.0", "", {}, "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q=="],
|
||||||
|
|
||||||
|
"@maplibre/geojson-vt": ["@maplibre/geojson-vt@5.0.4", "", {}, "sha512-KGg9sma45S+stfH9vPCJk1J0lSDLWZgCT9Y8u8qWZJyjFlP8MNP1WGTxIMYJZjDvVT3PDn05kN1C95Sut1HpgQ=="],
|
||||||
|
|
||||||
|
"@maplibre/maplibre-gl-style-spec": ["@maplibre/maplibre-gl-style-spec@24.4.1", "", { "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/unitbezier": "^0.0.1", "json-stringify-pretty-compact": "^4.0.0", "minimist": "^1.2.8", "quickselect": "^3.0.0", "rw": "^1.3.3", "tinyqueue": "^3.0.0" }, "bin": { "gl-style-migrate": "dist/gl-style-migrate.mjs", "gl-style-validate": "dist/gl-style-validate.mjs", "gl-style-format": "dist/gl-style-format.mjs" } }, "sha512-UKhA4qv1h30XT768ccSv5NjNCX+dgfoq2qlLVmKejspPcSQTYD4SrVucgqegmYcKcmwf06wcNAa/kRd0NHWbUg=="],
|
||||||
|
|
||||||
|
"@maplibre/mlt": ["@maplibre/mlt@1.1.6", "", { "dependencies": { "@mapbox/point-geometry": "^1.1.0" } }, "sha512-rgtY3x65lrrfXycLf6/T22ZnjTg5WgIOsptOIoCaMZy4O4UAKTyZlYY0h6v8le721pTptF94U65yMDQkug+URw=="],
|
||||||
|
|
||||||
|
"@maplibre/vt-pbf": ["@maplibre/vt-pbf@4.2.1", "", { "dependencies": { "@mapbox/point-geometry": "^1.1.0", "@mapbox/vector-tile": "^2.0.4", "@maplibre/geojson-vt": "^5.0.4", "@types/geojson": "^7946.0.16", "@types/supercluster": "^7.1.3", "pbf": "^4.0.1", "supercluster": "^8.0.1" } }, "sha512-IxZBGq/+9cqf2qdWlFuQ+ZfoMhWpxDUGQZ/poPHOJBvwMUT1GuxLo6HgYTou+xxtsOsjfbcjI8PZaPCtmt97rA=="],
|
||||||
|
|
||||||
|
"@types/geojson": ["@types/geojson@7946.0.16", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="],
|
||||||
|
|
||||||
|
"@types/maplibre-gl": ["@types/maplibre-gl@1.14.0", "", { "dependencies": { "maplibre-gl": "*" } }, "sha512-I6ibscT7UdL1oOqqCz9s1gjcolLaUPkHIIfMLusczTvlsMhjORyS6sE1g4V/NESAOL5KhNQX3/31LJH+OCGjkg=="],
|
||||||
|
|
||||||
|
"@types/supercluster": ["@types/supercluster@7.1.3", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA=="],
|
||||||
|
|
||||||
|
"earcut": ["earcut@3.0.2", "", {}, "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ=="],
|
||||||
|
|
||||||
|
"esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="],
|
||||||
|
|
||||||
|
"get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="],
|
||||||
|
|
||||||
|
"gl-matrix": ["gl-matrix@3.4.4", "", {}, "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ=="],
|
||||||
|
|
||||||
|
"json-stringify-pretty-compact": ["json-stringify-pretty-compact@4.0.0", "", {}, "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q=="],
|
||||||
|
|
||||||
|
"kdbush": ["kdbush@4.0.2", "", {}, "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA=="],
|
||||||
|
|
||||||
|
"maplibre-gl": ["maplibre-gl@5.18.0", "", { "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", "@mapbox/point-geometry": "^1.1.0", "@mapbox/tiny-sdf": "^2.0.7", "@mapbox/unitbezier": "^0.0.1", "@mapbox/vector-tile": "^2.0.4", "@mapbox/whoots-js": "^3.1.0", "@maplibre/geojson-vt": "^5.0.4", "@maplibre/maplibre-gl-style-spec": "^24.4.1", "@maplibre/mlt": "^1.1.6", "@maplibre/vt-pbf": "^4.2.1", "@types/geojson": "^7946.0.16", "@types/supercluster": "^7.1.3", "earcut": "^3.0.2", "gl-matrix": "^3.4.4", "kdbush": "^4.0.2", "murmurhash-js": "^1.0.0", "pbf": "^4.0.1", "potpack": "^2.1.0", "quickselect": "^3.0.0", "supercluster": "^8.0.1", "tinyqueue": "^3.0.0" } }, "sha512-UtWxPBpHuFvEkM+5FVfcFG9ZKEWZQI6+PZkvLErr8Zs5ux+O7/KQ3JjSUvAfOlMeMgd/77qlHpOw0yHL7JU5cw=="],
|
||||||
|
|
||||||
|
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
||||||
|
|
||||||
|
"murmurhash-js": ["murmurhash-js@1.0.0", "", {}, "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw=="],
|
||||||
|
|
||||||
|
"pbf": ["pbf@4.0.1", "", { "dependencies": { "resolve-protobuf-schema": "^2.1.0" }, "bin": { "pbf": "bin/pbf" } }, "sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA=="],
|
||||||
|
|
||||||
|
"potpack": ["potpack@2.1.0", "", {}, "sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ=="],
|
||||||
|
|
||||||
|
"protocol-buffers-schema": ["protocol-buffers-schema@3.6.0", "", {}, "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw=="],
|
||||||
|
|
||||||
|
"quickselect": ["quickselect@3.0.0", "", {}, "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g=="],
|
||||||
|
|
||||||
|
"resolve-protobuf-schema": ["resolve-protobuf-schema@2.1.0", "", { "dependencies": { "protocol-buffers-schema": "^3.3.1" } }, "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ=="],
|
||||||
|
|
||||||
|
"rw": ["rw@1.3.3", "", {}, "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="],
|
||||||
|
|
||||||
|
"supercluster": ["supercluster@8.0.1", "", { "dependencies": { "kdbush": "^4.0.2" } }, "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ=="],
|
||||||
|
|
||||||
|
"tinyqueue": ["tinyqueue@3.0.0", "", {}, "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
@@ -10,34 +10,41 @@ For the full list of settings and their values, see
|
|||||||
https://docs.djangoproject.com/en/6.0/ref/settings/
|
https://docs.djangoproject.com/en/6.0/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
load_dotenv(BASE_DIR / ".env")
|
||||||
|
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = "django-insecure-nows$x_3#k9x7j09f*o4xmx#p6zeb%ak+#ew2pc01yx2bm+hwq"
|
SECRET_KEY = os.getenv(
|
||||||
|
"SECRET_KEY",
|
||||||
|
"django-insecure-nows$x_3#k9x7j09f*o4xmx#p6zeb%ak+#ew2pc01yx2bm+hwq",
|
||||||
|
)
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = True
|
DEBUG = os.getenv("DEBUG", "False").strip().lower() in {"1", "true", "yes", "on"}
|
||||||
|
|
||||||
ALLOWED_HOSTS = []
|
ALLOWED_HOSTS = ["127.0.0.1", "localhost"]
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
"api",
|
"game",
|
||||||
"frontend",
|
"frontend",
|
||||||
"rest_framework",
|
"rest_framework",
|
||||||
"rest_framework_simplejwt",
|
"rest_framework_simplejwt",
|
||||||
"rest_framework_simplejwt.token_blacklist",
|
"rest_framework_simplejwt.token_blacklist",
|
||||||
"django.contrib.admin",
|
|
||||||
"django.contrib.auth",
|
"django.contrib.auth",
|
||||||
"django.contrib.contenttypes",
|
"django.contrib.contenttypes",
|
||||||
"django.contrib.sessions",
|
"django.contrib.sessions",
|
||||||
|
|||||||
@@ -15,11 +15,8 @@ Including another URLconf
|
|||||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.contrib import admin
|
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", include("frontend.urls")),
|
path("", include("frontend.urls")),
|
||||||
path("admin/", admin.site.urls),
|
|
||||||
path("api/", include("api.urls")),
|
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
# Register your models here.
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class FrontendConfig(AppConfig):
|
|
||||||
name = "frontend"
|
|
||||||
|
|
||||||
def ready(self) -> None:
|
|
||||||
from . import models # noqa: F401
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="UserProfile",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("display_name", models.CharField(max_length=150)),
|
|
||||||
(
|
|
||||||
"user",
|
|
||||||
models.OneToOneField(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="profile",
|
|
||||||
to=settings.AUTH_USER_MODEL,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
dependencies = [
|
|
||||||
("frontend", "0001_userprofile"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="userprofile",
|
|
||||||
name="display_name",
|
|
||||||
field=models.CharField(max_length=150, unique=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,6 +1,52 @@
|
|||||||
|
:root {
|
||||||
|
color-scheme: dark;
|
||||||
|
--map-ink: #041005;
|
||||||
|
--map-void: #020a03;
|
||||||
|
--map-forest: #0b1f0e;
|
||||||
|
--map-grid: #0f2f17;
|
||||||
|
--map-road: #1de85b;
|
||||||
|
--map-road-soft: #119a3b;
|
||||||
|
--map-node: #6dff9d;
|
||||||
|
--map-label: #7dffa6;
|
||||||
|
--map-glow: rgba(19, 240, 97, 0.35);
|
||||||
|
--map-glow-strong: rgba(19, 240, 97, 0.65);
|
||||||
|
--map-surface: rgba(6, 20, 9, 0.85);
|
||||||
|
--map-surface-strong: rgba(6, 24, 10, 0.96);
|
||||||
|
--map-border: rgba(29, 232, 91, 0.35);
|
||||||
|
--map-border-strong: rgba(29, 232, 91, 0.6);
|
||||||
|
--map-text: #b5ffd0;
|
||||||
|
--map-muted: #6bbf83;
|
||||||
|
--map-accent: #1de85b;
|
||||||
|
--map-accent-hot: #9bff5c;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: radial-gradient(
|
||||||
|
circle at top,
|
||||||
|
#0b1f0e 0%,
|
||||||
|
#041005 45%,
|
||||||
|
#020a03 100%
|
||||||
|
);
|
||||||
|
color: var(--map-text);
|
||||||
|
font-family:
|
||||||
|
"JetBrains Mono", "SFMono-Regular", "Menlo", "Monaco", "Consolas",
|
||||||
|
monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
#map {
|
#map {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
background:
|
||||||
|
radial-gradient(
|
||||||
|
circle at 20% 10%,
|
||||||
|
rgba(12, 48, 20, 0.85),
|
||||||
|
rgba(4, 14, 7, 0.9)
|
||||||
|
),
|
||||||
|
linear-gradient(140deg, rgba(5, 24, 10, 0.95), rgba(2, 8, 4, 0.98));
|
||||||
}
|
}
|
||||||
|
|
||||||
.site-header {
|
.site-header {
|
||||||
@@ -15,14 +61,20 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 0.85rem 1.5rem;
|
padding: 0.85rem 1.5rem;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: rgba(255, 255, 255, 0.85);
|
background: linear-gradient(
|
||||||
|
120deg,
|
||||||
|
rgba(7, 24, 11, 0.9),
|
||||||
|
rgba(6, 20, 9, 0.75)
|
||||||
|
);
|
||||||
backdrop-filter: blur(16px);
|
backdrop-filter: blur(16px);
|
||||||
border: 1px solid rgba(255, 255, 255, 0.6);
|
border: 1px solid var(--map-border);
|
||||||
box-shadow: 0 18px 40px rgba(24, 31, 59, 0.16);
|
box-shadow:
|
||||||
|
0 18px 40px rgba(0, 0, 0, 0.45),
|
||||||
|
0 0 24px var(--map-glow);
|
||||||
font-family:
|
font-family:
|
||||||
"JetBrains Mono", "SFMono-Regular", "Menlo", "Monaco", "Consolas",
|
"JetBrains Mono", "SFMono-Regular", "Menlo", "Monaco", "Consolas",
|
||||||
monospace;
|
monospace;
|
||||||
color: #111827;
|
color: var(--map-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.site-brand {
|
.site-brand {
|
||||||
@@ -32,6 +84,7 @@
|
|||||||
color: inherit;
|
color: inherit;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
text-shadow: 0 0 12px var(--map-glow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.site-actions {
|
.site-actions {
|
||||||
@@ -42,16 +95,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.site-user {
|
.site-user {
|
||||||
color: #4b5563;
|
color: var(--map-muted);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.site-link {
|
.site-link {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: #111827;
|
color: var(--map-text);
|
||||||
padding: 0.45rem 0.9rem;
|
padding: 0.45rem 0.9rem;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
border: 1px solid rgba(17, 24, 39, 0.12);
|
border: 1px solid rgba(29, 232, 91, 0.25);
|
||||||
transition:
|
transition:
|
||||||
transform 0.2s ease,
|
transform 0.2s ease,
|
||||||
box-shadow 0.2s ease,
|
box-shadow 0.2s ease,
|
||||||
@@ -60,15 +113,18 @@
|
|||||||
|
|
||||||
.site-link:hover {
|
.site-link:hover {
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
border-color: rgba(17, 24, 39, 0.28);
|
border-color: var(--map-border-strong);
|
||||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.12);
|
box-shadow:
|
||||||
|
0 10px 20px rgba(0, 0, 0, 0.35),
|
||||||
|
0 0 16px var(--map-glow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.site-link--accent {
|
.site-link--accent {
|
||||||
border: none;
|
border: none;
|
||||||
background: linear-gradient(130deg, #f97316, #facc15);
|
background: linear-gradient(130deg, #0fd64f, #9bff5c);
|
||||||
color: #1f2937;
|
color: #041005;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
box-shadow: 0 0 18px rgba(15, 214, 79, 0.45);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
@@ -97,12 +153,12 @@
|
|||||||
padding: 4rem 1.5rem;
|
padding: 4rem 1.5rem;
|
||||||
background: radial-gradient(
|
background: radial-gradient(
|
||||||
circle at top,
|
circle at top,
|
||||||
#eef5ff,
|
#0e2613,
|
||||||
#f7f0ff 35%,
|
#07180c 35%,
|
||||||
#f7f6ff 65%,
|
#041106 65%,
|
||||||
#fdf6ef
|
#020a03
|
||||||
);
|
);
|
||||||
color: #1f1f1f;
|
color: var(--map-text);
|
||||||
font-family:
|
font-family:
|
||||||
"JetBrains Mono", "SFMono-Regular", "Menlo", "Monaco", "Consolas",
|
"JetBrains Mono", "SFMono-Regular", "Menlo", "Monaco", "Consolas",
|
||||||
monospace;
|
monospace;
|
||||||
@@ -110,11 +166,13 @@
|
|||||||
|
|
||||||
.auth-card {
|
.auth-card {
|
||||||
width: min(420px, 100%);
|
width: min(420px, 100%);
|
||||||
background: #ffffff;
|
background: var(--map-surface);
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
padding: 2.5rem;
|
padding: 2.5rem;
|
||||||
box-shadow: 0 24px 60px rgba(24, 31, 59, 0.12);
|
box-shadow:
|
||||||
border: 1px solid rgba(0, 0, 0, 0.05);
|
0 24px 60px rgba(0, 0, 0, 0.5),
|
||||||
|
0 0 22px var(--map-glow);
|
||||||
|
border: 1px solid var(--map-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-header {
|
.auth-header {
|
||||||
@@ -125,28 +183,28 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.2em;
|
letter-spacing: 0.2em;
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
color: #57606a;
|
color: var(--map-muted);
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-title {
|
.auth-title {
|
||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
color: #111827;
|
color: var(--map-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-subtitle {
|
.auth-subtitle {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
color: #6b7280;
|
color: var(--map-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-messages {
|
.auth-messages {
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
background: #fff4f4;
|
background: rgba(18, 55, 26, 0.75);
|
||||||
border: 1px solid #ffccd2;
|
border: 1px solid rgba(110, 255, 157, 0.35);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
padding: 0.75rem 1rem;
|
padding: 0.75rem 1rem;
|
||||||
color: #b42318;
|
color: var(--map-accent-hot);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-message {
|
.auth-message {
|
||||||
@@ -158,6 +216,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-field {
|
.auth-field {
|
||||||
@@ -165,20 +224,26 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.45rem;
|
gap: 0.45rem;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
color: #374151;
|
color: var(--map-muted);
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-field input {
|
.auth-field input {
|
||||||
padding: 0.7rem 0.9rem;
|
padding: 0.7rem 0.9rem;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
border: 1px solid #d1d5db;
|
border: 1px solid rgba(109, 255, 157, 0.3);
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
|
background: var(--map-surface-strong);
|
||||||
|
color: var(--map-text);
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(3, 18, 7, 0.8);
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-field input:focus {
|
.auth-field input:focus {
|
||||||
outline: 2px solid rgba(76, 110, 245, 0.35);
|
outline: 2px solid rgba(29, 232, 91, 0.35);
|
||||||
border-color: #6d7bf7;
|
border-color: var(--map-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-submit {
|
.auth-submit {
|
||||||
@@ -186,8 +251,8 @@
|
|||||||
padding: 0.8rem 1rem;
|
padding: 0.8rem 1rem;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
border: none;
|
border: none;
|
||||||
background: linear-gradient(130deg, #f97316, #facc15);
|
background: linear-gradient(130deg, #0fd64f, #9bff5c);
|
||||||
color: #1f2937;
|
color: #041005;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition:
|
transition:
|
||||||
@@ -197,17 +262,19 @@
|
|||||||
|
|
||||||
.auth-submit:hover {
|
.auth-submit:hover {
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
box-shadow: 0 12px 25px rgba(249, 115, 22, 0.3);
|
box-shadow:
|
||||||
|
0 12px 25px rgba(15, 214, 79, 0.35),
|
||||||
|
0 0 18px var(--map-glow-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-footer {
|
.auth-footer {
|
||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
color: #6b7280;
|
color: var(--map-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-footer a {
|
.auth-footer a {
|
||||||
color: #111827;
|
color: var(--map-text);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
frontend/static/frontend/images/favicon.ico
Normal file
BIN
frontend/static/frontend/images/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
13
frontend/static/frontend/ts/layers.ts
Normal file
13
frontend/static/frontend/ts/layers.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { AddLayerObject } from "maplibre-gl";
|
||||||
|
|
||||||
|
export const HIGHLIGHT_LAYER = {
|
||||||
|
id: "buildings-highlight", // nome arbitrario del layer
|
||||||
|
type: "fill",
|
||||||
|
source: "buildings",
|
||||||
|
"source-layer": "building",
|
||||||
|
paint: {
|
||||||
|
"fill-color": "#41ff44",
|
||||||
|
"fill-opacity": 1,
|
||||||
|
},
|
||||||
|
filter: ["==", ["id"], ""],
|
||||||
|
} as AddLayerObject;
|
||||||
3
frontend/static/frontend/ts/lib/add.ts
Normal file
3
frontend/static/frontend/ts/lib/add.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export default function add(a: number, b: number): number {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
41
frontend/static/frontend/ts/main.ts
Normal file
41
frontend/static/frontend/ts/main.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { HIGHLIGHT_LAYER } from "./layers";
|
||||||
|
|
||||||
|
import { Map } from "maplibre-gl";
|
||||||
|
|
||||||
|
const map = new Map({
|
||||||
|
style:
|
||||||
|
"https://api.maptiler.com/maps/019be805-c88e-7c8b-9850-bc704d72e604/style.json?key=8nmgHEIZQiIgqQj3RZNa",
|
||||||
|
container: "map",
|
||||||
|
zoom: 17,
|
||||||
|
});
|
||||||
|
|
||||||
|
map.on("load", () => {
|
||||||
|
navigator.geolocation.getCurrentPosition((position) => {
|
||||||
|
map.panTo({
|
||||||
|
lat: position.coords.latitude,
|
||||||
|
lng: position.coords.longitude,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Il layer per gli highlight
|
||||||
|
map.addLayer(HIGHLIGHT_LAYER);
|
||||||
|
|
||||||
|
map.on("mousemove", (ev) => {
|
||||||
|
const features = map.queryRenderedFeatures(ev.point, {
|
||||||
|
layers: ["buildings"], // questo e' il layer che c'e' nello style di maptiler
|
||||||
|
});
|
||||||
|
|
||||||
|
if (features && features.length > 0) {
|
||||||
|
const feature = features[0];
|
||||||
|
const hoveredId = feature.id;
|
||||||
|
|
||||||
|
if (hoveredId) {
|
||||||
|
map.setFilter("buildings-highlight", ["==", ["id"], hoveredId]);
|
||||||
|
map.getCanvas().style.cursor = "pointer";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
map.setFilter("buildings-highlight", ["==", ["id"], ""]);
|
||||||
|
map.getCanvas().style.cursor = "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -6,22 +6,33 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>{% block title %}{% endblock %}</title>
|
<title>{% block title %}{% endblock %}</title>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap" rel="stylesheet">
|
<link
|
||||||
<link rel="stylesheet" href="{% static 'frontend/css/base.css' %}">
|
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap"
|
||||||
<link rel="stylesheet" href="{% static 'frontend/css/reset.css' %}">
|
rel="stylesheet"
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/maplibre-gl/5.7.3/maplibre-gl.min.css" integrity="sha512-/UDhp6sLyQgK2cEDHUYEyJFXI7+WgJ+nuxTqETJkT8XlfLiMSt2xQblBVnCjE5rGJMBr5sOWaEhflmtBL1Psww==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
/>
|
||||||
|
<link rel="stylesheet" href="{% static 'frontend/css/base.css' %}" />
|
||||||
|
<link rel="stylesheet" href="{% static 'frontend/css/reset.css' %}" />
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://cdnjs.cloudflare.com/ajax/libs/maplibre-gl/5.7.3/maplibre-gl.min.css"
|
||||||
|
integrity="sha512-/UDhp6sLyQgK2cEDHUYEyJFXI7+WgJ+nuxTqETJkT8XlfLiMSt2xQblBVnCjE5rGJMBr5sOWaEhflmtBL1Psww=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
/>
|
||||||
|
<link rel="icon" type="image/x-icon" href="{% static 'frontend/images/favicon.ico' %}">
|
||||||
{% block extra_css %}{% endblock %}
|
{% block extra_css %}{% endblock %}
|
||||||
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js" integrity="sha384-/TgkGk7p307TH7EXJDuUlgG3Ce1UVolAOFopFekQkkXihi5u/6OCvVKyz1W+idaz" crossorigin="anonymous"></script>
|
<script
|
||||||
|
src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js"
|
||||||
|
integrity="sha384-/TgkGk7p307TH7EXJDuUlgG3Ce1UVolAOFopFekQkkXihi5u/6OCvVKyz1W+idaz"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
></script>
|
||||||
{% block js_top %}{% endblock %}
|
{% block js_top %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>{% include "frontend/partials/header.html" %}</header>
|
||||||
{% include "frontend/partials/header.html" %}
|
|
||||||
</header>
|
|
||||||
{% block content %} {% endblock %}
|
{% block content %} {% endblock %}
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/maplibre-gl/5.7.3/maplibre-gl.min.js" integrity="sha512-Gx0xDElSrwjxjT9mjMg+OsoA0ekI8IkwuPurccWk5afkFBzXQHE0eQsQ7syopu9MJ0HD1EYGmVXjY8SPZt5FAg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
|
||||||
{% block js_bottom %}{% endblock %}
|
{% block js_bottom %}{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,18 +1,13 @@
|
|||||||
{% extends 'frontend/base.html' %}
|
{% extends 'frontend/base.html' %}
|
||||||
|
|
||||||
{% block title %}Home{% endblock %}
|
{% load static %}
|
||||||
|
|
||||||
|
{% block title %}ᑀ DroneWars ᑅ{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="map"></div>
|
<div id="map"></div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js_bottom %}
|
{% block js_bottom %}
|
||||||
<script>
|
<script src="{% static 'frontend/dist/js/main.js' %}"></script>
|
||||||
var map = new maplibregl.Map({
|
|
||||||
container: "map",
|
|
||||||
style: "https://api.maptiler.com/maps/019be805-c88e-7c8b-9850-bc704d72e604/style.json?key=8nmgHEIZQiIgqQj3RZNa",
|
|
||||||
center: [-74.5, 40],
|
|
||||||
zoom: 9,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="site-actions">
|
<div class="site-actions">
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<span class="site-user">
|
<span class="site-user">
|
||||||
{{ user.profile.display_name|default:user.get_username }}
|
Welcome, <strong>{{ user.profile.display_name|default:user.get_username }}</strong>
|
||||||
</span>
|
</span>
|
||||||
<a class="site-link" href="{% url 'logout' %}">Logout</a>
|
<a class="site-link" href="{% url 'logout' %}">Logout</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ from django.urls import path
|
|||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", views.home, name="home"),
|
path("", views.home, name="home"),
|
||||||
path("auth/register/", views.register, name="register"),
|
path("auth/register/", views.register, name="register"),
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from django.shortcuts import redirect, render
|
|||||||
from django.views.decorators.http import require_http_methods
|
from django.views.decorators.http import require_http_methods
|
||||||
from django_ratelimit.decorators import ratelimit
|
from django_ratelimit.decorators import ratelimit
|
||||||
|
|
||||||
from .models import UserProfile
|
from game.models import UserProfile
|
||||||
|
|
||||||
|
|
||||||
def home(request):
|
def home(request):
|
||||||
|
|||||||
5
game/apps.py
Normal file
5
game/apps.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class GameConfig(AppConfig):
|
||||||
|
name = 'game'
|
||||||
41
game/migrations/0001_initial.py
Normal file
41
game/migrations/0001_initial.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Generated by Django 6.0.2 on 2026-02-11 20:00
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Building',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('geojson_id', models.IntegerField()),
|
||||||
|
('health', models.FloatField()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='PlayerInfo',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('energy', models.PositiveIntegerField()),
|
||||||
|
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='player_info', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='UserProfile',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('display_name', models.CharField(max_length=150, unique=True)),
|
||||||
|
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -4,6 +4,20 @@ from django.db.models.signals import post_save
|
|||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
|
||||||
|
class Building(models.Model):
|
||||||
|
geojson_id = models.IntegerField()
|
||||||
|
health = models.FloatField()
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerInfo(models.Model):
|
||||||
|
user = models.OneToOneField(
|
||||||
|
settings.AUTH_USER_MODEL,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="player_info",
|
||||||
|
)
|
||||||
|
energy = models.PositiveIntegerField()
|
||||||
|
|
||||||
|
|
||||||
class UserProfile(models.Model):
|
class UserProfile(models.Model):
|
||||||
user = models.OneToOneField(
|
user = models.OneToOneField(
|
||||||
settings.AUTH_USER_MODEL,
|
settings.AUTH_USER_MODEL,
|
||||||
@@ -19,7 +33,8 @@ class UserProfile(models.Model):
|
|||||||
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
|
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
|
||||||
def create_profile_for_user(sender, instance, created, **kwargs):
|
def create_profile_for_user(sender, instance, created, **kwargs):
|
||||||
if created:
|
if created:
|
||||||
UserProfile.objects.create( # type: ignore[attr-defined]
|
UserProfile.objects.create(
|
||||||
user=instance,
|
user=instance,
|
||||||
display_name=instance.username,
|
display_name=instance.username,
|
||||||
)
|
)
|
||||||
|
PlayerInfo.objects.create(user=instance, energy=10_000)
|
||||||
3
game/views.py
Normal file
3
game/views.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
11
package.json
Normal file
11
package.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@types/maplibre-gl": "^1.14.0",
|
||||||
|
"esbuild": "^0.27.3",
|
||||||
|
"maplibre-gl": "^5.18.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"dev": "bun run build.js --dev",
|
||||||
|
"build": "bun run build.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,10 +7,12 @@ requires-python = ">=3.13"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"django>=6.0.2",
|
"django>=6.0.2",
|
||||||
"django-ratelimit>=4.1.0",
|
"django-ratelimit>=4.1.0",
|
||||||
|
"django-stubs>=5.2.9",
|
||||||
"djangorestframework>=3.16.1",
|
"djangorestframework>=3.16.1",
|
||||||
"djangorestframework-simplejwt>=5.5.0",
|
"djangorestframework-simplejwt>=5.5.0",
|
||||||
"ipython>=9.10.0",
|
"ipython>=9.10.0",
|
||||||
"pydantic>=2.12.5",
|
"pydantic>=2.12.5",
|
||||||
|
"python-dotenv>=1.2.1",
|
||||||
"uvicorn>=0.40.0",
|
"uvicorn>=0.40.0",
|
||||||
"whitenoise>=6.11.0",
|
"whitenoise>=6.11.0",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ click==8.3.1
|
|||||||
decorator==5.2.1
|
decorator==5.2.1
|
||||||
django==6.0.2
|
django==6.0.2
|
||||||
django-ratelimit==4.1.0
|
django-ratelimit==4.1.0
|
||||||
|
django-stubs==5.2.9
|
||||||
|
django-stubs-ext==5.2.9
|
||||||
djangorestframework==3.16.1
|
djangorestframework==3.16.1
|
||||||
djangorestframework-simplejwt==5.5.1
|
djangorestframework-simplejwt==5.5.1
|
||||||
executing==2.2.1
|
executing==2.2.1
|
||||||
@@ -22,9 +24,11 @@ pydantic==2.12.5
|
|||||||
pydantic-core==2.41.5
|
pydantic-core==2.41.5
|
||||||
pygments==2.19.2
|
pygments==2.19.2
|
||||||
pyjwt==2.11.0
|
pyjwt==2.11.0
|
||||||
|
python-dotenv==1.2.1
|
||||||
sqlparse==0.5.5
|
sqlparse==0.5.5
|
||||||
stack-data==0.6.3
|
stack-data==0.6.3
|
||||||
traitlets==5.14.3
|
traitlets==5.14.3
|
||||||
|
types-pyyaml==6.0.12.20250915
|
||||||
typing-extensions==4.15.0
|
typing-extensions==4.15.0
|
||||||
typing-inspection==0.4.2
|
typing-inspection==0.4.2
|
||||||
uvicorn==0.40.0
|
uvicorn==0.40.0
|
||||||
|
|||||||
12
tsconfig.json
Normal file
12
tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "Bundler",
|
||||||
|
"strict": true,
|
||||||
|
"types": ["maplibre-gl"],
|
||||||
|
"lib": ["ES2020", "DOM"],
|
||||||
|
"noEmit": true
|
||||||
|
},
|
||||||
|
"include": ["frontend/static/frontend/ts/**/*.ts"]
|
||||||
|
}
|
||||||
50
uv.lock
generated
50
uv.lock
generated
@@ -82,6 +82,34 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/fb/78/2c59b30cd8bc8068d02349acb6aeed5c4e05eb01cdf2107ccd76f2e81487/django_ratelimit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d047a31cf94d83ef1465d7543ca66c6fc16695559b5f8d814d1b51df15110b92", size = 11608, upload-time = "2023-07-24T20:34:31.362Z" },
|
{ url = "https://files.pythonhosted.org/packages/fb/78/2c59b30cd8bc8068d02349acb6aeed5c4e05eb01cdf2107ccd76f2e81487/django_ratelimit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d047a31cf94d83ef1465d7543ca66c6fc16695559b5f8d814d1b51df15110b92", size = 11608, upload-time = "2023-07-24T20:34:31.362Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "django-stubs"
|
||||||
|
version = "5.2.9"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "django" },
|
||||||
|
{ name = "django-stubs-ext" },
|
||||||
|
{ name = "types-pyyaml" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/9c/01/86c921e0e19c9fa7e705bf795998dbf55eb183e7be0342a3027dc1bcbc9f/django_stubs-5.2.9.tar.gz", hash = "sha256:c192257120b08785cfe6f2f1c91f1797aceae8e9daa689c336e52c91e8f6a493", size = 257970, upload-time = "2026-01-20T23:59:27.018Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/05/4c9c419b7051eb4b350100b086be6df487f968ab672d3d370f8ccf7c3746/django_stubs-5.2.9-py3-none-any.whl", hash = "sha256:2317a7130afdaa76f6ff7f623650d7f3bf1b6c86a60f95840e14e6ec6de1a7cd", size = 508656, upload-time = "2026-01-20T23:59:25.12Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "django-stubs-ext"
|
||||||
|
version = "5.2.9"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "django" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/55/03/9c2be939490d2282328db4611bc5956899f5ff7eabc3e88bd4b964a87373/django_stubs_ext-5.2.9.tar.gz", hash = "sha256:6db4054d1580657b979b7d391474719f1a978773e66c7070a5e246cd445a25a9", size = 6497, upload-time = "2026-01-20T23:58:59.462Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/f7/0d5f7d7e76fe972d9f560f687fdc0cab4db9e1624fd90728ca29b4ed7a63/django_stubs_ext-5.2.9-py3-none-any.whl", hash = "sha256:230c51575551b0165be40177f0f6805f1e3ebf799b835c85f5d64c371ca6cf71", size = 9974, upload-time = "2026-01-20T23:58:58.438Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "djangorestframework"
|
name = "djangorestframework"
|
||||||
version = "3.16.1"
|
version = "3.16.1"
|
||||||
@@ -115,10 +143,12 @@ source = { virtual = "." }
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "django" },
|
{ name = "django" },
|
||||||
{ name = "django-ratelimit" },
|
{ name = "django-ratelimit" },
|
||||||
|
{ name = "django-stubs" },
|
||||||
{ name = "djangorestframework" },
|
{ name = "djangorestframework" },
|
||||||
{ name = "djangorestframework-simplejwt" },
|
{ name = "djangorestframework-simplejwt" },
|
||||||
{ name = "ipython" },
|
{ name = "ipython" },
|
||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
|
{ name = "python-dotenv" },
|
||||||
{ name = "uvicorn" },
|
{ name = "uvicorn" },
|
||||||
{ name = "whitenoise" },
|
{ name = "whitenoise" },
|
||||||
]
|
]
|
||||||
@@ -127,10 +157,12 @@ dependencies = [
|
|||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "django", specifier = ">=6.0.2" },
|
{ name = "django", specifier = ">=6.0.2" },
|
||||||
{ name = "django-ratelimit", specifier = ">=4.1.0" },
|
{ name = "django-ratelimit", specifier = ">=4.1.0" },
|
||||||
|
{ name = "django-stubs", specifier = ">=5.2.9" },
|
||||||
{ name = "djangorestframework", specifier = ">=3.16.1" },
|
{ name = "djangorestframework", specifier = ">=3.16.1" },
|
||||||
{ name = "djangorestframework-simplejwt", specifier = ">=5.5.0" },
|
{ name = "djangorestframework-simplejwt", specifier = ">=5.5.0" },
|
||||||
{ name = "ipython", specifier = ">=9.10.0" },
|
{ name = "ipython", specifier = ">=9.10.0" },
|
||||||
{ name = "pydantic", specifier = ">=2.12.5" },
|
{ name = "pydantic", specifier = ">=2.12.5" },
|
||||||
|
{ name = "python-dotenv", specifier = ">=1.2.1" },
|
||||||
{ name = "uvicorn", specifier = ">=0.40.0" },
|
{ name = "uvicorn", specifier = ">=0.40.0" },
|
||||||
{ name = "whitenoise", specifier = ">=6.11.0" },
|
{ name = "whitenoise", specifier = ">=6.11.0" },
|
||||||
]
|
]
|
||||||
@@ -347,6 +379,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" },
|
{ url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-dotenv"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlparse"
|
name = "sqlparse"
|
||||||
version = "0.5.5"
|
version = "0.5.5"
|
||||||
@@ -379,6 +420,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" },
|
{ url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "types-pyyaml"
|
||||||
|
version = "6.0.12.20250915"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/7e/69/3c51b36d04da19b92f9e815be12753125bd8bc247ba0470a982e6979e71c/types_pyyaml-6.0.12.20250915.tar.gz", hash = "sha256:0f8b54a528c303f0e6f7165687dd33fafa81c807fcac23f632b63aa624ced1d3", size = 17522, upload-time = "2025-09-15T03:01:00.728Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/e0/1eed384f02555dde685fff1a1ac805c1c7dcb6dd019c916fe659b1c1f9ec/types_pyyaml-6.0.12.20250915-py3-none-any.whl", hash = "sha256:e7d4d9e064e89a3b3cae120b4990cd370874d2bf12fa5f46c97018dd5d3c9ab6", size = 20338, upload-time = "2025-09-15T03:00:59.218Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typing-extensions"
|
name = "typing-extensions"
|
||||||
version = "4.15.0"
|
version = "4.15.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user