Compare commits

..

6 Commits

10 changed files with 143 additions and 17 deletions

View File

@ -119,3 +119,5 @@ USE_TZ = True
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = '/static/'
LOGIN_URL = '/accounts/login/'

View File

@ -18,5 +18,6 @@ from django.urls import path, include
urlpatterns = [
path('writing/', include('writingtogether.urls')),
path('accounts/', include('django.contrib.auth.urls')),
path('admin/', admin.site.urls),
]

View File

@ -1,3 +1,5 @@
from typing import Tuple
from django.contrib.auth import get_user_model
from django.db import models
from django.db.models import CASCADE
@ -29,6 +31,14 @@ class StoryRound(models.Model):
return False
return True
def advance_to_next_turn_and_get_status_and_round_number(self) -> Tuple[str, int]:
if self.current_turn+1 == self.number_of_rounds:
return 'finished', self.current_turn
self.current_turn += 1
self.save()
return 'ongoing', self.current_turn
#class Participant(models.Model):
# user = models.ForeignKey(User, on_delete=CASCADE)
@ -60,9 +70,9 @@ class StoryPart(models.Model):
user = models.ForeignKey(User, on_delete=CASCADE)
previous_part = models.ForeignKey('StoryPart', on_delete=CASCADE, null=True, blank=True)
text = models.TextField(null=True, blank=True)
part_of = models.ForeignKey('Story', on_delete=CASCADE)
part_of = models.ForeignKey('Story', on_delete=CASCADE, related_name='parts')
turn_number = models.IntegerField()
@property
def finished(self):
return self.text
return bool(self.text)

View File

@ -0,0 +1,36 @@
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Your account doesn't have access to this page. To proceed,
please login with an account that has access.</p>
{% else %}
<p>Please login to see this page.</p>
{% endif %}
{% endif %}
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</tr>
</table>
<input type="submit" value="login">
<input type="hidden" name="next" value="{{ next }}">
</form>
{# Assumes you setup the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>
{% endblock %}

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>Fertig!</h1>
{% for story in stories %}
{% for story_part in story.parts.all %}
<div>{{ story_part.text }} <i>({{ story_part.user }})</i></div>
{% endfor %}
<br>
<br>
{% endfor %}
</body>
</html>

View File

@ -5,8 +5,12 @@
<title>Title</title>
</head>
<body>
<h1>Runde {{ current_round }} / {{ total_rounds }}</h1>
<form action="{% url 'writing:create_story_part' %}" method="post">
{% if previous_part %}
<div>Letzter Satz: {{ previous_part.text }}</div>
{% endif %}
<form action="{% url 'writing:update_story_part' story_round_pk=story_round_pk story_pk=story_pk pk=pk %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div>Die nächste Runde ist noch nicht bereit.</div>
<div>Klick hier um zu prüfen, ob die anderen fertig sind:
<a href="{% url 'writing:redirect_story_part' story_round_pk=object.pk %}">nächste Runde</a>
</div>
</body>
</html>

View File

@ -9,8 +9,9 @@ User = get_user_model()
class TestViews(TestCase):
def setUp(self) -> None:
self.user1 = User.objects.create(username='player1')
self.user2 = User.objects.create(username='player2')
self.user1 = User.objects.create_user(username='player1', password='12345')
self.user2 = User.objects.create_user(username='player2')
self.client.login(username='player1', password='12345')
def test_create_story_round_two_rounds(self):

View File

@ -8,6 +8,8 @@ urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('create/', views.StoryRoundCreate.as_view(), name='create_story_round'),
path('open/<int:story_round_pk>/<int:story_pk>/<int:story_part_pk>/', views.StoryPartUpdate.as_view(), name='update_story_part'),
path('open/<int:story_round_pk>/<int:story_pk>/<int:pk>/', views.StoryPartUpdate.as_view(), name='update_story_part'),
path('open/<int:pk>/waiting/', views.WaitForOthersView.as_view(), name='wait_for_others'),
path('open/<int:story_round_pk>/', views.RedirectToNextOpenPart.as_view(), name='redirect_story_part'),
path('finished/<int:pk>/', views.RoundFinishedView.as_view(), name ='finished'),
]

View File

@ -1,16 +1,15 @@
from django import forms
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
# Create your views here.
from django.urls import reverse_lazy, reverse
from django.views import generic
from django.views.generic import CreateView, UpdateView, RedirectView
from django.views.generic import CreateView, UpdateView, RedirectView, DetailView, ListView
from writingtogether.models import Story, StoryPart, StoryRound
class IndexView(generic.ListView):
class IndexView(LoginRequiredMixin, ListView):
template_name = 'writingtogether/index.html'
context_object_name = 'open_story_round_list'
@ -19,12 +18,12 @@ class IndexView(generic.ListView):
return StoryRound.objects.order_by('-created')[:5]
class DetailView(generic.DetailView):
class StoryRoundDetailView(LoginRequiredMixin, DetailView):
model = StoryRound
template_name = 'writingtogether/detail.html'
class StoryRoundCreate(CreateView):
class StoryRoundCreate(LoginRequiredMixin, CreateView):
model = StoryRound
fields = ['name', 'participants', 'number_of_rounds']
success_url = reverse_lazy('writing:index')
@ -53,15 +52,27 @@ class StoryRoundCreate(CreateView):
return HttpResponseRedirect(self.get_success_url())
class StoryUpdate(UpdateView):
class StoryUpdate(LoginRequiredMixin, UpdateView):
model = Story
fields = ['name']
class StoryPartUpdate(UpdateView):
class StoryPartUpdate(LoginRequiredMixin, UpdateView):
model = StoryPart
fields = ['text']
template_name = 'writingtogether/story_part.html'
success_url = reverse_lazy('writing:index')
def get_context_data(self, **kwargs):
context = super(StoryPartUpdate, self).get_context_data(**kwargs)
context.update({
'current_round': self.object.turn_number + 1,
'total_rounds': self.object.part_of.part_of_round.number_of_rounds,
'previous_part': self.object.previous_part,
})
context.update(self.kwargs)
return context
#def form_valid(self, form):
# form.instance.created_by = self.request.user
@ -70,7 +81,7 @@ class StoryPartUpdate(UpdateView):
# return super().form_valid(form)
class RedirectToNextOpenPart(RedirectView):
class RedirectToNextOpenPart(LoginRequiredMixin, RedirectView):
permanent = False
query_string = True
pattern_name = 'writing:update_story_part'
@ -78,8 +89,34 @@ class RedirectToNextOpenPart(RedirectView):
def get_redirect_url(self, *args, **kwargs):
story_round = get_object_or_404(StoryRound, pk=kwargs['story_round_pk'])
if story_round.next_round_ready():
status, turn_number = story_round.advance_to_next_turn_and_get_status_and_round_number()
if status == 'finished':
self.pattern_name = 'writing:finished'
kwargs['pk'] = kwargs.pop('story_round_pk')
return super().get_redirect_url(*args, **kwargs)
story_part = story_round.get_next_story_part(user=self.request.user)
if story_part.finished:
self.pattern_name = 'writing:wait_for_others'
kwargs['pk'] = kwargs.pop('story_round_pk')
else:
kwargs['story_pk'] = story_part.part_of.pk
kwargs['story_part_pk'] = story_part.pk
kwargs['pk'] = story_part.pk
return super().get_redirect_url(*args, **kwargs)
class WaitForOthersView(LoginRequiredMixin, DetailView):
model = StoryRound
template_name = 'writingtogether/wait_for_others.html'
class RoundFinishedView(LoginRequiredMixin, ListView):
model = Story
context_object_name = 'stories'
template_name = 'writingtogether/finished.html'
def get_queryset(self):
return Story.objects.filter(part_of_round_id=self.kwargs['pk']).prefetch_related('parts')