diff --git a/.gitignore b/.gitignore index 86cd900..b78f427 100644 --- a/.gitignore +++ b/.gitignore @@ -76,7 +76,7 @@ coverage.xml docs/_build/ # PyBuilder -target/ +/target/ ### Django ### diff --git a/counter/forms.py b/counter/forms.py index aadd33f..2fef448 100644 --- a/counter/forms.py +++ b/counter/forms.py @@ -1,6 +1,6 @@ from django import forms from django.conf import settings -from .models import ArrowCount +from .models import ArrowCount, Target class ArrowCountForm(forms.ModelForm): date = forms.DateField(widget=forms.DateInput( @@ -10,3 +10,9 @@ class ArrowCountForm(forms.ModelForm): class Meta: model = ArrowCount fields = ['date', 'count'] + +class TargetForm(forms.ModelForm): + + class Meta: + model = Target + fields = ['target'] diff --git a/counter/migrations/0002_auto_20190726_2244.py b/counter/migrations/0002_auto_20190726_2244.py new file mode 100644 index 0000000..e8c1aa1 --- /dev/null +++ b/counter/migrations/0002_auto_20190726_2244.py @@ -0,0 +1,28 @@ +# Generated by Django 2.2.3 on 2019-07-26 20:44 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0001_initial'), + ('counter', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Target', + fields=[ + ('target', models.PositiveIntegerField(verbose_name='Target to reach')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.AlterField( + model_name='arrowcount', + name='date', + field=models.DateField(verbose_name='Training date'), + ), + ] diff --git a/counter/models.py b/counter/models.py index b403f72..237d44f 100644 --- a/counter/models.py +++ b/counter/models.py @@ -2,6 +2,14 @@ from django.db import models from django.conf import settings from django.contrib.auth.models import User +class Target(models.Model): + target = models.PositiveIntegerField('Target to reach') + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + primary_key = True + ) + class ArrowCount(models.Model): user = models.ForeignKey( settings.AUTH_USER_MODEL, diff --git a/counter/static/css/main.css b/counter/static/css/main.css index 3dbcb6a..578dddf 100644 --- a/counter/static/css/main.css +++ b/counter/static/css/main.css @@ -36,14 +36,14 @@ form ul, form span.helptext { } form ul { - background: #ffecb3; + background: #ffecb3; } form ul.errorlist { background: #ffcdd2; } -form .card-action button[type=submit] { +form .card-action button { background: none !important; border: none; cursor: pointer; @@ -57,11 +57,13 @@ form .card-action button[type=submit] { margin-right: auto; } -#edit-arrowcount-form input { +#edit-arrowcount-form input, +#edit-target-form input { text-align: center } -#edit-arrowcount-form #id_count { +#edit-arrowcount-form #id_count, +#edit-target-form #id_target { font-size: 3em; padding: .25em 0; } diff --git a/counter/templates/index.html b/counter/templates/index.html index 39ae609..f762460 100644 --- a/counter/templates/index.html +++ b/counter/templates/index.html @@ -5,17 +5,23 @@ {% block content %}

Arrow counter

A simple online arrow counter
+{% if user.is_authenticated %}

Excel Data (CSV) file_download

- -{% if user.is_authenticated %}
Arrows shot this year:

{{ yearArrows }}

+{% if diffTarget is not False %} +
+
Difference with target:
+

{{ diffTarget }}

+
+{% endif %}
Arrows shot this month:

{{ monthArrows }}

