瀏覽代碼

Adjusted layouts for better responsive design. Also started adding validation logic to timesheet form.

Adam Day 4 年之前
父節點
當前提交
fa6cb31a19
共有 6 個文件被更改,包括 97 次插入45 次删除
  1. 28 16
      app/forms.py
  2. 6 6
      app/templates/forms/timesheet_entry.html
  3. 1 1
      app/templates/layout.html
  4. 46 11
      app/templates/timesheet.html
  5. 15 10
      app/views.py
  6. 1 1
      static/app/css/app.css

+ 28 - 16
app/forms.py

@@ -1,11 +1,27 @@
 from django import forms
-from django.core.validators import RegexValidator, MaxLengthValidator
+from django.core.validators import RegexValidator, MaxLengthValidator, MinLengthValidator, ValidationError
 from . models import Project, Setting
 
 numeric = RegexValidator(r'^[0-9+]', 'Only numeric characters.')
-time_max_length = MaxLengthValidator(4, 'Length limit exceeds 4 characters')
-max_daily_hours_length = MaxLengthValidator(2, 'Only 2 place values allowed')
-session_timeout_length = MaxLengthValidator(4, 'Only 4 place values allowed')
+time_max_length = MaxLengthValidator(4, 'Length limit exceeds 4 characters.')
+max_daily_hours_length = MaxLengthValidator(2, 'Only 2 place values allowed.')
+session_timeout_length = MaxLengthValidator(4, 'Only 4 place values allowed.')
+min_pin_length = MinLengthValidator(4, 'Must be at least 4 characters long.')
+max_pin_length = MaxLengthValidator(4, 'May not be longer then 4 characters long.')
+
+
+def pin_blacklist(value):
+    blacklist = ['1234', '4321', '0000', '1111',
+                 '2222', '3333', '4444', '5555',
+                 '6666', '7777', '8888', '9999',
+                 '2345', '5432', '3456', '6543',
+                 '4567', '7654', '5678', '8765',
+                 '6789', '9876', '7890', '0987']
+    if value in blacklist:
+        raise ValidationError("Please provide a more complex PIN")
+    else:
+        return value
+
 
 hours = []
 try:
@@ -37,21 +53,17 @@ class LoginForm(forms.Form):
 class CreateUserForm(forms.Form):
     first_name = forms.CharField(strip=True, required=True)
     last_name = forms.CharField(strip=True, required=True)
-    pin = forms.CharField(strip=True, required=True, validators=[numeric], help_text="Numeric values only")
+    pin = forms.CharField(strip=True, required=True, validators=[numeric, min_pin_length, max_pin_length, pin_blacklist],
+                          help_text="4 character numeric PIN")
 
 
 class TimeEntryForm(forms.Form):
-    project = forms.ModelChoiceField(Project.objects.all(), required=False, widget=forms.Select(attrs={
-        'class': 'form-control form-control-lg'
-    }))
-
-    hours = forms.ChoiceField(required=True, choices=hours, widget=forms.Select(attrs={
-        'class': 'form-control form-control-lg',
-    }))
-
-    minutes = forms.ChoiceField(required=True, choices=minutes, widget=forms.Select(attrs={
-        'class': 'form-control form-control-lg',
-    }))
+    project = forms.ModelChoiceField(Project.objects.all(), required=False, label="Select a project if applicable (not required)",
+                                     widget=forms.Select(attrs={'class': 'form-control form-control-lg'}))
+    hours = forms.ChoiceField(required=True, choices=hours,
+                              widget=forms.Select(attrs={'class': 'form-control form-control-lg'}))
+    minutes = forms.ChoiceField(required=True, choices=minutes,
+                                widget=forms.Select(attrs={'class': 'form-control form-control-lg'}))
 
 
 class SettingsForm(forms.Form):

+ 6 - 6
app/templates/forms/timesheet_entry.html

@@ -2,16 +2,16 @@
 
 <form action="{% url 'timesheet' %}" method="post">
     <div class="row">
-        <div class="col-sm-12 col-md-12">
-            {{ form.project | as_crispy_field }}
-        </div>
-        <div class="col-sm-12 col-md-4">
+        <div class="col-sm-12 col-md-6">
             {{ form.hours | as_crispy_field }}
         </div>
-        <div class="col-sm-12 col-md-4">
+        <div class="col-sm-12 col-md-6">
             {{ form.minutes | as_crispy_field }}
         </div>
-        <div class="col-sm-12 col-md-4">
+        <div class="col-sm-12 col-md-6">
+            {{ form.project | as_crispy_field }}
+        </div>
+        <div class="col-sm-12 col-md-6">
             <label class="form-label">&nbsp;</label>
             <input type="submit" value="Submit" class="form-control form-control-lg btn btn-lg btn-dark">
         </div>

+ 1 - 1
app/templates/layout.html

@@ -16,7 +16,7 @@
     <div class="d-flex align-items-center min-vh-100">
         <div class="container-fluid">
             <div class="row justify-content-center">
-                <div class="col-12 text-center mt-5 mb-3">
+                <div class="col-12 text-center mt-2 mb-2">
                     <h1 class="display-3"><span class="oi" data-glyph="clock"></span> Time Sheet Station</h1>
                 </div>
             </div>

+ 46 - 11
app/templates/timesheet.html

