Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 4.2.20 on 2025-05-25 22:03

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("games", "0047_merge_20250524_2245"),
]

operations = [
migrations.AddField(
model_name="game",
name="twine_file_name",
field=models.CharField(blank=True, max_length=255, null=True),
),
migrations.AlterField(
model_name="game",
name="twine_file",
field=models.BinaryField(blank=True, null=True),
),
]
12 changes: 12 additions & 0 deletions src/chigame/games/migrations/0049_merge_20250525_1739.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Generated by Django 4.2.20 on 2025-05-25 22:39

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("games", "0048_game_twine_file_name_alter_game_twine_file"),
("games", "0048_lobby_join_code"),
]

operations = []
4 changes: 3 additions & 1 deletion src/chigame/games/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ class Game(models.Model):
max_players = models.PositiveIntegerField()

# interactive fiction - twine file
twine_file = models.FileField(upload_to="twine_games/", null=True, blank=True)
# want twine file to be binary to store in the actual database
twine_file_name = models.CharField(max_length=255, null=True, blank=True)
twine_file = models.BinaryField(null=True, blank=True)

suggested_age = models.PositiveSmallIntegerField(
null=True, blank=True
Expand Down
1 change: 1 addition & 0 deletions src/chigame/games/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
path("interactive-fiction/", views.IFGameCreateView.as_view(), name="interactive-fiction-create"),
path("<int:pk>/upload/", UploadFileView.as_view(), name="upload-file"),
path("if-game/<int:pk>/", InteractiveFictionView.as_view(), name="interactive-fiction-detail"),
path("twine-db/<int:pk>/", views.serve_twine_from_db, name="twine-db"),
# tournaments
path("tournaments/", views.TournamentListView.as_view(), name="tournament-list"),
path("tournaments/<int:pk>/", views.TournamentDetailView.as_view(), name="tournament-detail"),
Expand Down
28 changes: 21 additions & 7 deletions src/chigame/games/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from django.db.models import Avg, Case, Count, ExpressionWrapper, F, FloatField, Q, Value, When
from django.db.models.functions import Lower
from django.forms import ValidationError
from django.http import HttpResponseForbidden, HttpResponseRedirect, JsonResponse
from django.http import Http404, HttpResponse, HttpResponseForbidden, HttpResponseRedirect, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse, reverse_lazy
from django.utils import timezone
Expand Down Expand Up @@ -123,7 +123,7 @@ def get_context_data(self, **kwargs):
context["avg_rating"] = self.object.reviews.filter(is_public=True).aggregate(Avg("rating"))["rating__avg"]

# FOR IF/twine GAMES
context["is_twine_game"] = self.object.twine_file.name.endswith(".html") if self.object.twine_file else False
context["is_twine_game"] = self.object.twine_file is not None
context["recommended_games"] = get_recommended_games(
game=self.object,
user=self.request.user if self.request.user.is_authenticated else None,
Expand Down Expand Up @@ -171,13 +171,17 @@ def get_context_data(self, **kwargs):
def form_valid(self, form):
self.object = form.save(commit=False)
# ✅ Manually assign uploaded file
if self.request.FILES.get("twine_file"):
self.object.twine_file = self.request.FILES["twine_file"]
uploaded_file = self.request.FILES.get("twine_file")
if uploaded_file:
self.object.twine_file_name = uploaded_file.name
self.object.twine_file = uploaded_file.read()
uploaded_file.seek(0)

self.object.save()
return redirect(self.get_success_url())

def get_success_url(self):
if self.object.twine_file and self.object.twine_file.name.endswith(".html"):
if self.object.twine_file_name and self.object.twine_file_name.endswith(".html"):
return reverse("interactive-fiction-detail", kwargs={"pk": self.object.pk})
return reverse("game-detail", kwargs={"pk": self.object.pk})

Expand All @@ -202,6 +206,17 @@ def get_context_data(self, **kwargs):
return context


def serve_twine_from_db(request, pk):
game = get_object_or_404(Game, pk=pk)
if not game.twine_file:
raise Http404("No Twine file stored in database.")
return HttpResponse(
game.twine_file,
content_type="text/html",
headers={"Content-Disposition": f'inline; filename="{game.twine_file_name}"'},
)


# =============== Game: Create and Join Matches ===============
class MatchCreateView(CreateView):
model = Match
Expand Down Expand Up @@ -675,8 +690,7 @@ def get_context_data(self, **kwargs):
context["game"] = latest_game

if latest_game.twine_file:
context["uploaded_file_url"] = latest_game.twine_file.url

context["has_uploaded_twine"] = bool(latest_game.twine_file)
return context


Expand Down
9 changes: 8 additions & 1 deletion src/templates/games/game_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,19 @@ <h3 id="description">Description</h3>
</p>
{% endif %}
<p>{{ game.description|linebreaksbr }}</p>
{% if is_twine_game %}
{% if game.twine_file %}
<h3>Play Twine Game</h3>
<a href="{{ game.twine_file.url }}"
target="_blank"
class="btn btn-success">Open Game in New Tab</a>
{% endif %}
<!-- stored in database game code -->
{% if game.twine_file_content %}
<h3>Play Twine Game from Database</h3>
<a href="{% url 'twine-db' game.pk %}"
target="_blank"
class="btn btn-success">Open Game in New Tab</a>
{% endif %}
<h3 id="player-description">Players</h3>
<p>
{% if game.min_players == game.max_players %}
Expand Down
5 changes: 5 additions & 0 deletions src/templates/games/game_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ <h1>
</div>
<br />
{% endfor %}
<!-- Twine upload (manual field) -->
<label for="id_twine_file">Upload Twine Game (.html):</label>
<button type="submit">Save</button>
<input type="file" name="twine_file" id="id_twine_file" accept=".html" />
<br />
<br />
</form>
<!-- AJAX script for BGG search (only in Create view) -->
{% if is_create %}
Expand Down