diff --git a/counter/templates/menu.html b/counter/templates/menu.html index a619a45..5e0ef8c 100644 --- a/counter/templates/menu.html +++ b/counter/templates/menu.html @@ -14,6 +14,7 @@
  • {% if user.is_authenticated %}
  • Counts
  • +
  • Set yearly target
  • Weekly stats
  • {% if user.is_superuser %} diff --git a/counter/templates/target/edit.html b/counter/templates/target/edit.html new file mode 100644 index 0000000..7f16528 --- /dev/null +++ b/counter/templates/target/edit.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} + +{% load static %} + +{% block title %}Set yearly target{% endblock %} + +{% block content %} +

    Set yearly target

    +
    +
    +
    + {% csrf_token %} +
    + {{ form.as_p }} +
    +
    +
    + + +
    +
    +
    +{% endblock %} diff --git a/counter/urls.py b/counter/urls.py index 2f1b372..c111f05 100644 --- a/counter/urls.py +++ b/counter/urls.py @@ -11,6 +11,10 @@ urlpatterns = [ name='count_new'), path('count/edit/', login_required(views.EditArrowCount.as_view()), name='count_edit'), + path('target/edit', login_required(views.EditTarget.as_view()), + name='target_edit'), + path('target/delete', views.target_delete, + name='target_delete'), path('count/delete/', login_required(views.DeleteArrowCount.as_view()), name='count_delete'), path('count/edit//ajax', login_required(views \ diff --git a/counter/views.py b/counter/views.py index 080d623..1b57546 100644 --- a/counter/views.py +++ b/counter/views.py @@ -1,12 +1,12 @@ # vim: set ts=4 sw=4 et tw=80: -from django.shortcuts import render +from django.shortcuts import render, redirect from django.http import HttpResponse, JsonResponse from django.views import generic from django.template import loader from django.urls import reverse_lazy -from .models import ArrowCount -from .forms import ArrowCountForm +from .models import ArrowCount, Target +from .forms import ArrowCountForm, TargetForm from django.contrib.auth.decorators import login_required from django.conf import settings from django.core.exceptions import SuspiciousOperation @@ -35,20 +35,32 @@ def index(request): yearArrows = ArrowCount.objects.filter(user=request.user) \ .filter(date__range=(date(now.year, 1, 1), date(now.year, 12, 31))) \ .aggregate(s=Sum('count')) + yearArrows = yearArrows['s'] if yearArrows['s'] is not None else 0 + + diff_target = False + try: + target = Target.objects.get(user=request.user).target + days_this_year = (date(now.year + 1, 1, 1) - date(now.year, 1, 1)).days + diff_target = round(yearArrows - (now.timetuple().tm_yday / days_this_year) * \ + target) + except Target.DoesNotExist: + pass monthArrows = ArrowCount.objects.filter(user=request.user) \ .filter(date__year=now.year, date__month=now.month) \ .aggregate(s=Sum('count')) - weekday = now.isoweekday() + weekday = now.isoweekday() - 1 weekArrows = ArrowCount.objects.filter(user=request.user) \ - .filter(date__range=(now - timedelta(days=weekday), now + timedelta(days=6-weekday))) \ + .filter(date__range=(now - timedelta(days=weekday), \ + now + timedelta(days=6-weekday))) \ .aggregate(s=Sum('count')) return HttpResponse(template.render({ - 'yearArrows': 0 if yearArrows['s'] is None else yearArrows['s'], + 'yearArrows': yearArrows, 'monthArrows': 0 if monthArrows['s'] is None else monthArrows['s'], - 'weekArrows': 0 if weekArrows['s'] is None else weekArrows['s'] + 'weekArrows': 0 if weekArrows['s'] is None else weekArrows['s'], + 'diffTarget': diff_target }, request)) else: return HttpResponse(template.render({}), request) @@ -143,6 +155,26 @@ class EditArrowCount(generic.UpdateView): context_data.update(ac_id=self.kwargs['id']) return self.render_to_response(context_data) +class EditTarget(generic.UpdateView): + form_class = TargetForm + success_url = reverse_lazy('index') + template_name = 'target/edit.html' + + def get_object(self, queryset=None): + try: + obj = Target.objects.get(user=self.request.user) + except Target.DoesNotExist: + obj = Target(user=self.request.user, target=0) + obj.save() + return obj + + def get(self, request, *args, **kwargs): + super().get(self, request, *args, **kwargs) + context_data = self.get_context_data() + context_data.update(ac_id=self.request.user) + return self.render_to_response(context_data) + + class DeleteArrowCount(generic.DeleteView): model = ArrowCount success_url = reverse_lazy('count_list') @@ -151,6 +183,15 @@ class DeleteArrowCount(generic.DeleteView): obj = ArrowCount.objects.get(id=self.kwargs['id']) return obj +@login_required +def target_delete(request): + try: + to_delete = Target.objects.get(user=request.user) + to_delete.delete() + except Target.DoesNotExist: + pass + return redirect('index') + @login_required def arrow_count_update_ajax(request, ac_id): try: