mirror of
https://github.com/Crocmagnon/charasheet.git
synced 2024-11-05 14:23:53 +01:00
Allow GM to increase/decrese battle effects rounds
This commit is contained in:
parent
27afcc7791
commit
ad5e690e21
6 changed files with 146 additions and 20 deletions
|
@ -1,5 +1,5 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
from django.db.models import F, Q
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django_extensions.db.models import TimeStampedModel
|
from django_extensions.db.models import TimeStampedModel
|
||||||
|
|
||||||
|
@ -69,8 +69,27 @@ class Party(UniquelyNamedModel, TimeStampedModel, models.Model):
|
||||||
character.reset_stats()
|
character.reset_stats()
|
||||||
|
|
||||||
|
|
||||||
|
class BattleEffectQuerySet(models.QuerySet):
|
||||||
|
def increase_rounds(self):
|
||||||
|
self.temporary().update(remaining_rounds=F("remaining_rounds") + 1)
|
||||||
|
|
||||||
|
def decrease_rounds(self):
|
||||||
|
self.active().update(remaining_rounds=F("remaining_rounds") - 1)
|
||||||
|
|
||||||
|
def active(self):
|
||||||
|
return self.filter(remaining_rounds__gt=0)
|
||||||
|
|
||||||
|
def terminated(self):
|
||||||
|
return self.filter(remaining_rounds=0)
|
||||||
|
|
||||||
|
def permanent(self):
|
||||||
|
return self.filter(remaining_rounds=-1)
|
||||||
|
|
||||||
|
def temporary(self):
|
||||||
|
return self.exclude(remaining_rounds=-1)
|
||||||
|
|
||||||
|
|
||||||
class BattleEffectManager(models.Manager):
|
class BattleEffectManager(models.Manager):
|
||||||
def decrease_all_remaining_rounds(self):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,7 +118,7 @@ class BattleEffect(TimeStampedModel, models.Model):
|
||||||
verbose_name="créé par",
|
verbose_name="créé par",
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = BattleEffectManager()
|
objects = BattleEffectManager.from_queryset(BattleEffectQuerySet)()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def remaining_percent(self) -> float:
|
def remaining_percent(self) -> float:
|
||||||
|
|
|
@ -7,10 +7,12 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{{ party.name }}</h1>
|
<h1>{{ party.name }}</h1>
|
||||||
<p>MJ : {{ party.game_master.get_full_name|default:party.game_master.username }}</p>
|
<p>MJ : {{ party.game_master.get_full_name|default:party.game_master.username }}</p>
|
||||||
|
{% if party.game_master == request.user %}
|
||||||
<p>
|
<p>
|
||||||
<a href="{% url "party:reset_stats" pk=party.pk %}" id="reset-stats">Réinitialiser
|
<a href="{% url "party:reset_stats" pk=party.pk %}" id="reset-stats">Réinitialiser
|
||||||
les stats</a>
|
les stats</a>
|
||||||
</p>
|
</p>
|
||||||
|
{% endif %}
|
||||||
<h2 class="mt-4">Personnages</h2>
|
<h2 class="mt-4">Personnages</h2>
|
||||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 row-cols-xl-4 g-4">
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 row-cols-xl-4 g-4">
|
||||||
{% for character in party.characters.all %}
|
{% for character in party.characters.all %}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
{% load character_extras %}
|
||||||
<div id="effects">
|
<div id="effects">
|
||||||
<div id="effects-form">
|
<div id="effects-form">
|
||||||
<button
|
<button
|
||||||
|
@ -8,6 +9,26 @@
|
||||||
id="add-effect"
|
id="add-effect"
|
||||||
class="btn btn-primary"><i class="fa-solid fa-plus"></i> Ajouter un effet
|
class="btn btn-primary"><i class="fa-solid fa-plus"></i> Ajouter un effet
|
||||||
</button>
|
</button>
|
||||||
|
{% if party.game_master == request.user %}
|
||||||
|
<div class="btn-group">
|
||||||
|
<button
|
||||||
|
hx-get="{% url "party:increase_rounds" pk=party.pk %}"
|
||||||
|
hx-target="#effects"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
type="button"
|
||||||
|
id="increase-rounds"
|
||||||
|
class="btn btn-outline-secondary"> <i class="fa-solid fa-plus"></i> tours
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
hx-get="{% url "party:decrease_rounds" pk=party.pk %}"
|
||||||
|
hx-target="#effects"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
type="button"
|
||||||
|
id="decrease-rounds"
|
||||||
|
class="btn btn-outline-secondary"> <i class="fa-solid fa-minus"></i> tours
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div id="effects-cards" class="row mt-1 row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 g-4">
|
<div id="effects-cards" class="row mt-1 row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 g-4">
|
||||||
{% for effect in party.effects.all %}
|
{% for effect in party.effects.all %}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import random
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from model_bakery import baker
|
from model_bakery import baker
|
||||||
|
@ -137,13 +139,8 @@ def test_player_can_add_effect_to_group(
|
||||||
)
|
)
|
||||||
remaining_rounds = "8"
|
remaining_rounds = "8"
|
||||||
|
|
||||||
login(selenium, live_server, user, password)
|
go_to_party(selenium, live_server, party, user, password)
|
||||||
|
|
||||||
url = reverse("party:details", kwargs={"pk": party.pk})
|
|
||||||
selenium.get(live_server.url + url)
|
|
||||||
|
|
||||||
fill_effect(selenium, name, description, target, remaining_rounds)
|
fill_effect(selenium, name, description, target, remaining_rounds)
|
||||||
|
|
||||||
assert_effect_is_created(name, description, target, remaining_rounds)
|
assert_effect_is_created(name, description, target, remaining_rounds)
|
||||||
# Todo: assert effect is displayed
|
# Todo: assert effect is displayed
|
||||||
|
|
||||||
|
@ -170,13 +167,8 @@ def test_gm_can_add_effect_to_group(
|
||||||
)
|
)
|
||||||
remaining_rounds = "-1"
|
remaining_rounds = "-1"
|
||||||
|
|
||||||
login(selenium, live_server, user, password)
|
go_to_party(selenium, live_server, party, user, password)
|
||||||
|
|
||||||
url = reverse("party:details", kwargs={"pk": party.pk})
|
|
||||||
selenium.get(live_server.url + url)
|
|
||||||
|
|
||||||
fill_effect(selenium, name, description, target, remaining_rounds)
|
fill_effect(selenium, name, description, target, remaining_rounds)
|
||||||
|
|
||||||
assert_effect_is_created(name, description, target, remaining_rounds)
|
assert_effect_is_created(name, description, target, remaining_rounds)
|
||||||
# Todo: assert effect is displayed
|
# Todo: assert effect is displayed
|
||||||
|
|
||||||
|
@ -186,6 +178,59 @@ def test_gm_can_change_remaining_rounds(
|
||||||
selenium: WebDriver, live_server: LiveServer, initial_data: None
|
selenium: WebDriver, live_server: LiveServer, initial_data: None
|
||||||
):
|
):
|
||||||
"""The GM of a group can increase or decrease the remaining rounds of effects."""
|
"""The GM of a group can increase or decrease the remaining rounds of effects."""
|
||||||
|
user, password = "gm", "password"
|
||||||
|
gm = User.objects.create_user(user, password=password)
|
||||||
|
party = baker.make(Party, game_master=gm)
|
||||||
|
|
||||||
|
active_not_nearly_terminated = baker.make( # noqa: F841
|
||||||
|
BattleEffect,
|
||||||
|
_quantity=7,
|
||||||
|
remaining_rounds=lambda: random.randint(2, 12),
|
||||||
|
party=party,
|
||||||
|
)
|
||||||
|
active_nearly_terminated = baker.make( # noqa: F841
|
||||||
|
BattleEffect, _quantity=3, remaining_rounds=1, party=party
|
||||||
|
)
|
||||||
|
terminated = baker.make( # noqa: F841
|
||||||
|
BattleEffect, _quantity=5, remaining_rounds=0, party=party
|
||||||
|
)
|
||||||
|
permanent = baker.make( # noqa: F841
|
||||||
|
BattleEffect, _quantity=2, remaining_rounds=-1, party=party
|
||||||
|
)
|
||||||
|
not_party = baker.make(BattleEffect, _quantity=4, remaining_rounds=55) # noqa: F841
|
||||||
|
|
||||||
|
go_to_party(selenium, live_server, party, user, password)
|
||||||
|
selenium.find_element(By.ID, "increase-rounds").click()
|
||||||
|
assert BattleEffect.objects.filter(party=party).permanent().count() == 2
|
||||||
|
assert (
|
||||||
|
BattleEffect.objects.filter(party=party, remaining_rounds__gt=1).count() == 10
|
||||||
|
)
|
||||||
|
assert BattleEffect.objects.filter(party=party, remaining_rounds=1).count() == 5
|
||||||
|
assert BattleEffect.objects.filter(party=party).terminated().count() == 0
|
||||||
|
assert (
|
||||||
|
BattleEffect.objects.exclude(party=party).filter(remaining_rounds=55).count()
|
||||||
|
== 4
|
||||||
|
)
|
||||||
|
|
||||||
|
selenium.find_element(By.ID, "decrease-rounds").click()
|
||||||
|
assert BattleEffect.objects.filter(party=party).permanent().count() == 2
|
||||||
|
assert BattleEffect.objects.filter(party=party, remaining_rounds__gt=1).count() == 7
|
||||||
|
assert BattleEffect.objects.filter(party=party, remaining_rounds=1).count() == 3
|
||||||
|
assert BattleEffect.objects.filter(party=party).terminated().count() == 5
|
||||||
|
assert (
|
||||||
|
BattleEffect.objects.exclude(party=party).filter(remaining_rounds=55).count()
|
||||||
|
== 4
|
||||||
|
)
|
||||||
|
|
||||||
|
selenium.find_element(By.ID, "decrease-rounds").click()
|
||||||
|
assert BattleEffect.objects.filter(party=party).permanent().count() == 2
|
||||||
|
assert BattleEffect.objects.filter(party=party).active().count() == 7
|
||||||
|
assert BattleEffect.objects.filter(party=party, remaining_rounds=1).count() == 0
|
||||||
|
assert BattleEffect.objects.filter(party=party).terminated().count() == 8
|
||||||
|
assert (
|
||||||
|
BattleEffect.objects.exclude(party=party).filter(remaining_rounds=55).count()
|
||||||
|
== 4
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
|
@ -234,3 +279,9 @@ def assert_effect_is_created(name, description, target, remaining_rounds):
|
||||||
assert effect.target == target
|
assert effect.target == target
|
||||||
assert effect.description == description
|
assert effect.description == description
|
||||||
assert str(effect.remaining_rounds) == remaining_rounds
|
assert str(effect.remaining_rounds) == remaining_rounds
|
||||||
|
|
||||||
|
|
||||||
|
def go_to_party(selenium, live_server, party, user, password):
|
||||||
|
login(selenium, live_server, user, password)
|
||||||
|
url = reverse("party:details", kwargs={"pk": party.pk})
|
||||||
|
selenium.get(live_server.url + url)
|
||||||
|
|
|
@ -11,6 +11,12 @@ urlpatterns = [
|
||||||
path("<int:pk>/delete/", views.party_delete, name="delete"),
|
path("<int:pk>/delete/", views.party_delete, name="delete"),
|
||||||
path("<int:pk>/reset_stats/", views.party_reset_stats, name="reset_stats"),
|
path("<int:pk>/reset_stats/", views.party_reset_stats, name="reset_stats"),
|
||||||
path("<int:pk>/add_effect/", views.party_add_effect, name="add_effect"),
|
path("<int:pk>/add_effect/", views.party_add_effect, name="add_effect"),
|
||||||
|
path(
|
||||||
|
"<int:pk>/increase_rounds/", views.party_increase_rounds, name="increase_rounds"
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"<int:pk>/decrease_rounds/", views.party_decrease_rounds, name="decrease_rounds"
|
||||||
|
),
|
||||||
path("<int:pk>/leave/<int:character_pk>/", views.party_leave, name="leave"),
|
path("<int:pk>/leave/<int:character_pk>/", views.party_leave, name="leave"),
|
||||||
path("<int:pk>/join/<int:character_pk>/", views.party_join, name="join"),
|
path("<int:pk>/join/<int:character_pk>/", views.party_join, name="join"),
|
||||||
path("<int:pk>/refuse/<int:character_pk>/", views.party_refuse, name="refuse"),
|
path("<int:pk>/refuse/<int:character_pk>/", views.party_refuse, name="refuse"),
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
|
from django.views.decorators.http import require_GET, require_http_methods
|
||||||
|
|
||||||
from character.models import Character, HarmfulState
|
from character.models import Character, HarmfulState
|
||||||
from party.forms import BattleEffectForm, PartyForm
|
from party.forms import BattleEffectForm, PartyForm
|
||||||
from party.models import Party
|
from party.models import Party
|
||||||
|
|
||||||
|
|
||||||
|
@require_GET
|
||||||
@login_required
|
@login_required
|
||||||
def parties_list(request):
|
def parties_list(request):
|
||||||
context = {
|
context = {
|
||||||
|
@ -17,6 +19,7 @@ def parties_list(request):
|
||||||
return render(request, "party/parties_list.html", context)
|
return render(request, "party/parties_list.html", context)
|
||||||
|
|
||||||
|
|
||||||
|
@require_http_methods(["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def party_create(request):
|
def party_create(request):
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
|
@ -33,6 +36,7 @@ def party_create(request):
|
||||||
return render(request, "party/party_form.html", context)
|
return render(request, "party/party_form.html", context)
|
||||||
|
|
||||||
|
|
||||||
|
@require_GET
|
||||||
@login_required
|
@login_required
|
||||||
def party_details(request, pk):
|
def party_details(request, pk):
|
||||||
party = get_object_or_404(Party.objects.related_to(request.user), pk=pk)
|
party = get_object_or_404(Party.objects.related_to(request.user), pk=pk)
|
||||||
|
@ -43,6 +47,7 @@ def party_details(request, pk):
|
||||||
return render(request, "party/party_details.html", context)
|
return render(request, "party/party_details.html", context)
|
||||||
|
|
||||||
|
|
||||||
|
@require_http_methods(["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def party_delete(request, pk):
|
def party_delete(request, pk):
|
||||||
party = get_object_or_404(Party.objects.managed_by(request.user), pk=pk)
|
party = get_object_or_404(Party.objects.managed_by(request.user), pk=pk)
|
||||||
|
@ -55,6 +60,7 @@ def party_delete(request, pk):
|
||||||
return render(request, "party/party_delete.html", context)
|
return render(request, "party/party_delete.html", context)
|
||||||
|
|
||||||
|
|
||||||
|
@require_http_methods(["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def party_reset_stats(request, pk):
|
def party_reset_stats(request, pk):
|
||||||
party = get_object_or_404(Party.objects.managed_by(request.user), pk=pk)
|
party = get_object_or_404(Party.objects.managed_by(request.user), pk=pk)
|
||||||
|
@ -68,6 +74,7 @@ def party_reset_stats(request, pk):
|
||||||
return render(request, "party/party_reset_stats.html", context)
|
return render(request, "party/party_reset_stats.html", context)
|
||||||
|
|
||||||
|
|
||||||
|
@require_http_methods(["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def party_add_effect(request, pk):
|
def party_add_effect(request, pk):
|
||||||
party = get_object_or_404(Party.objects.played_or_mastered_by(request.user), pk=pk)
|
party = get_object_or_404(Party.objects.played_or_mastered_by(request.user), pk=pk)
|
||||||
|
@ -86,6 +93,23 @@ def party_add_effect(request, pk):
|
||||||
return render(request, "party/snippets/add_effect_form.html", context)
|
return render(request, "party/snippets/add_effect_form.html", context)
|
||||||
|
|
||||||
|
|
||||||
|
@require_GET
|
||||||
|
@login_required
|
||||||
|
def party_increase_rounds(request, pk):
|
||||||
|
party = get_object_or_404(Party.objects.managed_by(request.user), pk=pk)
|
||||||
|
party.effects.increase_rounds()
|
||||||
|
return render(request, "party/snippets/effects.html", {"party": party})
|
||||||
|
|
||||||
|
|
||||||
|
@require_GET
|
||||||
|
@login_required
|
||||||
|
def party_decrease_rounds(request, pk):
|
||||||
|
party = get_object_or_404(Party.objects.managed_by(request.user), pk=pk)
|
||||||
|
party.effects.decrease_rounds()
|
||||||
|
return render(request, "party/snippets/effects.html", {"party": party})
|
||||||
|
|
||||||
|
|
||||||
|
@require_http_methods(["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def party_change(request, pk):
|
def party_change(request, pk):
|
||||||
party = get_object_or_404(Party.objects.managed_by(request.user), pk=pk)
|
party = get_object_or_404(Party.objects.managed_by(request.user), pk=pk)
|
||||||
|
@ -102,6 +126,7 @@ def party_change(request, pk):
|
||||||
return render(request, "party/party_form.html", context)
|
return render(request, "party/party_form.html", context)
|
||||||
|
|
||||||
|
|
||||||
|
@require_http_methods(["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def party_leave(request, pk, character_pk):
|
def party_leave(request, pk, character_pk):
|
||||||
party = get_object_or_404(Party.objects.played_by(request.user).distinct(), pk=pk)
|
party = get_object_or_404(Party.objects.played_by(request.user).distinct(), pk=pk)
|
||||||
|
@ -116,6 +141,7 @@ def party_leave(request, pk, character_pk):
|
||||||
return render(request, "party/party_leave.html", context)
|
return render(request, "party/party_leave.html", context)
|
||||||
|
|
||||||
|
|
||||||
|
@require_GET
|
||||||
@login_required
|
@login_required
|
||||||
def party_join(request, pk, character_pk):
|
def party_join(request, pk, character_pk):
|
||||||
party = get_object_or_404(Party.objects.invited_to(request.user).distinct(), pk=pk)
|
party = get_object_or_404(Party.objects.invited_to(request.user).distinct(), pk=pk)
|
||||||
|
@ -128,6 +154,7 @@ def party_join(request, pk, character_pk):
|
||||||
return redirect("party:list")
|
return redirect("party:list")
|
||||||
|
|
||||||
|
|
||||||
|
@require_GET
|
||||||
@login_required
|
@login_required
|
||||||
def party_refuse(request, pk, character_pk):
|
def party_refuse(request, pk, character_pk):
|
||||||
party = get_object_or_404(Party.objects.invited_to(request.user).distinct(), pk=pk)
|
party = get_object_or_404(Party.objects.invited_to(request.user).distinct(), pk=pk)
|
||||||
|
|
Loading…
Reference in a new issue