Skip to content
Merged
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
20 changes: 19 additions & 1 deletion presente/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _
from taggit.models import Tag
from .models import Activity
from .models import Activity, Network

User = get_user_model()

Expand Down Expand Up @@ -172,3 +172,21 @@ def clean_columns(self):
# Default columns if none selected
return ["number", "name", "matricula", "checked_in_at"]
return columns


class NetworkForm(forms.ModelForm):
class Meta:
model = Network
fields = ["name", "description", "ip_addresses", "is_active"]
widgets = {
"name": forms.TextInput(attrs={"class": "form-control"}),
"description": forms.Textarea(attrs={"class": "form-control", "rows": 3}),
"ip_addresses": forms.Textarea(
attrs={
"class": "form-control font-monospace",
"rows": 10,
"placeholder": "200.137.2.62\n192.168.1.0/24\n10.0.0.1",
}
),
"is_active": forms.CheckboxInput(attrs={"class": "form-check-input"}),
}
10 changes: 10 additions & 0 deletions presente/menus.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,13 @@
check=lambda r: r.user.is_superuser,
),
)

Menu.add_item(
"presente",
MenuItem(
"Redes",
reverse("presente:network_list"),
icon="bi bi-hdd-network",
check=lambda r: r.user.is_superuser,
),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 5.2.7 on 2025-12-02 05:39

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('presente', '0014_alter_activity_is_enabled'),
]

operations = [
migrations.AddField(
model_name='activity',
name='created_at',
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Criado em'),
),
migrations.AddField(
model_name='activity',
name='modified_at',
field=models.DateTimeField(auto_now=True, null=True, verbose_name='Modificado em'),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Generated by Django 5.2.7 on 2025-12-03 16:12

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('presente', '0015_activity_created_at_activity_modified_at'),
]

operations = [
migrations.AlterField(
model_name='activity',
name='created_at',
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Criação'),
),
migrations.AlterField(
model_name='activity',
name='end_time',
field=models.DateTimeField(verbose_name='Término'),
),
migrations.AlterField(
model_name='activity',
name='modified_at',
field=models.DateTimeField(auto_now=True, null=True, verbose_name='Modificação'),
),
migrations.AlterField(
model_name='activity',
name='start_time',
field=models.DateTimeField(verbose_name='Início'),
),
]
10 changes: 8 additions & 2 deletions presente/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ class Activity(models.Model):
),
blank=True,
)
start_time = models.DateTimeField(_("Data/hora de início"))
end_time = models.DateTimeField(_("Data/hora de término"))
start_time = models.DateTimeField(_("Início"))
end_time = models.DateTimeField(_("Término"))
is_enabled = models.BooleanField(
default=True,
verbose_name=_("Habilitar?"),
Expand All @@ -80,6 +80,12 @@ class Activity(models.Model):
blank=True,
help_text=_("Selecione as redes que podem acessar esta atividade"),
)
created_at = models.DateTimeField(
_("Criação"), auto_now_add=True, null=True, blank=True
)
modified_at = models.DateTimeField(
_("Modificação"), auto_now=True, null=True, blank=True
)

def __str__(self):
return self.title
Expand Down
9 changes: 8 additions & 1 deletion presente/tables.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import django_tables2
from django.utils.translation import gettext_lazy as _
from django.utils.safestring import mark_safe
from .models import Activity, Attendance
from .models import Activity, Attendance, Network


class CoreTable(django_tables2.Table):
Expand Down Expand Up @@ -135,3 +135,10 @@ class Meta:
"checked_in_at",
)
order_by = "-checked_in_at"


