diff --git a/accounts/models.py b/accounts/models.py
index a12186b..6330c67 100644
--- a/accounts/models.py
+++ b/accounts/models.py
@@ -29,6 +29,7 @@ class Student(models.Model):
student_number = models.IntegerField()
department = models.ForeignKey(Department, on_delete=models.CASCADE)
is_clocked_in = models.BooleanField(default=False)
+ current_period_id = models.IntegerField(blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
diff --git a/attendance/forms.py b/attendance/forms.py
index 0fd6005..5a3e492 100644
--- a/attendance/forms.py
+++ b/attendance/forms.py
@@ -7,3 +7,20 @@ class AttendanceUpdateForm(forms.Form):
max_length=100,
widget=forms.TextInput(attrs={'autofocus': True})
)
+
+class PeriodForm(forms.ModelForm):
+ class Meta:
+ model = Period
+ fields = ['student', 'station_number', 'clocked_in', 'clocked_out']
+ widgets = {
+ 'clocked_in': forms.DateTimeInput(format = '%Y-%m-%d %H:%M', attrs = {
+ 'placeholder': '2006-10-25 14:30'
+ }),
+ 'clocked_out': forms.DateTimeInput(format = '%Y-%m-%d %H:%M', attrs = {
+ 'placeholder': '2006-10-25 14:30'
+ }),
+ }
+ labels = {
+ 'clocked_in': 'Clocked in (example 2006-10-25 14:30):',
+ 'clocked_out': 'Clocked out (example 2006-10-25 14:30):',
+ }
diff --git a/attendance/models.py b/attendance/models.py
index d17d700..34f5e27 100644
--- a/attendance/models.py
+++ b/attendance/models.py
@@ -1,3 +1,4 @@
+from datetime import datetime
from django.db import models
from django.urls import reverse
from accounts.models import Student
@@ -20,7 +21,7 @@ class Code(models.Model):
class Period(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE)
- clocked_in = models.DateTimeField(auto_now_add=True)
+ clocked_in = models.DateTimeField()
clocked_out = models.DateTimeField(blank=True, null=True)
station_number = models.IntegerField()
duration = models.DurationField(blank=True, null=True)
@@ -38,3 +39,8 @@ class Period(models.Model):
def __str__(self):
return f'{self.clocked_in}: {self.student.user.first_name} {self.student.user.last_name}'
+
+ def save(self, *args, **kwargs):
+ if isinstance(self.clocked_out, datetime):
+ self.duration = self.clocked_out - self.clocked_in
+ super(Period, self).save(*args, **kwargs)
diff --git a/attendance/templates/attendance/attendance_overview_instructor.html b/attendance/templates/attendance/attendance_overview_instructor.html
index de5d202..1825ac8 100644
--- a/attendance/templates/attendance/attendance_overview_instructor.html
+++ b/attendance/templates/attendance/attendance_overview_instructor.html
@@ -7,6 +7,9 @@
Active sessions
+
+ + Add new session
+
diff --git a/attendance/templates/attendance/attendance_overview_student.html b/attendance/templates/attendance/attendance_overview_student.html
index 7033e47..134623d 100644
--- a/attendance/templates/attendance/attendance_overview_student.html
+++ b/attendance/templates/attendance/attendance_overview_student.html
@@ -1,13 +1,17 @@
{% endblock %}
diff --git a/attendance/templates/attendance/period_detail.html b/attendance/templates/attendance/period_detail.html
index 5d12cbb..c13619b 100644
--- a/attendance/templates/attendance/period_detail.html
+++ b/attendance/templates/attendance/period_detail.html
@@ -19,6 +19,8 @@
{{ period.clocked_in }}
Clocked out
{{ period.clocked_out }}
+ Duration
+ {{ period.duration }}
{% endblock %}
diff --git a/attendance/templates/attendance/period_form.html b/attendance/templates/attendance/period_form.html
index 4cc43c4..cfd202d 100644
--- a/attendance/templates/attendance/period_form.html
+++ b/attendance/templates/attendance/period_form.html
@@ -4,11 +4,12 @@
Generate Period
{% endblock %}
diff --git a/attendance/urls.py b/attendance/urls.py
index 3fd30f4..3f170ce 100644
--- a/attendance/urls.py
+++ b/attendance/urls.py
@@ -10,6 +10,7 @@ from . import views
urlpatterns = [
path('', views.AttendanceOverview.as_view(), name='attendance-overview'),
path('update/', views.AttendanceUpdateView.as_view(), name='attendance-update'),
+ path('periods/new/', views.PeriodCreateView.as_view(), name='period-create'),
path('periods//', include([
path('', views.PeriodDetailView.as_view(), name='period-detail'),
path('update/', views.PeriodUpdateView.as_view(), name='period-update'),
diff --git a/attendance/views.py b/attendance/views.py
index 6943278..f1848cd 100644
--- a/attendance/views.py
+++ b/attendance/views.py
@@ -12,7 +12,7 @@ from django.contrib import messages
from django.contrib.auth.models import User
from accounts.models import Instructor, Student
from .models import Code, Period
-from .forms import AttendanceUpdateForm
+from .forms import AttendanceUpdateForm, PeriodForm
# EXAMPLE PERMISSION MIXIN
# class MyView(PermissionRequiredMixin, View):
@@ -32,19 +32,18 @@ class AttendanceOverview(LoginRequiredMixin, TemplateView):
context['period_list'] = Period.objects.order_by('-clocked_in')
elif hasattr(self.request.user, 'student'):
# sum all duration fields for student
- total_duration = Period.objects.filter(
- student=self.request.user.student
+ periods_duration_sum = Period.objects.filter(
+ student = self.request.user.student
).filter(
clocked_in__year=timezone.now().year
).filter(
clocked_in__month=timezone.now().month
- ).order_by('-clocked_in'
).aggregate(total_duration=Sum('duration'))
- hours = ""
+ hours = 0
# Convert to hours floating point
- if hasattr(total_duration, 'total_duration'):
- hours = round((total_duration['total_duration'].total_seconds() / 3600), 2)
+ if periods_duration_sum['total_duration'] != None:
+ hours = round((periods_duration_sum['total_duration'].total_seconds() / 3600), 2)
context['period_list'] = Period.objects.filter(
student=self.request.user.student
@@ -54,6 +53,7 @@ class AttendanceOverview(LoginRequiredMixin, TemplateView):
clocked_in__month=timezone.now().month
).order_by('-clocked_in')
context['period_total'] = hours
+ context['current_period'] = Period.objects.get(pk=self.request.user.student.current_period_id)
return context
class AttendanceUpdateView(LoginRequiredMixin, FormView):
@@ -67,14 +67,14 @@ class AttendanceUpdateView(LoginRequiredMixin, FormView):
student = Student.objects.get(student_number=student_number)
if student.is_clocked_in:
student.is_clocked_in=False
- period = student.period_set.last()
+ period = student.period_set.get(pk=student.current_period_id)
period.clocked_out=timezone.now()
- period.duration=period.clocked_out-period.clocked_in
student.save()
period.save()
messages.add_message(self.request, messages.INFO, f'{student.user.first_name} {student.user.last_name} clocked out.')
else:
- student.period_set.create(student=student, station_number=station_number)
+ c_p = student.period_set.create(student=student, clocked_in=timezone.now(), station_number=station_number)
+ student.current_period_id = c_p.id
student.is_clocked_in=True
student.save()
messages.add_message(self.request, messages.INFO, f'{student.user.first_name} {student.user.last_name} clocked in.')
@@ -89,7 +89,7 @@ class AttendanceUpdateView(LoginRequiredMixin, FormView):
# PERIODS
class PeriodCreateView(LoginRequiredMixin, CreateView):
model = Period
- fields = ['student']
+ form_class = PeriodForm
template_name = 'attendance/period_form.html'
class PeriodDetailView(LoginRequiredMixin, DetailView):
@@ -98,9 +98,17 @@ class PeriodDetailView(LoginRequiredMixin, DetailView):
class PeriodUpdateView(LoginRequiredMixin, UpdateView):
model = Period
- fields = ['clocked_out']
+ form_class = PeriodForm
template_name = 'attendance/period_form.html'
+ # When editing a period, check if it matches the current period of the student and clock them out
+ def form_valid(self, form):
+ student = form.instance.student
+ if form.instance.id == student.current_period_id:
+ student.is_clocked_in = False
+ student.save()
+ return super().form_valid(form)
+
def get_success_url(self):
pk = self.kwargs["pk"]
return reverse('period-detail', kwargs={'pk': pk})
diff --git a/home/__init__.py b/home/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/home/admin.py b/home/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/home/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/home/apps.py b/home/apps.py
new file mode 100644
index 0000000..90dc713
--- /dev/null
+++ b/home/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class HomeConfig(AppConfig):
+ name = 'home'
diff --git a/home/migrations/__init__.py b/home/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/home/models.py b/home/models.py
new file mode 100644
index 0000000..71a8362
--- /dev/null
+++ b/home/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/home/templates/home/home.html b/home/templates/home/home.html
new file mode 100644
index 0000000..2d8144b
--- /dev/null
+++ b/home/templates/home/home.html
@@ -0,0 +1,6 @@
+{% extends 'application.html' %}
+{% load static %}
+
+{% block content %}
+Welcome home
+{% endblock %}
diff --git a/home/tests.py b/home/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/home/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/home/urls.py b/home/urls.py
new file mode 100644
index 0000000..d66c424
--- /dev/null
+++ b/home/urls.py
@@ -0,0 +1,12 @@
+from django.urls import include, path
+from . import views
+
+# list/ /users/
+# create/ /users/new/
+# detail/ /users/1/
+# update/ /users/1/update/ (update shift preferences)
+# delete/ /users/1/delete/
+
+urlpatterns = [
+ path('', views.HomeView.as_view(), name='home'),
+]
diff --git a/home/views.py b/home/views.py
new file mode 100644
index 0000000..5202dac
--- /dev/null
+++ b/home/views.py
@@ -0,0 +1,5 @@
+from django.shortcuts import render
+from django.views.generic.base import TemplateView
+
+class HomeView(TemplateView):
+ template_name = "home/home.html"
diff --git a/static/css/base.css b/static/css/base.css
index 5ce7dd8..8342344 100644
--- a/static/css/base.css
+++ b/static/css/base.css
@@ -6,10 +6,8 @@ accent 2 (orange) #9b6f45
accent 3 (blue) #242e34
*/
-@import url('https://fonts.googleapis.com/css2?family=Heebo:wght@400;700;900&display=swap');
-
html {
- font-size: 1.125em;
+ font-size: 100%;
}
body {
@@ -17,46 +15,36 @@ body {
margin: 0.25in auto;
background-color: #f7f7f7;
color: #323834;
- font-family: 'Heebo', sans-serif;
+ font-family: 'Lato', sans-serif;
font-weight: 400;
- line-height: 1.65;
+ line-height: 1.75;
}
-
-header {
- display: flex;
- align-items: baseline;
- justify-content: space-between;
-}
-
-/* Text Elements */
-
p {
- margin-bottom: 1.15rem;
+ margin-bottom: 1rem;
}
h1, h2, h3, h4, h5 {
- /*margin: 2.75rem 0 1.05rem;*/
- margin: 0 0 1.05rem;
- font-weight: 800;
- line-height: 1.15;
+ margin: 3rem 0 1.38rem;
+ font-family: 'Lato', sans-serif;
+ line-height: 1.3;
}
h1 {
margin-top: 0;
- font-size: 2.488em;
+ font-size: 2.488rem;
}
h2 {
- font-size: 2.074em;
+ font-size: 2.074rem;
}
h3 {
- font-size: 1.728em;
+ font-size: 1.728rem;
}
h4 {
- font-size: 1.44em;
+ font-size: 1.44rem;
}
h5 {
- font-size: 1.2em;
+ font-size: 1.2rem;
}
small {
- font-size: 0.833em;
+ font-size: 0.833rem;
}
a {
@@ -65,14 +53,23 @@ a {
white-space: nowrap;
}
-small {
- font-size: 0.8em;
-}
hr {
margin: 0;
border: 0.8px solid #bdc3c7;
}
+.navigation {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+}
+
+.header {
+ display: flex;
+ align-items: top;
+ justify-content: space-between;
+}
+
blockquote {
text-align: left;
padding: 0 15px;
@@ -109,6 +106,7 @@ label {
input[type=text],
input[type=email],
+input[type=number],
input[type=password],
select[multiple=multiple],
textarea,
@@ -219,4 +217,4 @@ th {
/* Messages */
-.messages > .info {color: green;}
+.info {color: green;}
diff --git a/templates/application.html b/templates/application.html
index 6edf910..6c4e9ea 100644
--- a/templates/application.html
+++ b/templates/application.html
@@ -9,11 +9,13 @@
{% block head %}
{% endblock %}
+
+
-
- BTech Time Tracker
+
+ BTech Time Tracker
{% if user.is_authenticated %}