massive additions made thru somewhat new apps.epic.models, .urls, .views; new html page & partial in apps/gameboard; new apps.epic FT & ITs (all green); New Game applet now actually leads to game room feat. token-drop gatekeeper mechanism intended for 6 gamers

This commit is contained in:
Disco DeDisco
2026-03-13 00:31:17 -04:00
parent 681a1a4cd0
commit 5773462b4c
12 changed files with 303 additions and 7 deletions

View File

@@ -0,0 +1,26 @@
# Generated by Django 6.0 on 2026-03-12 19:30
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dashboard', '0002_rename_list_to_note'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AlterField(
model_name='note',
name='owner',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='notes', to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='note',
name='shared_with',
field=models.ManyToManyField(blank=True, related_name='shared_notes', to=settings.AUTH_USER_MODEL),
),
]

View File

@@ -0,0 +1,45 @@
# Generated by Django 6.0 on 2026-03-12 19:46
import django.db.models.deletion
import uuid
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='Room',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(max_length=200)),
('visibility', models.CharField(choices=[('PRIVATE', 'Private'), ('PUBLIC', 'Public'), ('INVITE ONLY', 'Invite Only')], default='PRIVATE', max_length=20)),
('gate_status', models.CharField(choices=[('GATHERING', 'Gathering'), ('OPEN', 'Open'), ('RENEWAL_DUE', 'Renewal Due')], default='GATHERING', max_length=20)),
('renewal_period', models.DurationField(blank=True, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('board_state', models.JSONField(default=dict)),
('seed_count', models.IntegerField(default=12)),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='owned_rooms', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='GateSlot',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('slot_number', models.IntegerField()),
('status', models.CharField(choices=[('EMPTY', 'Empty'), ('RESERVED', 'Reserved'), ('FILLED', 'Filled')], default='EMPTY', max_length=10)),
('reserved_at', models.DateTimeField(blank=True, null=True)),
('filled_at', models.DateTimeField(blank=True, null=True)),
('funded_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='funded_slots', to=settings.AUTH_USER_MODEL)),
('gamer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='gate_slots', to=settings.AUTH_USER_MODEL)),
('room', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='gate_slots', to='epic.room')),
],
),
]

View File

@@ -1,3 +1,69 @@
from django.db import models
import uuid
# Create your models here.
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
class Room(models.Model):
GATHERING = "GATHERING"
OPEN = "OPEN"
RENEWAL_DUE = "RENEWAL_DUE"
GATE_STATUS_CHOICES = [
(GATHERING, "Gathering"),
(OPEN, "Open"),
(RENEWAL_DUE, "Renewal Due"),
]
PRIVATE = "PRIVATE"
PUBLIC = "PUBLIC"
INVITE_ONLY = "INVITE ONLY"
VISIBILITY_CHOICES = [
(PRIVATE, "Private"),
(PUBLIC, "Public"),
(INVITE_ONLY, "Invite Only"),
]
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=200)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="owned_rooms"
)
visibility = models.CharField(max_length=20, choices=VISIBILITY_CHOICES, default=PRIVATE)
gate_status = models.CharField(max_length=20, choices=GATE_STATUS_CHOICES, default=GATHERING)
renewal_period = models.DurationField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
board_state = models.JSONField(default=dict)
seed_count = models.IntegerField(default=12)
class GateSlot(models.Model):
EMPTY = "EMPTY"
RESERVED = "RESERVED"
FILLED = "FILLED"
STATUS_CHOICES = [
(EMPTY, "Empty"),
(RESERVED, "Reserved"),
(FILLED, "Filled"),
]
room = models.ForeignKey(Room, on_delete=models.CASCADE, related_name="gate_slots")
slot_number = models.IntegerField()
gamer = models.ForeignKey(
settings.AUTH_USER_MODEL, null=True, blank=True,
on_delete=models.SET_NULL, related_name="gate_slots"
)
funded_by = models.ForeignKey(
settings.AUTH_USER_MODEL, null=True, blank=True,
on_delete=models.SET_NULL, related_name="funded_slots"
)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default=EMPTY)
reserved_at = models.DateTimeField(null=True, blank=True)
filled_at = models.DateTimeField(null=True, blank=True)
@receiver(post_save, sender=Room)
def create_gate_slots(sender, instance, created, **kwargs):
if created:
for i in range(1, 7):
GateSlot.objects.create(room=instance, slot_number=i)

View File

@@ -0,0 +1,11 @@
from django.test import TestCase
from apps.lyric.models import User
from apps.epic.models import Room, GateSlot
class RoomCreationTest(TestCase):
def test_creating_a_room_generates_six_gate_slots(self):
owner = User.objects.create(email="founder@example.com")
room = Room.objects.create(name="Test Room", owner=owner)
self.assertEqual(GateSlot.objects.filter(room=room).count(), 6)

View File

@@ -0,0 +1,31 @@
from django.test import TestCase
from django.urls import reverse
from apps.lyric.models import User
from apps.epic.models import Room
class RoomCreationViewTest(TestCase):
def setUp(self):
self.user = User.objects.create(email="founder@test.io")
self.client.force_login(self.user)
def test_post_creates_room_and_redirects_to_gatekeeper(self):
response = self.client.post(
reverse("epic:create_room"),
data={"name": "Test Room"},
)
room = Room.objects.get(owner=self.user)
self.assertRedirects(
response, reverse(
"epic:gatekeeper",
args=[room.id],
)
)
def test_post_requires_login(self):
self.client.logout()
response = self.client.post(
reverse("epic:create_room"),
data={"name": "Test Room"},
)

View File

@@ -0,0 +1,11 @@
from django.urls import path
from . import views
app_name = 'epic'
urlpatterns = [
path('rooms/create_room', views.create_room, name='create_room'),
path('room/<uuid:room_id>/gate/', views.gatekeeper, name='gatekeeper'),
]

View File

@@ -1,3 +1,22 @@
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, render
# Create your views here.
from apps.epic.models import Room
@login_required
def create_room(request):
if request.method == "POST":
name = request.POST.get("name", "").strip()
if name:
room = Room.objects.create(name=name, owner=request.user)
return redirect("epic:gatekeeper", room_id=room.id)
return redirect("gameboard:index")
def gatekeeper(request, room_id):
room = Room.objects.get(id=room_id)
slots = room.gate_slots.order_by("slot_number")
return render(request, "apps/gameboard/room.html", {
'room': room,
'slots': slots,
})