Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Team attendance register #84

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
python: [3.9, "3.10", "3.11"]
python: ["3.10", "3.11"]
steps:
- uses: actions/checkout@v4

Expand Down
4 changes: 2 additions & 2 deletions helpdesk/helpdesk/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
BASE_DIR = Path(__file__).resolve().parent.parent

# Validate Python version
if parse_version(platform.python_version()) < parse_version("3.9.0"): # pragma: nocover
if parse_version(platform.python_version()) < parse_version("3.10.0"): # pragma: nocover
raise RuntimeError(
f"Helpdesk requires Python 3.9 or higher (current: Python {platform.python_version()})",
f"Helpdesk requires Python 3.10 or higher (current: Python {platform.python_version()})",
)

#
Expand Down
11 changes: 11 additions & 0 deletions helpdesk/teams/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django import forms

from teams.models import Team, TeamAttendanceEvent


class TeamAttendanceLogForm(forms.ModelForm):
team = forms.ModelChoiceField(queryset=Team.objects.all(), widget=forms.HiddenInput())

class Meta:
model = TeamAttendanceEvent
fields = ("type", "comment", "team")
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 4.2.11 on 2024-12-24 18:40

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("teams", "0004_add_team_comment"),
]

operations = [
migrations.AlterModelOptions(
name="team",
options={"ordering": ["tla"]},
),
migrations.CreateModel(
name="TeamAttendanceEvent",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
(
"type",
models.TextField(
choices=[("AR", "Arrived"), ("LE", "Left"), ("DE", "Delayed"), ("DO", "Dropped Out")],
max_length=2,
),
),
("comment", models.TextField()),
("created_at", models.DateTimeField(auto_now_add=True)),
(
"team",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="team_attendance_events",
related_query_name="team_attendance_events",
to="teams.team",
),
),
("user", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
],
),
]
29 changes: 29 additions & 0 deletions helpdesk/teams/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,32 @@ class Meta:

def __str__(self) -> str:
return f"Comment on {self.team.name} at {self.created_at} by {self.author}"


class TeamAttendanceEventType(models.TextChoices):
ARRIVED = "ARRIVED", "Arrived"
LEFT = "LEFT", "Left"
DELAYED = "DELAYED", "Delayed"
DROPPED_OUT = "DROPPED_OUT", "Dropped Out"


class TeamAttendanceEvent(models.Model):
team = models.ForeignKey(
Team,
on_delete=models.CASCADE,
related_name="team_attendance_events",
related_query_name="team_attendance_events",
)
user = models.ForeignKey(
"accounts.User",
on_delete=models.PROTECT,
)
type = models.TextField(
max_length=11,
choices=TeamAttendanceEventType.choices,
)
comment = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)

def __str__(self) -> str:
return f"Attendance Event: {self.team.name} {self.type} at {self.created_at}"
22 changes: 21 additions & 1 deletion helpdesk/teams/tables.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import django_tables2 as tables

from .models import Team
from .models import Team, TeamAttendanceEventType


class TeamTable(tables.Table):
Expand All @@ -13,3 +13,23 @@ class Meta:
model = Team
exclude = ("id", "pit_location")
order_by = "tla"


class TeamAttendanceTable(tables.Table):
name = tables.LinkColumn("teams:team_detail", args=[tables.A("tla")])
latest_event__0__type = tables.Column("Latest Event")
latest_event__0__comment = tables.Column("Comment")
latest_event__0__created_at = tables.DateTimeColumn(verbose_name="Time")
user = tables.TemplateColumn(
verbose_name="Logged by",
template_code='{{record.latest_event.0.user|default:"—"}}',
)
actions = tables.LinkColumn("teams:team_log_attendance_form", args=[tables.A("tla")], text="Log")

def render_latest_event__0__type(self, value: str) -> str | None:
lookups = dict(TeamAttendanceEventType.choices)
return lookups.get(value)

class Meta:
model = Team
exclude = ["id", "tla", "is_rookie", "pit_location"]
4 changes: 4 additions & 0 deletions helpdesk/teams/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from django.urls import path

