228 lines
7.4 KiB
Python
228 lines
7.4 KiB
Python
# vim: set ts=4 sw=4 et tw=80:
|
|
|
|
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, 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
|
|
from django.utils.translation import gettext as _
|
|
from django.db.models.functions import Extract, ExtractWeek
|
|
from django.db.models import Sum
|
|
from datetime import datetime, timedelta, date
|
|
import json
|
|
from django.core.serializers.json import DjangoJSONEncoder
|
|
import csv
|
|
from django.utils.encoding import smart_str
|
|
import math
|
|
|
|
# https://stackoverflow.com/questions/5882405
|
|
def tofirstdayinisoweek(year, week):
|
|
ret = datetime.strptime('%04d-%02d-1' % (year, week), '%Y-%W-%w')
|
|
if date(year, 1, 4).isoweekday() > 4:
|
|
ret -= timedelta(days=7)
|
|
return ret
|
|
|
|
def index(request):
|
|
template = loader.get_template('index.html')
|
|
|
|
if request.user.is_authenticated:
|
|
now = datetime.today()
|
|
|
|
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() - 1
|
|
weekArrows = ArrowCount.objects.filter(user=request.user) \
|
|
.filter(date__range=(now - timedelta(days=weekday), \
|
|
now + timedelta(days=6-weekday))) \
|
|
.aggregate(s=Sum('count'))
|
|
|
|
return HttpResponse(template.render({
|
|
'yearArrows': yearArrows,
|
|
'monthArrows': 0 if monthArrows['s'] is None else monthArrows['s'],
|
|
'weekArrows': 0 if weekArrows['s'] is None else weekArrows['s'],
|
|
'diffTarget': diff_target
|
|
}, request))
|
|
else:
|
|
return HttpResponse(template.render({}), request)
|
|
|
|
@login_required
|
|
def count_stats(request):
|
|
template = loader.get_template('stats.html')
|
|
|
|
# Group counts by week (extract isoyear works only on psql and DB2)
|
|
weeklyArrows = ArrowCount.objects \
|
|
.filter(user = request.user) \
|
|
.annotate(isoyear=Extract('date', lookup_name='isoyear')) \
|
|
.annotate(week=ExtractWeek('date')) \
|
|
.values('isoyear', 'week') \
|
|
.annotate(sum_count=Sum('count')) \
|
|
.order_by('-isoyear', '-week')
|
|
|
|
for w in weeklyArrows:
|
|
w['weekStarts'] = tofirstdayinisoweek(w['isoyear'], w['week'])
|
|
w['weekEnds'] = w['weekStarts'] + timedelta(days=6)
|
|
|
|
return HttpResponse(template.render({
|
|
'weeklyArrows': json.dumps(list(weeklyArrows), cls=DjangoJSONEncoder)
|
|
}, request))
|
|
|
|
@login_required
|
|
def arrow_count_export(request):
|
|
counts = ArrowCount.objects.filter(user=request.user).order_by('-date').all()
|
|
response = HttpResponse(content_type='text/csv')
|
|
response['Content-Disposition'] = 'attachment; filename=counts-' \
|
|
+ datetime.today().strftime('%Y-%m-%d') + '.csv'
|
|
writer = csv.writer(response, csv.excel, delimiter=';')
|
|
response.write(u'\ufeff'.encode('utf8'))
|
|
writer.writerow([
|
|
smart_str(u"Date"),
|
|
smart_str(u"Count")
|
|
])
|
|
for row in counts:
|
|
writer.writerow([
|
|
smart_str(row.date.strftime('%Y-%m-%d')),
|
|
smart_str(row.count)
|
|
])
|
|
return response
|
|
|
|
@login_required
|
|
def arrow_count_list(request):
|
|
page = request.GET.get('page')
|
|
|
|
if not page:
|
|
page = 1
|
|
else:
|
|
page = int(page)
|
|
|
|
if page <= 0:
|
|
raise SuspiciousOperation(_("page is negative or 0"))
|
|
|
|
start = settings.ITEMS_PER_PAGE * (page - 1)
|
|
finish = settings.ITEMS_PER_PAGE + start
|
|
counts = ArrowCount.objects.order_by('-date') \
|
|
.filter(user = request.user)[start:finish]
|
|
|
|
pageCount = math.ceil(ArrowCount.objects.filter(user = request.user).count() / \
|
|
settings.ITEMS_PER_PAGE)
|
|
template = loader.get_template('counter/list.html')
|
|
return HttpResponse(template.render({
|
|
'counts': counts,
|
|
'pageCount': pageCount,
|
|
'page': page
|
|
}, request))
|
|
|
|
class NewArrowCount(generic.CreateView):
|
|
form_class = ArrowCountForm
|
|
success_url = reverse_lazy('count_list')
|
|
template_name = 'counter/new.html'
|
|
|
|
def form_valid(self, form):
|
|
form.instance.user = self.request.user
|
|
return super().form_valid(form)
|
|
|
|
class EditArrowCount(generic.UpdateView):
|
|
form_class = ArrowCountForm
|
|
success_url = reverse_lazy('count_list')
|
|
template_name = 'counter/edit.html'
|
|
|
|
def get_object(self, queryset=None):
|
|
obj = ArrowCount.objects.get(id=self.kwargs['id'])
|
|
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.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')
|
|
|
|
def get_object(self, queryset=None):
|
|
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:
|
|
count = int(request.POST.get("count", None))
|
|
except ValueError:
|
|
return JsonResponse({
|
|
'success': False,
|
|
'error': _('count is not a number')
|
|
})
|
|
|
|
if count == None or count < 0:
|
|
return JsonResponse({
|
|
'success': False,
|
|
'error': _('count is negative or 0')
|
|
})
|
|
|
|
arrow_count = ArrowCount.objects.filter(
|
|
id=ac_id, user=request.user)[0]
|
|
|
|
if arrow_count == None:
|
|
return JsonResponse({
|
|
'success': False,
|
|
'error': _('ArrowCount instance not found or from different user')
|
|
})
|
|
|
|
arrow_count.count = count
|
|
arrow_count.save()
|
|
|
|
return JsonResponse({
|
|
'success': True,
|
|
'count': arrow_count.count
|
|
})
|
|
|