Merge branch 'master' of ssh://willipink.eu:3456/moritz/coinmanager

This commit is contained in:
willipink 2021-05-29 07:56:23 +00:00
commit 5ee77597ba
7 changed files with 153 additions and 32 deletions

View File

@ -0,0 +1,55 @@
# encoding: utf-8
#
# Copyright (C) 2020 willipink.eu
# Author Moritz Münch moritzmuench@mailbox.org
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from hashlib import sha256
from random import random
from django.core.cache import cache
from django.http import Http404
from .models import Coin
def get_last_modified_index(request):
return cache.get(f'last_modified_index', set_last_modified_index())
def set_last_modified_index():
''' set and return the datetime of the last coin added '''
try:
last_modified = Coin.objects.latest('date_modified').date_modified
except Coin.DoesNotExist:
raise Http404(f'Das Land "{name_iso}" existiert nicht')
cache.set(f'last_modified_index', last_modified)
return last_modified
def get_last_modified_country(request, name_iso):
return cache.get(f'last_modified_{name_iso}', set_last_modified_country(name_iso))
def set_last_modified_country(name_iso):
''' return the datetime of the last coin added to a country '''
try:
last_modified = Coin.objects.filter(country=name_iso).latest('date_modified').date_modified
except Coin.DoesNotExist:
raise Http404(f'Das Land "{name_iso}" existiert nicht')
cache.set(f'last_modified_{name_iso}', last_modified)
return last_modified

View File

@ -0,0 +1,54 @@
# encoding: utf-8
#
# Copyright (C) 2020 willipink.eu
# Author Moritz Münch moritzmuench@mailbox.org
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .models import Country, Coin
def total_coin_sum():
''' add each coin_sum from each country and return the result
>>> total_coin_sum()
173.57
'''
total_coin_sum = 0
for country in Country.objects.order_by('name'):
total_coin_sum += coin_sum_of_(country)
return total_coin_sum
def coin_sum_of_(country):
''' calculate the sum of all coins from a country
>>> coin_sum_of_(germany)
346.82
'''
coin_count = {'total': 0}
for value in [1, 2, 5, 10, 20, 50, 100, 200, 201, 202, 203]:
coin_count[value] = Coin.objects.filter(
country=country,
value=value
).exclude(found_by__isnull=True).count()
if value > 200:
coin_count['total'] += 200 * coin_count[value]
else:
coin_count['total'] += value * coin_count[value]
return coin_count['total'] / 100

View File

@ -20,7 +20,7 @@
from datetime import datetime, date from datetime import datetime, date
from django.db.models import BooleanField, CASCADE, CharField, DateField, ForeignKey, Model, PositiveIntegerField, PositiveSmallIntegerField, TextField from django.db.models import BooleanField, CASCADE, CharField, DateField, DateTimeField, ForeignKey, Model, PositiveIntegerField, PositiveSmallIntegerField, TextField
year_now = int(datetime.now().year) year_now = int(datetime.now().year)
@ -85,6 +85,10 @@ class Coin(Model):
found_on = DateField('Eingetragen am', default=date.today) found_on = DateField('Eingetragen am', default=date.today)
date_added = DateTimeField('Hinzugefügt', auto_now_add=True)
date_modified = DateTimeField('Geändert', auto_now=True)
circulation = PositiveIntegerField('Auflage', default=0) circulation = PositiveIntegerField('Auflage', default=0)
buy_only = BooleanField('Kursmünze', default=False) buy_only = BooleanField('Kursmünze', default=False)

View File

@ -1,9 +1,11 @@
{% load cache %}
{% csrf_token %}
{% cache None controlbar user %}
<style type="text/css">{% for user in users %} <style type="text/css">{% for user in users %}
div.{{ user.name }} { background-color: {{ user.color }} !important; }{% endfor %} div.{{ user.name }} { background-color: {{ user.color }} !important; }{% endfor %}
</style> </style>
<div id="button_control"> <div id="button_control">
{% csrf_token %}
{% if user.is_authenticated %} {% if user.is_authenticated %}
<button id="begin_edit" class="btn btn-info" title="Hinzufügen"><i class="fas fa-plus"></i><span> Hinzufügen</span></button> <button id="begin_edit" class="btn btn-info" title="Hinzufügen"><i class="fas fa-plus"></i><span> Hinzufügen</span></button>
<button id="do_logout" class="btn btn-info" title="Abmelden"><i class="fas fa-sign-out-alt"></i></button> <button id="do_logout" class="btn btn-info" title="Abmelden"><i class="fas fa-sign-out-alt"></i></button>
@ -14,7 +16,6 @@
<!-- navbar --> <!-- navbar -->
<nav class="navbar navbar-expand-lg navbar-light bg-light"> <nav class="navbar navbar-expand-lg navbar-light bg-light">
{% csrf_token %}
<!-- advanced options --> <!-- advanced options -->
<div id="advanced_options"> <div id="advanced_options">
@ -114,7 +115,7 @@
</div> </div>
</div> </div>
</div> </div>
{% endcache %}
<!-- modal login --> <!-- modal login -->
{% if not user.is_authenticated %} {% if not user.is_authenticated %}
<div id="login" class="modal-container"> <div id="login" class="modal-container">