from .views import (
TeamAttendanceFormView,
TeamAttendanceView,
TeamDetailAboutView,
TeamDetailCommentsView,
TeamDetailTicketsView,
Expand All @@ -14,6 +16,8 @@

urlpatterns = [
path("", TeamListView.as_view(), name="team_list"),
path("attendance", TeamAttendanceView.as_view(), name="team_list_attendance"),
path("attendance/<slug:slug>", TeamAttendanceFormView.as_view(), name="team_log_attendance_form"),
path("<slug:slug>/", TicketDetailRedirectView.as_view(), name="team_detail"),
path("<slug:slug>/about", TeamDetailAboutView.as_view(), name="team_detail_about"),
path("<slug:slug>/comments", TeamDetailCommentsView.as_view(), name="team_detail_comments"),
Expand Down
48 changes: 43 additions & 5 deletions helpdesk/teams/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,27 @@
from typing import Any

from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import CharField, F, QuerySet, Value
from django.db.models import CharField, F, Prefetch, QuerySet, Value
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy
from django.views.generic import DetailView, RedirectView
from django.views.generic import CreateView, DetailView, ListView, RedirectView
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.edit import FormMixin, ProcessFormView
from django_filters.views import FilterView
from django_tables2 import SingleTableMixin

from helpdesk.forms import CommentSubmitForm
from helpdesk.utils import is_filterset_filtered
from helpdesk.utils import get_object_or_none, is_filterset_filtered
from tickets.filters import TicketFilter
from tickets.models import Ticket, TicketEvent
from tickets.tables import TicketTable

from .filters import TeamFilterset
from .models import Team, TeamComment
from .forms import TeamAttendanceLogForm
from .models import Team, TeamAttendanceEvent, TeamComment
from .srcomp import srcomp
from .tables import TeamTable
from .tables import TeamAttendanceTable, TeamTable


class TicketDetailRedirectView(RedirectView):
Expand Down Expand Up @@ -172,3 +174,39 @@ def get_entries(self) -> QuerySet[Any]:

def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
return super().get_context_data(entries=self.get_entries(), **kwargs)


class TeamAttendanceView(LoginRequiredMixin, SingleTableMixin, ListView):
model = Team
table_class = TeamAttendanceTable

def get_queryset(self) -> QuerySet[Any]:
return Team.objects.all().prefetch_related(
Prefetch(
"team_attendance_events",
TeamAttendanceEvent.objects.order_by("-created_at")[:1],
to_attr="latest_event",
)
)


class TeamAttendanceFormView(LoginRequiredMixin, CreateView):
model = TeamAttendanceEvent
form_class = TeamAttendanceLogForm
slug_field = "tla"

def get_success_url(self) -> str:
return reverse_lazy("teams:team_list_attendance")

def get_initial(self):
return {"team": get_object_or_404(Team, tla=self.kwargs["slug"])}

def get_context_data(self, **kwargs):
context_data = super().get_context_data(**kwargs)
context_data["team"] = self.kwargs["slug"]
return context_data

def form_valid(self, form: TeamAttendanceLogForm) -> HttpResponse:
form.instance.user = self.request.user
return super().form_valid(form)

16 changes: 13 additions & 3 deletions helpdesk/templates/inc/nav/nav.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,19 @@
<a class="navbar-item" href="{% url 'tickets:queue_default' %}">
Queues
</a>
<a class="navbar-item" href="{% url 'teams:team_list' %}">
Teams
</a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">
Teams
</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="{% url 'teams:team_list' %}">
All Teams
</a>
<a class="navbar-item" href="{% url 'teams:team_list_attendance' %}">
Attendance
</a>
</div>
</div>
<a class="navbar-item" href="{% url 'tickets:ticket_all' %}">
All Tickets
</a>
Expand Down
28 changes: 14 additions & 14 deletions helpdesk/templates/inc/nav/team-tabs.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@
<span>Tickets</span>
</a>
</li>
<li {% if active == "comments" %}class="is-active"{% endif %}></li>
<a href="{% url 'teams:team_detail_comments' team.tla %}">
<span class="icon is-small"><i class="fas fa-comment" aria-hidden="true"></i></span>
<span>Comments</span>
</a>
</li>
<li {% if active == "timeline" %}class="is-active"{% endif %}></li>
<a href="{% url 'teams:team_detail_timeline' team.tla %}">
<span class="icon is-small"><i class="fas fa-timeline" aria-hidden="true"></i></span>
<span>Timeline</span>
</a>
</li>
</ul>
</div>
<li {% if active == "comments" %}class="is-active"{% endif %}>
<a href="{% url 'teams:team_detail_comments' team.tla %}">
<span class="icon is-small"><i class="fas fa-comment" aria-hidden="true"></i></span>
<span>Comments</span>
</a>
</li>
<li {% if active == "timeline" %}class="is-active"{% endif %}>
<a href="{% url 'teams:team_detail_timeline' team.tla %}">
<span class="icon is-small"><i class="fas fa-timeline" aria-hidden="true"></i></span>
<span>Timeline</span>
</a>
</li>
</ul>
</div>
20 changes: 20 additions & 0 deletions helpdesk/templates/teams/team_list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{% extends "layouts/base_app.html" %}
{% load render_table from django_tables2 %}
{% load crispy_forms_tags %}

{% block page_title %}Team Attendance{% endblock %}
{% block title %}Team Attendance{% endblock %}

{% block page_buttons %}
{# <input class="input" type="date">#}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Is this meant to be commented out?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a WIP thing. I wanted to add the option to filter by day. Not sure if I should keep it. We'd also want to make sure that teams which have dropped out ignore the filter.

{% endblock %}

{% block content %}
<div class="container">
<div class="columns">
<div class="column">
{% render_table table %}
</div>
</div>
</div>
{% endblock %}
17 changes: 17 additions & 0 deletions helpdesk/templates/teams/teamattendanceevent_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{% extends "layouts/base_app.html" %}
{% load crispy_forms_tags %}

{% block page_title %}
Log attendance for {{ team }}
{% endblock %}
{% block title %}
Log attendance for {{ team }}
{% endblock %}

{% block content %}
<form class="block" method="post">
{% csrf_token %}
{{form|crispy}}
<input class="button is-primary" type="submit" value="Save">
</form>
{% endblock %}
2 changes: 1 addition & 1 deletion helpdesk/tickets/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class TicketTable(tables.Table):
status = tables.Column()
assignee_id = tables.TemplateColumn(
verbose_name="Assignee",
template_code='{{record.assignee|default:"-"}}',
template_code='{{record.assignee|default:""}}',
)
actions = tables.LinkColumn("tickets:ticket_detail", args=[tables.A("id")], text="View")

Expand Down