Merge branch 'release/1.0.0'
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -8,3 +8,5 @@ build/
 | 
			
		||||
*/*/__pycache__/
 | 
			
		||||
caromserver/local_settings.py
 | 
			
		||||
/staticfiles/
 | 
			
		||||
.venv/
 | 
			
		||||
update.sh
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								Pipfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								Pipfile
									
									
									
									
									
										Normal file
									
								
							@@ -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"
 | 
			
		||||
							
								
								
									
										126
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -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')
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								billard/forms.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								billard/forms.py
									
									
									
									
									
										Normal file
									
								
							@@ -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',)
 | 
			
		||||
							
								
								
									
										24
									
								
								billard/migrations/0027_clientdata.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								billard/migrations/0027_clientdata.py
									
									
									
									
									
										Normal file
									
								
							@@ -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',
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -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')
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								billard/tables.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								billard/tables.py
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
@@ -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,30 +15,33 @@
 | 
			
		||||
 | 
			
		||||
    {{ pk }}
 | 
			
		||||
 | 
			
		||||
    <table class="table">
 | 
			
		||||
        <tr>
 | 
			
		||||
            <th>Start-Datum:</th>
 | 
			
		||||
            <th>Stop-Datum:</th>
 | 
			
		||||
            <th>Preis Normal:</th>
 | 
			
		||||
            <th>Preis Happy Hour:</th>
 | 
			
		||||
            <th>Preis gesamt:</th>
 | 
			
		||||
        </tr>
 | 
			
		||||
        {% for acc in accounting %}
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>{{ acc.time_from }}</td>
 | 
			
		||||
                <td>{{ acc.time_to }}</td>
 | 
			
		||||
                <td>{{ acc.prize_normal }}</td>
 | 
			
		||||
                <td>{{ acc.prize_hh }}</td>
 | 
			
		||||
                <td>{{ acc.prize }}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
    </table>
 | 
			
		||||
 | 
			
		||||
    <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>
 | 
			
		||||
                <th>Preis Happy Hour:</th>
 | 
			
		||||
                <th>Preis gesamt:</th>
 | 
			
		||||
            </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>
 | 
			
		||||
                    <td>{{ acc.prize_hh }}</td>
 | 
			
		||||
                    <td>{{ acc.prize }}</td>
 | 
			
		||||
                </tr>
 | 
			
		||||
            {% endfor %}
 | 
			
		||||
        </table>
 | 
			
		||||
        <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 %}
 | 
			
		||||
 | 
			
		||||
    <h2>Bitte Standort auswählen:</h2>
 | 
			
		||||
    {% 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 %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								billard/templates/billard/tc_accounting_detail.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								billard/templates/billard/tc_accounting_detail.html
									
									
									
									
									
										Normal file
									
								
							@@ -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>
 | 
			
		||||
							
								
								
									
										3
									
								
								billard/templates/billard/tc_location_detail.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								billard/templates/billard/tc_location_detail.html
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								billard/templatetags/display_daily_sale.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								billard/templatetags/display_daily_sale.py
									
									
									
									
									
										Normal file
									
								
							@@ -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'])
 | 
			
		||||
@@ -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'),
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
							
								
								
									
										2050
									
								
								static/css/bootstrap-grid.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2050
									
								
								static/css/bootstrap-grid.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										7
									
								
								static/css/bootstrap-grid.min.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								static/css/bootstrap-grid.min.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										330
									
								
								static/css/bootstrap-reboot.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										330
									
								
								static/css/bootstrap-reboot.css
									
									
									
									
										vendored
									
									
								
							@@ -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
											
										
									
								
							
							
								
								
									
										8
									
								
								static/css/bootstrap-reboot.min.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								static/css/bootstrap-reboot.min.css
									
									
									
									
										vendored
									
									
								
							@@ -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
											
										
									
								
							
							
								
								
									
										2524
									
								
								static/css/bootstrap.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2524
									
								
								static/css/bootstrap.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										4
									
								
								static/css/bootstrap.min.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								static/css/bootstrap.min.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										6328
									
								
								static/js/bootstrap.bundle.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6328
									
								
								static/js/bootstrap.bundle.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										7
									
								
								static/js/bootstrap.bundle.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								static/js/bootstrap.bundle.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2207
									
								
								static/js/bootstrap.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2207
									
								
								static/js/bootstrap.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										4
									
								
								static/js/bootstrap.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								static/js/bootstrap.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										8269
									
								
								static/js/jquery-3.3.1.slim.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8269
									
								
								static/js/jquery-3.3.1.slim.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2
									
								
								static/js/jquery-3.3.1.slim.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								static/js/jquery-3.3.1.slim.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								static/js/jquery-3.3.1.slim.min.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								static/js/jquery-3.3.1.slim.min.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												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 %}
 | 
			
		||||
            <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>
 | 
			
		||||
                    </form>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            </form>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										21
									
								
								templates/registration/my_account.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								templates/registration/my_account.html
									
									
									
									
									
										Normal file
									
								
							@@ -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