@@ -23,6 +23,7 @@
             </div>
         </div>
     </div>
+    {% if entries %}
     <div class="row">
         <div class="col-12">
             <div class="card">
@@ -31,41 +32,75 @@
                         <div class="col-sm-6">
                             <h3>Total Time Worked</h3>
                         </div>
-                        <div class="col-sm-6">
+                        <div class="col-sm-3 text-center">
                             <h3>{{ total_time_worked }}</h3>
                         </div>
+                        <div class="col-sm-3 text-end">
+                            <a href="#!" class="btn btn-dark"><span class="oi" data-glyph="print"></span></a>
+                        </div>
                     </div>
-                    <div class="row">
-                        <div class="col-4">
+                    <div class="row mb-2">
+                        <div class="col-sm-4 col-md-3">
                             <b>Date</b>
                         </div>
-                        <div class="col-4">
-                            <b>Time Worked</b>
+                        <div class="col-sm-4 col-md-2">
+                            <b>Hours</b>
                         </div>
-                        <div class="col-4">
+                        <div class="d-sm-none d-md-block col-md-3">
                             <b>Project</b>
                         </div>
+                        <div class="col-md-4 text-end">
+
+                        </div>
                     </div>
+
                     {% for entry in entries %}
-                        <div class="row report-row p-3">
-                            <div class="col-sm-12 col-md-4">
+                        <div class="row report-row pb-3 pt-3">
+                            <div class="col-sm-12 col-md-3">
                                 {{ entry.date }}
                             </div>
-                            <div class="col-sm-6 col-md-4">
+                            <div class="col-sm-6 col-md-2">
                                 {{ entry.time_worked }}
                             </div>
-                            <div class="col-sm-6 col-md-4">
+                            <div class="col-md-3">
                                 {% if entry.project %}
                                     {{ entry.project.name }}
                                 {% else %}
                                     -
                                 {% endif %}
                             </div>
+                            <div class="col-sm-6 col-md-4 text-end">
+                                <a href="#!" class="btn btn-secondary"><span class="oi" data-glyph="pencil"></span></a>
+                                <a href="#!" data-bs-toggle="modal" data-bs-target="#entry-{{ entry.id }}" class="btn btn-danger"><span class="oi" data-glyph="trash"></span></a>
+                            </div>
+                            <div class="modal fade" id="entry-{{ entry.id }}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
+                              <div class="modal-dialog modal-dialog-centered">
+                                <div class="modal-content">
+                                  <div class="modal-header">
+                                    <h5 class="modal-title" id="exampleModalLabel">Removal Confirmation</h5>
+                                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+                                  </div>
+                                  <div class="modal-body">
+                                      <div class="row">
+                                          <div class="col-12 lead mb-3 text-center">
+                                              Remove {{ entry.time_worked }} hours worked on {{ entry.date }}.
+                                          </div>
+                                          <div class="col-sm-12 col-md-6">
+                                              <button type="button" class="btn btn-lg form-control btn-secondary" data-bs-dismiss="modal">No</button>
+                                          </div>
+                                          <div class="col-sm-12 col-md-6">
+                                              <button type="button" class="btn btn-lg form-control btn-dark">Yes</button>
+                                          </div>
+                                      </div>
+                                  </div>
+                                </div>
+                              </div>
+                            </div>
                         </div>
                     {% endfor %}
                 </div>
             </div>
         </div>
     </div>
-
+    {% endif %}
 {% endblock %}

+ 15 - 10
app/views.py

@@ -1,5 +1,6 @@
 from django.shortcuts import render, redirect
 from . forms import LoginForm, CreateUserForm, TimeEntryForm, SettingsForm
+from django.core.validators import ValidationError
 from . models import User, Setting, Entry
 from hashlib import sha256
 import datetime
@@ -133,18 +134,21 @@ def timesheet(request):
 
     if request.method == "POST":
         form = TimeEntryForm(request.POST)
+
         if form.is_valid():
             data = form.cleaned_data
-            print(data)
-            entry = Entry()
-            entry.user = user
-            entry.project = data['project']
-            entry.date = datetime.datetime.now().date()
-            entry.hours = data['hours']
-            entry.minutes = data['minutes']
-            entry.save()
-
-            form = TimeEntryForm()
+            if data['hours'] == '0' and data['minutes'] == '0':
+                form.add_error('hours', 'May not be 0 if minutes is 0')
+                form.add_error('minutes', 'May not be 0 if hours is 0')
+            else:
+                entry = Entry()
+                entry.user = user
+                entry.project = data['project']
+                entry.date = datetime.datetime.now().date()
+                entry.hours = data['hours']
+                entry.minutes = data['minutes']
+                entry.save()
+                form = TimeEntryForm()
 
     entries = Entry.objects.filter(user__id=uid)
 
@@ -153,6 +157,7 @@ def timesheet(request):
     for entry in entries:
         time_worked = float(entry.hours) + float(entry.minutes)
         e = {
+            'id': entry.id,
             'date': entry.date,
             'hours': entry.hours,
             'minutes': entry.minutes,

+ 1 - 1
static/app/css/app.css

@@ -9,5 +9,5 @@ body {
 }
 
 .report-row:nth-of-type(odd) {
-    background: #e0e0e0;
+    background: #f5f5f5;
 }