View File

@ -1,3 +1,5 @@
{% load cache %}
{% cache None header %}
<!DOCTYPE html> <!DOCTYPE html>
<!-- <!--
@ -53,3 +55,4 @@
<title>{{ title }}</title> <title>{{ title }}</title>
</head> </head>
<body> <body>
{% endcache %}

View File

@ -17,6 +17,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from datetime import datetime, date from datetime import datetime, date
from json import dumps from json import dumps
@ -24,32 +25,15 @@ from django.conf import settings
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
from django.template import loader from django.template import loader
from django.template.defaultfilters import register from django.template.defaultfilters import register
from django.views.decorators.http import condition
from .cache import (get_last_modified_index, set_last_modified_index,
get_last_modified_country, set_last_modified_country)
from .models import Country, Stamp, Coin, User from .models import Country, Stamp, Coin, User
from .helper import total_coin_sum, coin_sum_of_
def total_coin_sum(): @condition(last_modified_func=get_last_modified_index)
total_coin_sum = 0
for country in Country.objects.order_by('name'):
total_coin_sum += coin_sum_of_(country)
return total_coin_sum
def coin_sum_of_(country):
coin_count = {'total': 0}
for value in [1, 2, 5, 10, 20, 50, 100, 200, 201, 202, 203]:
coin_count[value] = Coin.objects.filter(
country=country,
value=value
).exclude(found_by__isnull=True).count()
if value > 200:
coin_count['total'] += 200 * coin_count[value]
else:
coin_count['total'] += value * coin_count[value]
coin_count['total'] /= 100
return coin_count['total']
def index(request): def index(request):
''' index view ''' ''' index view '''
@ -60,12 +44,13 @@ def index(request):
context = { context = {
'countrys': countrys, 'countrys': countrys,
'users': users, 'users': users,
'coin_sum': f"{coin_sum:.2f}" 'coin_sum': f'{coin_sum:.2f}'
} }
return HttpResponse(template.render(context, request)) return HttpResponse(template.render(context, request))
@condition(last_modified_func=get_last_modified_country)
def detail_country(request, name_iso): def detail_country(request, name_iso):
''' wrapper_view for a *single* country ''' ''' wrapper_view for a *single* country '''
@ -194,6 +179,7 @@ def show_country(country, single_country=False):
c['years'][str(coin.year)][stamp][coin.value] = { c['years'][str(coin.year)][stamp][coin.value] = {
'marker': marker, 'marker': marker,
'name': name, 'name': name,
'date_modified': coin.date_modified,
'td_class': td_class, 'td_class': td_class,
'div_class': div_class, 'div_class': div_class,
'special_class': special_class, 'special_class': special_class,
@ -225,6 +211,7 @@ def show_coin(coin, value):
'value': value, 'value': value,
'marker': coin['marker'], 'marker': coin['marker'],
'name': coin['name'], 'name': coin['name'],
'date_modified': coin['date_modified'],
'td_class': coin['td_class'], 'td_class': coin['td_class'],
'div_class': coin['div_class'], 'div_class': coin['div_class'],
'special_class': coin['special_class'], 'special_class': coin['special_class'],
@ -268,6 +255,8 @@ def add_coin(request):
name no - str name no - str
found_by no None obj User found_by no None obj User
found_on no None str %Y-%m-%d found_on no None str %Y-%m-%d
date-added no auto str %Y-%m-%d %H:%M:%S.%s
date-modified no auto str %Y-%m-%d %H:%M:%S.%s
circulation no 0 int [0; 1000000000] circulation no 0 int [0; 1000000000]
buy_only no False bool buy_only no False bool
checked no False bool checked no False bool
@ -385,6 +374,8 @@ def add_coin(request):
in_collector = ec, in_collector = ec,
exists = exists) exists = exists)
set_last_modified_index()
set_last_modified_country(country.name_iso)
return response() return response()

View File

@ -44,10 +44,11 @@ INSTALLED_APPS = [
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.cache.UpdateCacheMiddleware', # 'django.middleware.cache.UpdateCacheMiddleware', # per-site cache
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware', # 'django.middleware.cache.FetchFromCacheMiddleware', # per-site cache
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
# 'django.middleware.http.ConditionalGetMiddleware', # set 'ETag' and 'Last Modified' headers
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
@ -129,6 +130,18 @@ MAINTENANCE_MODE_READ_ONLY = False
# do not redirect after login # do not redirect after login
LOGIN_REDIRECT_URL = './' LOGIN_REDIRECT_URL = './'
# caching # caching modes, i.e. file based, memcached, or other fancy stuff
CACHE_MIDDLEWARE_ALIAS = willipink_coinc # https://docs.djangoproject.com/en/3.1/topics/cache/#cache-arguments
CACHE_MIDDLEWARE_SECONDS = 600 CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
'TIMEOUT': None,
}
}
# per-site cache
# updatecachemiddleware: adds 'Expires' and 'Cache-Control' headers to give the
# page a maximum age CACHE_MIDDLEWARE_SECONDS
# CACHE_MIDDLEWARE_ALIAS = 'default'
# CACHE_MIDDLEWARE_SECONDS = 600