Merge branch 'release/1.0.0'
This commit is contained in:
@@ -8,3 +8,5 @@ build/
|
||||
*/*/__pycache__/
|
||||
caromserver/local_settings.py
|
||||
/staticfiles/
|
||||
.venv/
|
||||
update.sh
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
[[source]]
|
||||
name = "pypi"
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[packages]
|
||||
django = "==2.1.5"
|
||||
django-crispy-forms = "==1.7.2"
|
||||
django-debug-toolbar = "==1.11"
|
||||
django-extensions = "==2.1.5"
|
||||
django-tables2 = "==2.0.4"
|
||||
djangorestframework = "==3.9.1"
|
||||
requests = "==2.21.0"
|
||||
|
||||
[requires]
|
||||
python_version = "3.5"
|
||||
Generated
+126
@@ -0,0 +1,126 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "de1e65bd4b2342db22fea58996979f48314fcad56bd7b50f4c939035771ef85c"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.5"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7",
|
||||
"sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033"
|
||||
],
|
||||
"version": "==2018.11.29"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"django": {
|
||||
"hashes": [
|
||||
"sha256:a32c22af23634e1d11425574dce756098e015a165be02e4690179889b207c7a8",
|
||||
"sha256:d6393918da830530a9516bbbcbf7f1214c3d733738779f06b0f649f49cc698c3"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.1.5"
|
||||
},
|
||||
"django-crispy-forms": {
|
||||
"hashes": [
|
||||
"sha256:5952bab971110d0b86c278132dae0aa095beee8f723e625c3d3fa28888f1675f",
|
||||
"sha256:705ededc554ad8736157c666681165fe22ead2dec0d5446d65fc9dd976a5a876"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.7.2"
|
||||
},
|
||||
"django-debug-toolbar": {
|
||||
"hashes": [
|
||||
"sha256:89d75b60c65db363fb24688d977e5fbf0e73386c67acf562d278402a10fc3736",
|
||||
"sha256:c2b0134119a624f4ac9398b44f8e28a01c7686ac350a12a74793f3dd57a9eea0"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.11"
|
||||
},
|
||||
"django-extensions": {
|
||||
"hashes": [
|
||||
"sha256:6fcedb2ea660c9dbf9ac59441721ffdd4ab5b753fbd6159c3e28f391a65bab46",
|
||||
"sha256:a607459e5fa8c579a672131b63366fa52fab80adb2a862d362f5fb48cd2d2cac"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.1.5"
|
||||
},
|
||||
"django-tables2": {
|
||||
"hashes": [
|
||||
"sha256:a893fca1afe2e95b9739c6428cc6c9735a219f65707e24274df3920f61358525",
|
||||
"sha256:b5f7b4c76160ee927005e52ebea633c86d4529cf84757c0acd5d0434d31798a1"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.4"
|
||||
},
|
||||
"djangorestframework": {
|
||||
"hashes": [
|
||||
"sha256:79c6efbb2514bc50cf25906d7c0a5cfead714c7af667ff4bd110312cd380ae66",
|
||||
"sha256:a4138613b67e3a223be6c97f53b13d759c5b90d2b433bad670b8ebf95402075f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.9.1"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
|
||||
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
|
||||
],
|
||||
"version": "==2.8"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9",
|
||||
"sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c"
|
||||
],
|
||||
"version": "==2018.9"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e",
|
||||
"sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.21.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
|
||||
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
|
||||
],
|
||||
"version": "==1.12.0"
|
||||
},
|
||||
"sqlparse": {
|
||||
"hashes": [
|
||||
"sha256:ce028444cfab83be538752a2ffdb56bc417b7784ff35bb9a3062413717807dec",
|
||||
"sha256:d9cf190f51cbb26da0412247dfe4fb5f4098edb73db84e02f9fc21fdca31fed4"
|
||||
],
|
||||
"version": "==0.2.4"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39",
|
||||
"sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"
|
||||
],
|
||||
"version": "==1.24.1"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
||||
@@ -35,6 +35,12 @@ class ClientAdmin(admin.ModelAdmin):
|
||||
fields = ['location', 'uuid', 'report_user', 'last_seen']
|
||||
|
||||
|
||||
@admin.register(ClientData)
|
||||
class ClientDataAdmin(admin.ModelAdmin):
|
||||
list_display = ('uuid', 'last_seen')
|
||||
fields = ['location', 'last_seen']
|
||||
|
||||
|
||||
@admin.register(LocationData)
|
||||
class LocationDataAdmin(admin.ModelAdmin):
|
||||
def get_urls(self):
|
||||
@@ -46,6 +52,8 @@ class LocationDataAdmin(admin.ModelAdmin):
|
||||
return my_urls + urls
|
||||
|
||||
def process_locationdata(self, request):
|
||||
from .tasks import process_location_data
|
||||
process_location_data(sender=None)
|
||||
messages.success(request, 'Items processed.')
|
||||
return redirect('admin:billard_locationdata_changelist')
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
from django import forms
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
class UserInformationUpdateForm(forms.ModelForm):
|
||||
email = forms.EmailField()
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('first_name', 'last_name', 'email',)
|
||||
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 2.0.2 on 2018-02-19 10:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('billard', '0026_client_last_seen'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ClientData',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('uuid', models.UUIDField(verbose_name='Identifier')),
|
||||
('last_seen', models.DateTimeField(verbose_name='Letzter Update')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Client Data logs',
|
||||
'verbose_name_plural': 'Client Data logs',
|
||||
},
|
||||
),
|
||||
]
|
||||
+10
-6
@@ -4,8 +4,6 @@ import uuid
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -102,7 +100,13 @@ class Accounting(models.Model):
|
||||
verbose_name_plural = "Buchhaltungseinträge"
|
||||
|
||||
|
||||
@receiver(post_save, sender=LocationData)
|
||||
def test(sender, **kwargs):
|
||||
from .tasks import process_location_data
|
||||
process_location_data()
|
||||
class ClientData(models.Model):
|
||||
uuid = models.UUIDField(verbose_name="Identifier")
|
||||
last_seen = models.DateTimeField(verbose_name="Letzter Update")
|
||||
|
||||
def __str__(self):
|
||||
return '{}, {}'.format(self.uuid, self.last_seen)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Client Data logs"
|
||||
verbose_name_plural = "Client Data logs"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from billard.models import LocationData, Client
|
||||
from billard.models import LocationData, ClientData
|
||||
|
||||
|
||||
class LocationDataSerializer(serializers.HyperlinkedModelSerializer):
|
||||
@@ -11,5 +11,5 @@ class LocationDataSerializer(serializers.HyperlinkedModelSerializer):
|
||||
|
||||
class ClientUpdateLastSeenSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Client
|
||||
model = ClientData
|
||||
fields = ('uuid', 'last_seen')
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import django_tables2 as tables
|
||||
|
||||
from .models import Location
|
||||
|
||||
|
||||
class LocationTable(tables.Table):
|
||||
code = tables.TemplateColumn(template_name='billard/tc_location_detail.html')
|
||||
|
||||
class Meta:
|
||||
model = Location
|
||||
fields = ('code', 'name', 'street', 'plz', 'city')
|
||||
orderable = False
|
||||
|
||||
|
||||
class LocationAccountingTable(tables.Table):
|
||||
code = tables.TemplateColumn(template_name='billard/tc_location_detail.html')
|
||||
accounting = tables.TemplateColumn(template_name='billard/tc_accounting_detail.html')
|
||||
|
||||
class Meta:
|
||||
model = Location
|
||||
fields = ('code', 'name', 'street', 'plz', 'city', 'accounting')
|
||||
orderable = False
|
||||
+24
-2
@@ -2,13 +2,28 @@ from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import logging
|
||||
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
import billard.utils as utils
|
||||
from billard.models import LocationData, Client, Accounting
|
||||
from billard.models import LocationData, Client, Accounting, ClientData
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def process_location_data():
|
||||
@receiver(post_save, sender=ClientData)
|
||||
def process_client_data(sender, **kwargs):
|
||||
data = ClientData.objects.all().order_by('last_seen')
|
||||
for cd in data:
|
||||
client = Client.objects.get(uuid=cd.uuid)
|
||||
client.last_seen = cd.last_seen
|
||||
client.save()
|
||||
cd.delete()
|
||||
|
||||
|
||||
@receiver(post_save, sender=LocationData)
|
||||
def process_location_data(sender, **kwargs):
|
||||
log.info('Starte die Verarbeitung der Location-Data-Objecte')
|
||||
data = LocationData.objects.filter(processed=False).order_by('tst')
|
||||
for ld in data:
|
||||
try:
|
||||
@@ -64,3 +79,10 @@ def process_location_data():
|
||||
log.error(ld.error_msg)
|
||||
except:
|
||||
log.exception('', exc_info=True)
|
||||
|
||||
|
||||
@receiver(post_save, sender=Accounting)
|
||||
def process_accounting_data(sender, **kwargs):
|
||||
log.info('Starte die Verarbeitung der Accounting-Data-Objecte')
|
||||
data = Accounting.objects.filter(prize=0.0, reporter_uuid__isnull=True).exclude(time_to__isnull=True)
|
||||
data.delete()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% load i18n admin_urls static admin_list %}
|
||||
{% block object-tools-items %}
|
||||
<li>
|
||||
<a href="{% url 'admin:process_locationdata' %}">
|
||||
<a href="{% url 'admin:process_locationdata' %}" title="Verarbeiten der LocationDate Elemente">
|
||||
LD Verarbeiten
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -15,8 +15,12 @@
|
||||
|
||||
{{ pk }}
|
||||
|
||||
|
||||
<form action="confirm/" method="post" id="accounting">
|
||||
{% csrf_token %}
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Start-Datum:</th>
|
||||
<th>Stop-Datum:</th>
|
||||
<th>Preis Normal:</th>
|
||||
@@ -25,6 +29,8 @@
|
||||
</tr>
|
||||
{% for acc in accounting %}
|
||||
<tr>
|
||||
<td><input type="checkbox" name="list_acc_id" id="option{{ acc.id }}"
|
||||
value={{ acc.id }} checked="checked"/></td>
|
||||
<td>{{ acc.time_from }}</td>
|
||||
<td>{{ acc.time_to }}</td>
|
||||
<td>{{ acc.prize_normal }}</td>
|
||||
@@ -33,12 +39,9 @@
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<form action="confirm/" method="post" id="accounting">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="location-selector" value="{{ location_id }}">
|
||||
<input type="hidden" name="accountings" value="{{ acc_ids }}">
|
||||
<button type="submit" class="btn btn-default">Abrechnen</button>
|
||||
<button type="submit" class="btn btn-danger">Abrechnen</button>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load display_client %}
|
||||
|
||||
{% block title %}Location Data{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if not locations|length_is:"1" %}
|
||||
<form action="." method="post" id="location-form">
|
||||
{% csrf_token %}
|
||||
<div id="location-selector" class="alert">
|
||||
<select class="form-control" form="location-form" name="location-selector" id="location-select">
|
||||
{% for loc in locations %}
|
||||
<option value="{{ loc.id }}"{% if loc.id == location_id %} selected{% endif %}>{{ loc.code }}
|
||||
- {{ loc.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
<div id="desk_data">
|
||||
{% include 'billard/index_ajax.html' %}
|
||||
</div>
|
||||
<div id="modal-wrapper">
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript">
|
||||
var interval;
|
||||
$(document).ready(function () {
|
||||
$.ajaxSetup({cache: false});
|
||||
interval = window.setInterval(refresh_page, 1000);
|
||||
});
|
||||
|
||||
function refresh_page() {
|
||||
$('#desk_data').load('#');
|
||||
$('#modal-wrapper').load('{% url 'accountmodal' %}', function () {
|
||||
if ($('#accountsmodal').length) {
|
||||
window.clearInterval(interval);
|
||||
$('#accountsmodal').modal('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,10 +0,0 @@
|
||||
{% load display_client %}
|
||||
{% if clients %}
|
||||
{% for cli in clients %}
|
||||
{% for i in range %} {{ cli|display_client:i }} {% endfor %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="col-md-12">
|
||||
<div class="col-md-12 alert alert-danger">Keine Tische angelegt!</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -1,4 +1,4 @@
|
||||
{% load display_client %}
|
||||
{% load display_client display_daily_sale %}
|
||||
{% if location.clients.all %}
|
||||
{% for cli in location.clients.all %}
|
||||
{% for i in "12345678" %}
|
||||
@@ -10,3 +10,8 @@
|
||||
<div class="alert alert-danger">Keine Tische angelegt!</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col col-12">
|
||||
<div class="alert alert-warning">
|
||||
{{ location|display_daily_sale }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
|
||||
{% block title %}Standortliste{% endblock %}
|
||||
|
||||
@@ -7,37 +8,6 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if location_list %}
|
||||
<h2>Bitte Standort auswählen:</h2>
|
||||
<table class="table table-hover">
|
||||
<tr>
|
||||
<th>Code</th>
|
||||
<th>Name</th>
|
||||
<th>Strasse</th>
|
||||
<th>Plz</th>
|
||||
<th>Ort</th>
|
||||
{% if perms.billard.change_accounting %}
|
||||
<th>Accounting</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% for loc in location_list %}
|
||||
<tr>
|
||||
<td><a href="{% url 'billard:location_detail' loc.id %}"
|
||||
class="btn btn-outline-primary btn-sm">{{ loc.code|default_if_none:"" }}</a></td>
|
||||
<td>{{ loc.name|default_if_none:"" }}</td>
|
||||
<td>{{ loc.street|default_if_none:"" }}</td>
|
||||
<td>{{ loc.plz|default_if_none:"" }}</td>
|
||||
<td>{{ loc.city|default_if_none:"" }}</td>
|
||||
{% if perms.billard.change_accounting %}
|
||||
<td><a href="{% url 'billard:accounting_detail' loc.id %}"
|
||||
class="btn btn-outline-danger btn-sm">Abrechnen</a></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>Keine Standorte Zugeordnet.</p>
|
||||
{% endif %}
|
||||
|
||||
{% render_table table %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
{% extends '_base.html' %}
|
||||
|
||||
{% block title %}Location Data{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'billard/locationdata_detail_ajax.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
setInterval(function () {
|
||||
$("#content").load("#")
|
||||
}, 1000);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,51 +0,0 @@
|
||||
<h1>Locationdata: {{ locationdata.id }}</h1>
|
||||
|
||||
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
|
||||
|
||||
<form action="{% url 'index' %}" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<label for="location_id" class="col-sm-2 control-label">Location Id</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="location_id" type="text" name="location_id" value="{{ locationdata.location_id }}"
|
||||
placeholder="Locaton" class="form-control" disabled="disabled"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="table_no" class="col-sm-2 control-label">Table Number</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="table_no" type="number" name="table_no" value="{{ locationdata.table_no }}"
|
||||
placeholder="Table" class="form-control" min="1" max="8" disabled="disabled"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="tst" class="col-sm-2 control-label">Timestamp</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="tst" type="datetime" name="tst" value="{{ locationdata.tst }}"
|
||||
placeholder="Table" class="form-control" disabled="disabled"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="on_off" class="col-sm-2 control-label">On / Off</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="on_off" type="checkbox" name="on_off" value="{{ locationdata.on_off }}"
|
||||
placeholder="Table" class="form-control" disabled="disabled"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="processed" class="col-sm-2 control-label">Processed</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="processed" type="checkbox" name="processed" value="{{ locationdata.processed }}"
|
||||
placeholder="Table" class="form-control" disabled="disabled"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="error_msg" class="col-sm-2 control-label">Error Message</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="error_msg" type="text" name="error_msg" value="{{ locationdata.error_msg }}"
|
||||
placeholder="Table" class="form-control" disabled="disabled"/>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Abschicken</button>
|
||||
<a class="btn btn-default" href=".." role="button">Zurück</a>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
{% extends '_base.html' %}
|
||||
|
||||
{% block title %}Location Data{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'billard/locationdata_list_ajax.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
setInterval(function () {
|
||||
$("#content").load("#")
|
||||
}, 1000);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,42 +0,0 @@
|
||||
{% extends '_base.html' %}
|
||||
|
||||
{% block title %}Location Data{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="location-selector" class="alert">
|
||||
<select class="form-control">
|
||||
<option value="1">Casino 1</option>
|
||||
<option value="2">Casino 2</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{% if object_list %}
|
||||
<h1>Location Data</h1>
|
||||
<table class="table table-hover">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Location</th>
|
||||
<th>Table</th>
|
||||
<th>Timestamp</th>
|
||||
<th>On_Off</th>
|
||||
<th>Proc</th>
|
||||
<th>Error</th>
|
||||
</tr>
|
||||
{% for location_data in object_list %}
|
||||
<tr>
|
||||
<td><a href="{% url 'detail' location_data.id %}">{{ location_data.id }}</a></td>
|
||||
<td>{{ location_data.location_id }}</td>
|
||||
<td>{{ location_data.table_no }}</td>
|
||||
<td>{{ location_data.tst }}</td>
|
||||
<td>{{ location_data.on_off }}</td>
|
||||
<td>{{ location_data.processed }}</td>
|
||||
<td>{{ location_data.error_msg }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>No data available.</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
{% load static from staticfiles %}
|
||||
<a href="{% url 'billard:accounting_detail' record.id %}" class="btn btn-outline-danger btn-sm">Abrechnen</a>
|
||||
@@ -0,0 +1,3 @@
|
||||
{% load static from staticfiles %}
|
||||
<a href="{% url 'billard:location_detail' record.id %}"
|
||||
class="btn btn-outline-primary btn-sm">{{ record.code|default_if_none:"" }}</a>
|
||||
@@ -17,28 +17,10 @@ def display_client(client, desk_no):
|
||||
loc = desk.client.location
|
||||
if not desk.enabled:
|
||||
return ''
|
||||
alert = 'alert-success'
|
||||
acc = desk.accounting_set.all()[:3][::-1]
|
||||
if acc is not None and len(acc) > 0:
|
||||
a = acc[-1]
|
||||
if a.time_to is None:
|
||||
alert = 'alert-info'
|
||||
prize, u1, u2 = utils.get_prize_for(
|
||||
start=a.time_from,
|
||||
end=datetime.now(),
|
||||
pph=desk.prize,
|
||||
hh_start=loc.happy_hour_start,
|
||||
hh_end=loc.happy_hour_end,
|
||||
pphh=desk.prize_hh,
|
||||
)
|
||||
prize = '{0:.2f}'.format(prize)
|
||||
if prize != a.prize:
|
||||
a.prize = prize
|
||||
before5min = datetime.now() - timedelta(minutes=5)
|
||||
if client.last_seen is not None and client.last_seen < before5min:
|
||||
alert = 'alert-danger'
|
||||
_calc_prize(desk, acc)
|
||||
html = '<div class="col col-12 col-lg-6">\n'
|
||||
html += ' <div class="table-info alert {}">\n'.format(alert)
|
||||
html += ' <div class="table-info alert {}">\n'.format(_get_alert_name(desk))
|
||||
html += ' <h4 style="text-align: center">({}) {}</h4>\n'.format(desk_no, desk.name)
|
||||
if loc.happy_hour_start is not None and desk.prize_hh is not None:
|
||||
html += ' <h6 style="text-align: center">Preis: {:.2f} € / Stunde | {} - {}: {:.2f} / € Stunde</h6>\n' \
|
||||
@@ -67,3 +49,33 @@ def display_client(client, desk_no):
|
||||
html += '</div>\n'
|
||||
html = format_html(html)
|
||||
return html
|
||||
|
||||
|
||||
def _get_alert_name(desk):
|
||||
alert = 'alert-success'
|
||||
acc = desk.accounting_set.all()[:3][::-1]
|
||||
if acc is not None and len(acc) > 0:
|
||||
a = acc[-1]
|
||||
if a.time_to is None:
|
||||
alert = 'alert-info'
|
||||
before5min = datetime.now() - timedelta(minutes=5)
|
||||
if desk.client.last_seen is not None and desk.client.last_seen < before5min:
|
||||
alert = 'alert-danger'
|
||||
return alert
|
||||
|
||||
|
||||
def _calc_prize(desk, acc):
|
||||
if acc is not None and len(acc) > 0:
|
||||
a = acc[-1]
|
||||
if a.time_to is None:
|
||||
prize, u1, u2 = utils.get_prize_for(
|
||||
start=a.time_from,
|
||||
end=datetime.now(),
|
||||
pph=desk.prize,
|
||||
hh_start=desk.client.location.happy_hour_start,
|
||||
hh_end=desk.client.location.happy_hour_end,
|
||||
pphh=desk.prize_hh,
|
||||
)
|
||||
prize = '{0:.2f}'.format(prize)
|
||||
if prize != a.prize:
|
||||
a.prize = prize
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from django import template
|
||||
from django.db.models import Sum
|
||||
|
||||
from billard.models import Accounting
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter(is_safe=True)
|
||||
def display_daily_sale(location):
|
||||
start_date = datetime.now().replace(hour=5, minute=0, second=0, microsecond=0)
|
||||
end_date = start_date + timedelta(days=1)
|
||||
prize__sum = Accounting.objects.filter(desk__client__location=location,
|
||||
time_to__range=(start_date, end_date)).aggregate(Sum('prize'))
|
||||
if prize__sum['prize__sum'] is None:
|
||||
prize__sum['prize__sum'] = 0
|
||||
return "Tagesumsatz: {0:.2f} EUR".format(prize__sum['prize__sum'])
|
||||
+2
-2
@@ -25,6 +25,6 @@ urlpatterns = [
|
||||
path('<int:loc_pk>/account_modal/<pks>/confirm/', views.account_modal_confirm_view, name='account_modal_confirm'),
|
||||
# ex. /billard/api/v1/ (rest api)
|
||||
path('api/v1/', include(router.urls)),
|
||||
# ex. /billard/process_location_data/
|
||||
path('process_location_data/', views.process_location_data, name='process_location_data'),
|
||||
# ex. /billard/myaccount/
|
||||
path('my_account', views.UserUpdateView.as_view(), name='my_account'),
|
||||
]
|
||||
|
||||
+25
-9
@@ -1,23 +1,25 @@
|
||||
import ast
|
||||
import logging
|
||||
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.db.models import Sum
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render, redirect
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils import timezone
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import generic
|
||||
from django.views.generic import UpdateView
|
||||
from rest_framework import viewsets
|
||||
|
||||
from billard.models import LocationData, Location, Client, Accounting
|
||||
from billard.serializers import LocationDataSerializer, ClientUpdateLastSeenSerializer
|
||||
from billard.tasks import process_location_data
|
||||
from .forms import UserInformationUpdateForm
|
||||
from .tables import LocationTable, LocationAccountingTable
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LocationIndexView(generic.ListView):
|
||||
class LocationIndexView(LoginRequiredMixin, generic.ListView):
|
||||
template_name = 'billard/location_index.html'
|
||||
context_object_name = 'location_list'
|
||||
|
||||
@@ -25,8 +27,17 @@ class LocationIndexView(generic.ListView):
|
||||
"""Return the last five published questions."""
|
||||
return Location.objects.filter(users__id=self.request.user.id).order_by('code')
|
||||
|
||||
def get_context_data(self, *, object_list=None, **kwargs):
|
||||
context = super().get_context_data(object_list=object_list, **kwargs)
|
||||
table = LocationTable(self.get_queryset())
|
||||
user = self.request.user
|
||||
if user.has_perm('billard.change_accounting'):
|
||||
table = LocationAccountingTable(self.get_queryset())
|
||||
context['table'] = table
|
||||
return context
|
||||
|
||||
class LocationDetailView(generic.DetailView):
|
||||
|
||||
class LocationDetailView(LoginRequiredMixin, generic.DetailView):
|
||||
model = Location
|
||||
template_name = 'billard/location_detail.html'
|
||||
|
||||
@@ -67,7 +78,7 @@ class AccountingView(generic.ListView):
|
||||
def accounting_confirm(request, pk):
|
||||
if request.method == 'POST':
|
||||
if 'accountings' in request.POST:
|
||||
acc_ids = ast.literal_eval(request.POST['accountings'])
|
||||
acc_ids = request.POST.getlist('list_acc_id')
|
||||
if len(acc_ids) > 0:
|
||||
Accounting.objects.filter(id__in=acc_ids).update(
|
||||
billed=True,
|
||||
@@ -113,6 +124,11 @@ class ClientUpdateLastSeenViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = ClientUpdateLastSeenSerializer
|
||||
|
||||
|
||||
def process_location_data(request):
|
||||
process_location_data()
|
||||
return HttpResponse('DONE')
|
||||
@method_decorator(login_required, name='dispatch')
|
||||
class UserUpdateView(UpdateView):
|
||||
form_class = UserInformationUpdateForm
|
||||
template_name = 'registration/my_account.html'
|
||||
success_url = reverse_lazy('billard:my_account')
|
||||
|
||||
def get_object(self):
|
||||
return self.request.user
|
||||
|
||||
@@ -35,10 +35,13 @@ INSTALLED_APPS = [
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
# third party apps
|
||||
'crispy_forms',
|
||||
'debug_toolbar',
|
||||
'django_tables2',
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
'debug_toolbar',
|
||||
'crispy_forms',
|
||||
# carom apps
|
||||
'billard',
|
||||
]
|
||||
|
||||
@@ -160,10 +163,12 @@ EMAIL_PORT = 25
|
||||
URL_LOCATION_PROCESSOR = 'http://127.0.0.1:8000/billard/process_locationdata'
|
||||
|
||||
PRODUCT_INFO = 'CAROM-DEV'
|
||||
PRODUCT_VERSION = 'v 0.5.1'
|
||||
PRODUCT_VERSION = 'v 1.0.0'
|
||||
|
||||
INTERNAL_IPS = ['127.0.0.1']
|
||||
|
||||
DJANGO_TABLES2_TEMPLATE = 'django_tables2/bootstrap4.html'
|
||||
|
||||
try:
|
||||
from local_settings import *
|
||||
except ImportError:
|
||||
|
||||
@@ -24,8 +24,6 @@ urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||
path('billard/', include('billard.urls')),
|
||||
path('login/', auth_views.login, name='login'),
|
||||
path('logout/', auth_views.logout, name='logout'),
|
||||
path('', include('django.contrib.auth.urls')),
|
||||
path('', RedirectView.as_view(url='billard/', permanent=False), name='index')
|
||||
]
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
Django<2.1
|
||||
django-crispy-forms==1.7.0
|
||||
django-extensions>=1.7.0
|
||||
djangorestframework>=3.6.0
|
||||
requests>=2.18.0
|
||||
django-debug-toolbar<2.0.0
|
||||
Vendored
-2050
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Vendored
-7
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
-330
@@ -1,330 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
||||
* Copyright 2011-2018 The Bootstrap Authors
|
||||
* Copyright 2011-2018 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-ms-overflow-style: scrollbar;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
@-ms-viewport {
|
||||
width: device-width;
|
||||
}
|
||||
|
||||
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #212529;
|
||||
text-align: left;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
[tabindex="-1"]:focus {
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title],
|
||||
abbr[data-original-title] {
|
||||
text-decoration: underline;
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: .5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #0056b3;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]) {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]):focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
-ms-overflow-style: scrollbar;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
color: #6c757d;
|
||||
text-align: left;
|
||||
caption-side: bottom;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
outline: 1px dotted;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
input {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
button,
|
||||
html [type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input[type="date"],
|
||||
input[type="time"],
|
||||
input[type="datetime-local"],
|
||||
input[type="month"] {
|
||||
-webkit-appearance: listbox;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: .5rem;
|
||||
font-size: 1.5rem;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type="search"] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
[type="search"]::-webkit-search-cancel-button,
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
||||
File diff suppressed because one or more lines are too long
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
||||
* Copyright 2011-2018 The Bootstrap Authors
|
||||
* Copyright 2011-2018 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
||||
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
||||
File diff suppressed because one or more lines are too long
Vendored
+1716
-804
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Vendored
+2
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
-6328
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Vendored
-7
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+1229
-874
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Vendored
+2
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Vendored
+2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -36,11 +36,6 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'billard:location_index' %}">Standorte</a>
|
||||
</li>
|
||||
{% if user.is_superuser %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/admin">Administration</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% if user.is_authenticated %}
|
||||
<ul class="navbar-nav ml-auto">
|
||||
@@ -50,8 +45,12 @@
|
||||
{{ user.username }}
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userMenu">
|
||||
<!-- <a class="dropdown-item" href="#">My account</a> -->
|
||||
<a class="disabled dropdown-item" href="#">{% settings_value "PRODUCT_VERSION" %}</a>
|
||||
<a class="dropdown-item" href="{% url 'billard:my_account' %}">My account</a>
|
||||
{% if user.is_superuser %}
|
||||
<a class="dropdown-item" href="/admin">Administration</a>
|
||||
{% endif %}
|
||||
<a class="disabled dropdown-item"
|
||||
href="#">{% settings_value "PRODUCT_VERSION" %}</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="{% url 'logout' %}">Log out</a>
|
||||
</div>
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
{% extends '_base_accounts.html' %}
|
||||
|
||||
{% extends '_base.html' %}
|
||||
{% load static from staticfiles %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block title %}login{% endblock %}
|
||||
{% load form_tags %}
|
||||
{% block title %}Anmelden{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="row justify-content-center" style="margin-top: 80px;">
|
||||
<div class="col-lg-4 col-md-6 col-sm-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Log in</h3>
|
||||
<form method="post" novalidate>
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-header text-center">
|
||||
<h3>{% settings_value "PRODUCT_INFO" %}</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Login</h3>
|
||||
<input type="hidden" name="next" value="{{ next }}">
|
||||
{{ form|crispy }}
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" class="btn btn-primary btn-block">Log in</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,21 @@
|
||||
{% extends '_base.html' %}
|
||||
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block title %}My account{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
<li class="breadcrumb-item active">My account</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-8 col-sm-10">
|
||||
<form method="post" novalidate>
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<button type="submit" class="btn btn-success">Save changes</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user