timetracker/games/views/session.py

296 lines
11 KiB
Python
Raw Normal View History

2024-08-11 15:22:58 +00:00
from typing import Any
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
2024-11-09 22:52:09 +00:00
from django.db.models import Q
2024-08-11 15:22:58 +00:00
from django.http import HttpRequest, HttpResponse
2024-08-12 19:42:34 +00:00
from django.shortcuts import get_object_or_404, redirect, render
2024-08-11 15:22:58 +00:00
from django.template.loader import render_to_string
from django.urls import reverse
2024-08-12 19:42:34 +00:00
from django.utils import timezone
2024-08-11 15:22:58 +00:00
2024-11-09 21:34:01 +00:00
from common.components import (
A,
Button,
Div,
Form,
Icon,
LinkedNameWithPlatformIcon,
Popover,
)
from common.time import (
dateformat,
durationformat,
durationformat_manual,
format_duration,
local_strftime,
timeformat,
)
from common.utils import truncate
from games.forms import SessionForm
from games.models import Purchase, Session
from games.views.general import use_custom_redirect
2024-08-11 15:22:58 +00:00
@login_required
2024-11-09 21:34:01 +00:00
def list_sessions(request: HttpRequest, search_string: str = "") -> HttpResponse:
2024-08-11 15:22:58 +00:00
context: dict[Any, Any] = {}
page_number = request.GET.get("page", 1)
limit = request.GET.get("limit", 10)
2024-08-11 19:39:14 +00:00
sessions = Session.objects.order_by("-timestamp_start")
2024-11-09 21:34:01 +00:00
search_string = request.GET.get("search_string", search_string)
if search_string != "":
2024-11-09 22:52:09 +00:00
sessions = sessions.filter(
Q(purchase__edition__name__icontains=search_string)
| Q(purchase__edition__game__name__icontains=search_string)
| Q(purchase__platform__name__icontains=search_string)
| Q(device__name__icontains=search_string)
| Q(device__type__icontains=search_string)
)
try:
last_session = sessions.latest()
except Session.DoesNotExist:
last_session = None
2024-08-11 15:22:58 +00:00
page_obj = None
if int(limit) != 0:
paginator = Paginator(sessions, limit)
page_obj = paginator.get_page(page_number)
sessions = page_obj.object_list
context = {
"title": "Manage sessions",
"page_obj": page_obj or None,
"elided_page_range": (
page_obj.paginator.get_elided_page_range(
page_number, on_each_side=1, on_ends=1
)
if page_obj
else None
),
"data": {
2024-09-08 19:03:37 +00:00
"header_action": Div(
children=[
2024-11-09 21:34:01 +00:00
Form(
children=[
render_to_string(
"cotton/search_field.html",
{
"id": "search_string",
"search_string": search_string,
},
2024-11-09 21:34:01 +00:00
)
]
2024-09-08 19:03:37 +00:00
),
2024-11-09 21:34:01 +00:00
Div(
children=[
A(
url="add_session",
children=Button(
2024-09-08 19:03:37 +00:00
icon=True,
size="xs",
2024-11-09 21:34:01 +00:00
children=[Icon("play"), "LOG"],
),
),
A(
url=reverse(
"list_sessions_start_session_from_session",
args=[last_session.pk],
),
children=Popover(
popover_content=last_session.purchase.edition.name,
2024-09-08 19:03:37 +00:00
children=[
2024-11-09 21:34:01 +00:00
Button(
icon=True,
color="gray",
size="xs",
children=[
Icon("play"),
truncate(
f"{last_session.purchase.edition.name}"
),
],
)
2024-09-08 19:03:37 +00:00
],
2024-11-09 21:34:01 +00:00
),
)
if last_session
else "",
2024-11-09 21:34:01 +00:00
]
2024-09-08 19:03:37 +00:00
),
],
2024-11-09 21:34:01 +00:00
attributes=[("class", "flex justify-between")],
2024-09-08 19:03:37 +00:00
),
2024-08-11 15:22:58 +00:00
"columns": [
"Name",
"Date",
"Duration",
"Device",
"Created",
"Actions",
],
"rows": [
[
LinkedNameWithPlatformIcon(
name=session.purchase.edition.name,
game_id=session.purchase.edition.game.pk,
platform=session.purchase.platform,
),
f"{local_strftime(session.timestamp_start)}{f"{local_strftime(session.timestamp_end, timeformat)}" if session.timestamp_end else ""}",
2024-08-11 15:22:58 +00:00
(
format_duration(session.duration_calculated, durationformat)
2024-08-11 15:22:58 +00:00
if session.duration_calculated
2024-09-07 21:35:59 +00:00
else f"{format_duration(session.duration_manual, durationformat_manual)}*"
2024-08-11 15:22:58 +00:00
),
session.device,
session.created_at.strftime(dateformat),
render_to_string(
2024-09-08 19:03:37 +00:00
"cotton/button_group.html",
2024-08-11 15:22:58 +00:00
{
"buttons": [
2024-09-08 19:03:37 +00:00
{
"href": reverse(
"list_sessions_end_session", args=[session.pk]
),
"slot": Icon("end"),
"title": "Finish session now",
"color": "green",
"hover": "green",
}
if session.timestamp_end is None
# this only works without leaving an empty
# a element and wrong rounding of button edges
# because we check if button.href is not None
# in the button group component
else {},
2024-08-11 15:22:58 +00:00
{
"href": reverse("edit_session", args=[session.pk]),
2024-09-08 19:03:37 +00:00
"slot": Icon("edit"),
"title": "Edit",
# "color": "gray",
"hover": "green",
2024-08-11 15:22:58 +00:00
},
{
"href": reverse(
"delete_session", args=[session.pk]
),
2024-09-08 19:03:37 +00:00
"slot": Icon("delete"),
"title": "Delete",
2024-08-11 15:22:58 +00:00
"color": "red",
2024-09-08 19:03:37 +00:00
"hover": "red",
2024-08-11 15:22:58 +00:00
},
]
},
),
]
for session in sessions
],
},
}
return render(request, "list_purchases.html", context)
2024-08-12 19:42:34 +00:00
2024-11-09 21:34:01 +00:00
@login_required
def search_sessions(request: HttpRequest) -> HttpResponse:
return list_sessions(request, search_string=request.GET.get("search_string", ""))
2024-08-12 19:42:34 +00:00
@login_required
def add_session(request: HttpRequest, purchase_id: int = 0) -> HttpResponse:
context = {}
initial: dict[str, Any] = {"timestamp_start": timezone.now()}
last = Session.objects.last()
if last != None:
initial["purchase"] = last.purchase
if request.method == "POST":
form = SessionForm(request.POST or None, initial=initial)
if form.is_valid():
form.save()
return redirect("list_sessions")
else:
if purchase_id:
purchase = Purchase.objects.get(id=purchase_id)
form = SessionForm(
initial={
**initial,
"purchase": purchase,
}
)
else:
form = SessionForm(initial=initial)
context["title"] = "Add New Session"
2024-10-16 15:49:55 +00:00
context["script_name"] = "add_session.js"
2024-08-12 19:42:34 +00:00
context["form"] = form
return render(request, "add_session.html", context)
@login_required
@use_custom_redirect
def edit_session(request: HttpRequest, session_id: int) -> HttpResponse:
context = {}
session = get_object_or_404(Session, id=session_id)
form = SessionForm(request.POST or None, instance=session)
if form.is_valid():
form.save()
return redirect("list_sessions")
context["title"] = "Edit Session"
context["form"] = form
return render(request, "add_session.html", context)
def clone_session_by_id(session_id: int) -> Session:
session = get_object_or_404(Session, id=session_id)
clone = session
clone.pk = None
clone.timestamp_start = timezone.now()
clone.timestamp_end = None
clone.note = ""
clone.save()
return clone
@login_required
def new_session_from_existing_session(
request: HttpRequest, session_id: int, template: str = ""
) -> HttpResponse:
session = clone_session_by_id(session_id)
if request.htmx:
context = {
"session": session,
"session_count": int(request.GET.get("session_count", 0)) + 1,
}
return render(request, template, context)
return redirect("list_sessions")
@login_required
def end_session(
request: HttpRequest, session_id: int, template: str = ""
) -> HttpResponse:
session = get_object_or_404(Session, id=session_id)
session.timestamp_end = timezone.now()
session.save()
if request.htmx:
context = {
"session": session,
"session_count": request.GET.get("session_count", 0),
}
return render(request, template, context)
return redirect("list_sessions")
@login_required
def delete_session(request: HttpRequest, session_id: int = 0) -> HttpResponse:
session = get_object_or_404(Session, id=session_id)
session.delete()
return redirect("list_sessions")
2024-08-12 19:42:34 +00:00
@login_required
def delete_session(request: HttpRequest, session_id: int = 0) -> HttpResponse:
session = get_object_or_404(Session, id=session_id)
session.delete()
return redirect("list_sessions")