class NetworkTable(CoreTable):
class Meta:
model = Network
fields = ("name", "description", "is_active")
attrs = {"class": "table table-striped"}
14 changes: 14 additions & 0 deletions presente/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@
views.AttendanceDeleteView.as_view(),
name="attendance_delete",
),
# Network CRUD URLs
path("network/", views.NetworkListView.as_view(), name="network_list"),
path("network/add", views.NetworkCreateView.as_view(), name="network_add"),
path("network/<int:pk>/", views.NetworkDetailView.as_view(), name="network_view"),
path(
"network/<int:pk>/update/",
views.NetworkUpdateView.as_view(),
name="network_change",
),
path(
"network/<int:pk>/delete/",
views.NetworkDeleteView.as_view(),
name="network_delete",
),
# User attendances
path("my-attendances/", views.MyAttendancesView.as_view(), name="my_attendances"),
# Public attendance URLs
Expand Down
51 changes: 47 additions & 4 deletions presente/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from django_filters.views import FilterView
from core.mixins import PageTitleMixin, SuperuserRequiredMixin
from core.views import (
CoreListView,
CoreCreateView,
CoreDetailView,
CoreUpdateView,
Expand All @@ -19,9 +20,14 @@
import qrcode.image.svg
from io import BytesIO
import base64
from .models import Activity, Attendance
from .tables import ActivityTable, AttendanceTable, ActivityAttendanceTable
from .forms import ActivityForm, AttendancePrintConfigForm
from .models import Activity, Attendance, Network
from .tables import (
ActivityTable,
AttendanceTable,
ActivityAttendanceTable,
NetworkTable,
)
from .forms import ActivityForm, AttendancePrintConfigForm, NetworkForm
from .filters import ActivityFilter, AttendanceFilter, ActivityAttendanceFilter
from .mixins import ActivityOwnerMixin
from .utils import (
Expand Down Expand Up @@ -66,7 +72,9 @@ class ActivityListView(CoreFilterView):
permission_required = []

def get_queryset(self):
return Activity.objects.filter(owners=self.request.user)
return Activity.objects.filter(owners=self.request.user).order_by(
"-modified_at", "-start_time"
)


class AdminActivitiesView(SuperuserRequiredMixin, CoreFilterView):
Expand All @@ -75,6 +83,9 @@ class AdminActivitiesView(SuperuserRequiredMixin, CoreFilterView):
table_class = ActivityTable
filterset_class = ActivityFilter

def get_queryset(self):
return Activity.objects.all().order_by("-modified_at", "-start_time")


class ActivityCreateView(CoreCreateView):
model = Activity
Expand Down Expand Up @@ -115,6 +126,7 @@ def get_fields(self):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["attendances"] = self.object.attendances.select_related("user").all()
context["attendance_count"] = self.object.attendances.count()
context["encoded_id"] = encode_activity_id(self.object.id)
return context

Expand Down Expand Up @@ -447,3 +459,34 @@ def get_context_data(self, **kwargs):
context["generated_at"] = timezone.now()

return context


# Network CRUD Views


class NetworkListView(SuperuserRequiredMixin, CoreListView):
page_title = _("Redes")
model = Network
table_class = NetworkTable


class NetworkCreateView(SuperuserRequiredMixin, CoreCreateView):
model = Network
page_title = _("Redes")
form_class = NetworkForm


class NetworkDetailView(SuperuserRequiredMixin, CoreDetailView):
model = Network
page_title = _("Redes")


class NetworkUpdateView(SuperuserRequiredMixin, CoreUpdateView):
model = Network
page_title = _("Redes")
form_class = NetworkForm


class NetworkDeleteView(SuperuserRequiredMixin, CoreDeleteView):
model = Network
page_title = _("Redes")
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ identify==2.6.15
idna==3.10
nodeenv==1.9.1
oauthlib==3.3.1
pillow==12.0.0
platformdirs==4.4.0
pre_commit==4.3.0
pycparser==2.23
PyJWT==2.10.1
python-dotenv==1.1.1
PyYAML==6.0.3
qrcode==8.2
requests==2.32.5
ruff==0.13.3
sqlparse==0.5.3
Expand Down
2 changes: 2 additions & 0 deletions static/js/qrcode.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use strict";

// Helper function to format countdown time
function formatCountdown(totalSeconds) {
const days = Math.floor(totalSeconds / 86400);
Expand Down
1 change: 1 addition & 0 deletions templates/presente/activity_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
{% block card_footer_actions %}
<a href="{% url 'presente:activity_attendances' object.pk %}" class="btn btn-info me-2">
<i class="bi bi-people"></i> Ver Presenças
<span class="badge bg-success text-white ms-1">{{ attendance_count }}</span>
</a>
{{ block.super }}
{% endblock %}
Expand Down