register and sign in pages

This commit is contained in:
2026-09-22 00:50:30 +05:00
parent f313867653
commit 78d04f75d1
96 changed files with 6383 additions and 109 deletions
View File
+22
View File
@@ -0,0 +1,22 @@
from django.contrib import admin
from .models import Atoll, Island
class IslandInline(admin.TabularInline):
model = Island
extra = 0
@admin.register(Atoll)
class AtollAdmin(admin.ModelAdmin):
list_display = ["name", "code", "is_active"]
search_fields = ["name", "code"]
inlines = [IslandInline]
@admin.register(Island)
class IslandAdmin(admin.ModelAdmin):
list_display = ["name", "atoll", "is_active"]
list_filter = ["atoll", "is_active"]
search_fields = ["name"]
+17
View File
@@ -0,0 +1,17 @@
from rest_framework.generics import ListAPIView
from rest_framework.permissions import AllowAny
from .models import Atoll
from .serializers import AtollSerializer
class AtollListView(ListAPIView):
"""Public: the registration form needs this before anyone has a token."""
authentication_classes = []
permission_classes = [AllowAny]
serializer_class = AtollSerializer
pagination_class = None
def get_queryset(self):
return Atoll.objects.filter(is_active=True).prefetch_related("islands")
+6
View File
@@ -0,0 +1,6 @@
from django.apps import AppConfig
class LocationsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "locations"
@@ -0,0 +1,16 @@
from django.core.management.base import BaseCommand
from locations.models import Atoll, Island
from locations.seed import seed
class Command(BaseCommand):
help = "Create the atolls and islands SAR Link serves (idempotent)."
def handle(self, *args, **options):
atolls, islands = seed(Atoll, Island)
self.stdout.write(
self.style.SUCCESS(
f"Locations seeded: {atolls} atoll(s), {islands} island(s) created."
)
)
@@ -0,0 +1,40 @@
# Generated by Django 5.2.7 on 2026-09-21 19:05
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Atoll',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100, unique=True)),
('code', models.CharField(blank=True, max_length=8)),
('is_active', models.BooleanField(default=True)),
],
options={
'ordering': ['name'],
},
),
migrations.CreateModel(
name='Island',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('is_active', models.BooleanField(default=True)),
('atoll', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='islands', to='locations.atoll')),
],
options={
'ordering': ['name'],
'constraints': [models.UniqueConstraint(fields=('atoll', 'name'), name='unique_island_name_per_atoll')],
},
),
]
@@ -0,0 +1,32 @@
from django.db import migrations
from locations.seed import seed
def seed_locations(apps, schema_editor):
seed(apps.get_model("locations", "Atoll"), apps.get_model("locations", "Island"))
def unseed_locations(apps, schema_editor):
"""Only removes rows nothing references."""
Atoll = apps.get_model("locations", "Atoll")
Island = apps.get_model("locations", "Island")
from locations.seed import ATOLLS
for entry in ATOLLS:
Island.objects.filter(
atoll__name=entry["name"], name__in=entry["islands"], users__isnull=True
).delete()
Atoll.objects.filter(
name=entry["name"], islands__isnull=True, users__isnull=True
).delete()
class Migration(migrations.Migration):
dependencies = [
("locations", "0001_initial"),
# Islands/atolls are referenced by users; keep the tables in step.
("users", "0001_initial"),
]
operations = [migrations.RunPython(seed_locations, unseed_locations)]
+31
View File
@@ -0,0 +1,31 @@
from django.db import models
class Atoll(models.Model):
name = models.CharField(max_length=100, unique=True)
# Maldivian administrative code, e.g. "F" for Faafu.
code = models.CharField(max_length=8, blank=True)
is_active = models.BooleanField(default=True)
class Meta:
ordering = ["name"]
def __str__(self):
return self.name
class Island(models.Model):
atoll = models.ForeignKey(Atoll, on_delete=models.PROTECT, related_name="islands")
name = models.CharField(max_length=100)
is_active = models.BooleanField(default=True)
class Meta:
ordering = ["name"]
constraints = [
models.UniqueConstraint(
fields=["atoll", "name"], name="unique_island_name_per_atoll"
)
]
def __str__(self):
return f"{self.name}, {self.atoll.name}"
+37
View File
@@ -0,0 +1,37 @@
"""Seed data for atolls and islands.
Only the areas SAR Link actually serves are listed. Add more here (or in the
admin) as coverage grows; `seed()` is idempotent, so re-running is safe.
"""
ATOLLS = [
{
"name": "Faafu",
"code": "F",
"islands": ["Dharanboodhoo"],
},
]
def seed(atoll_model, island_model) -> tuple[int, int]:
"""Create any missing atolls/islands. Returns (atolls, islands) created.
Takes the models as arguments so both the management command and the data
migration can call it, the latter with historical models.
"""
atolls_created = 0
islands_created = 0
for entry in ATOLLS:
atoll, created = atoll_model.objects.get_or_create(
name=entry["name"], defaults={"code": entry.get("code", "")}
)
atolls_created += int(created)
for island_name in entry["islands"]:
_, created = island_model.objects.get_or_create(
atoll=atoll, name=island_name
)
islands_created += int(created)
return atolls_created, islands_created
+23
View File
@@ -0,0 +1,23 @@
from rest_framework import serializers
from .models import Atoll, Island
class IslandSerializer(serializers.ModelSerializer):
class Meta:
model = Island
fields = ["id", "name", "atoll"]
class AtollSerializer(serializers.ModelSerializer):
"""Atolls with their islands nested - the registration form needs both."""
islands = serializers.SerializerMethodField()
class Meta:
model = Atoll
fields = ["id", "name", "code", "islands"]
def get_islands(self, obj) -> list[dict]:
islands = [island for island in obj.islands.all() if island.is_active]
return IslandSerializer(islands, many=True).data
View File
+7
View File
@@ -0,0 +1,7 @@
from django.urls import path
from .api import AtollListView
urlpatterns = [
path("atolls/", AtollListView.as_view(), name="atoll-list"),
]