Compare commits
No commits in common. "master" and "1.0.0" have entirely different histories.
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,4 +10,3 @@ caromserver/local_settings.py
|
||||
/staticfiles/
|
||||
.venv/
|
||||
update.sh
|
||||
Pipfile.lock
|
||||
|
200
INSTALL.md
200
INSTALL.md
@ -1,200 +0,0 @@
|
||||
# Preparing
|
||||
|
||||
- [ ] Install and configure Mailsystem (postfix) so it is possible to send mails
|
||||
- [ ] Install python ```apt install python3 python3-pip python3-venv python3-virtualenv```
|
||||
- [ ] Install uwsgi ```apt install uwsgi uwsgi-plugin-python3```
|
||||
- [ ] Install and configure mariadb-server ```mysql_secure_installation```
|
||||
- [ ] Install and configure nginx und let's encrypt or similar
|
||||
- [ ] Install git ```apt install git```
|
||||
|
||||
|
||||
# Installation
|
||||
|
||||
- [ ] Create databases for carom and carom-int
|
||||
|
||||
```
|
||||
-- carom
|
||||
CREATE DATABASE carom DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
|
||||
CREATE USER 'carom'@'localhost' IDENTIFIED BY 'xxx';
|
||||
GRANT ALL PRIVILEGES ON carom.* TO 'carom'@'localhost';
|
||||
CREATE DATABASE `carom-int` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
|
||||
CREATE USER 'carom-int'@'localhost' IDENTIFIED BY 'xxx';
|
||||
GRANT ALL PRIVILEGES ON `carom-int`.* TO 'carom-int'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
```
|
||||
|
||||
Passphrases should be replaced by useful characters
|
||||
|
||||
- [ ] Create systemd unit file for uwsgi (/etc/systemd/system/uwsgi.service):
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=uWSGI Emperor service
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown www-data:www-data /run/uwsgi'
|
||||
ExecStart=/usr/bin/uwsgi --emperor /etc/uwsgi/apps-enabled
|
||||
Restart=always
|
||||
KillSignal=SIGQUIT
|
||||
Type=notify
|
||||
NotifyAccess=all
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
- [ ] Reread systemd configs for uwsgi
|
||||
|
||||
```
|
||||
systemctl daemon-reload
|
||||
systemctl enable uwsgi.service
|
||||
systemctl restart uwsgi.service
|
||||
```
|
||||
|
||||
- [ ] Checkout carom
|
||||
|
||||
```
|
||||
cd /srv
|
||||
git clone http://git.einsle.de/carom/carom-server.git carom
|
||||
git clone http://git.einsle.de/carom/carom-server.git carom-int
|
||||
cd carom-int
|
||||
git checkout develop
|
||||
git pull
|
||||
cd ..
|
||||
```
|
||||
|
||||
- [ ] Install pipenv
|
||||
|
||||
```
|
||||
pip3 install –upgrade pipenv
|
||||
```
|
||||
|
||||
- [ ] Install mysqlclient
|
||||
|
||||
```
|
||||
apt install libmariadbclient-dev
|
||||
```
|
||||
|
||||
In environments carom run
|
||||
|
||||
```
|
||||
pipenv install mysqlclient
|
||||
```
|
||||
|
||||
```
|
||||
git checkout -- Pipfile Pipfile.lock
|
||||
git status
|
||||
```
|
||||
|
||||
- [ ] Create caromserver/local_settings.py for both environments:
|
||||
|
||||
```
|
||||
cd caromserver
|
||||
cp local_settings_example.py local_settings.py
|
||||
vi local_settings.py
|
||||
ALLOWED_HOSTS, ADMINS, DEBUG should be filled
|
||||
SECRET_KEY use pwgen 50 1 to create content for
|
||||
DATABASES settings
|
||||
cd ..
|
||||
mkdir .venv
|
||||
pipenv install
|
||||
pipenv run python manage.py migrate
|
||||
pipenv run python manage.py collectstatic
|
||||
```
|
||||
|
||||
Do it for /srv/carom and /srv/carom-int
|
||||
|
||||
- [ ] Create Superuser Accounts using:
|
||||
|
||||
```
|
||||
pipenv run python manage.py createsuperuser
|
||||
```
|
||||
|
||||
- [ ] Create config File for uwsgi/carom
|
||||
|
||||
```
|
||||
# carom...ini file
|
||||
[uwsgi]
|
||||
plugin = python3
|
||||
chdir = /srv/carom/
|
||||
module = caromserver.wsgi:application
|
||||
home = /srv/carom/.venv/
|
||||
master = true
|
||||
processes = 5
|
||||
vacuum = true
|
||||
uid = www-data
|
||||
gid = www-data
|
||||
workers = 2
|
||||
socket = /run/uwsgi/carom.socket
|
||||
chmod-socket = 660
|
||||
log-date = true
|
||||
```
|
||||
|
||||
Create it for /etc/uwsgi/apps-available/carom.ini and carom-int.ini and link it
|
||||
to /etc/uwsgi/apps-enabled/
|
||||
|
||||
```
|
||||
systemctl restart uwsgi.service
|
||||
```
|
||||
|
||||
Show at syslog for errors and fix it.
|
||||
|
||||
- [ ] Create Config File for nginx/carom
|
||||
|
||||
```
|
||||
upstream socket_carom {
|
||||
server unix:///run/uwsgi/carom.socket;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name carom...;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
server_name carom...;
|
||||
ssl_certificate /etc/ssl/certs/xxx;
|
||||
ssl_certificate_key /etc/ssl/private/xxx;
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
charset utf-8;
|
||||
client_max_body_size 75M; # adjust to taste
|
||||
location /media {
|
||||
alias /srv/carom/media;
|
||||
}
|
||||
location /static {
|
||||
alias /srv/carom/staticfiles;
|
||||
}
|
||||
location / {
|
||||
uwsgi_pass socket_carom;
|
||||
include /etc/nginx/uwsgi_params;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Create it for /etc/ngin/sites-available/carom... and carom-int... and link it
|
||||
to /etc/ngin/sites-enabled/
|
||||
|
||||
Path to certificates must be modified.
|
||||
|
||||
```
|
||||
systemctl restart nginx
|
||||
```
|
||||
|
||||
- [ ] Create update.sh in carom and carom-int root dir
|
||||
|
||||
```
|
||||
pushd /srv/carom/
|
||||
git pull
|
||||
pipenv update
|
||||
pipenv run python manage.py migrate
|
||||
pipenv run python manage.py collectstatic --noinput
|
||||
touch /etc/uwsgi/apps-enabled/carom.ini
|
||||
popd
|
||||
```
|
||||
|
||||
Path to uwsgi config file (in apps-enabled) musst be matching.
|
18
Pipfile
18
Pipfile
@ -6,11 +6,13 @@ verify_ssl = true
|
||||
[dev-packages]
|
||||
|
||||
[packages]
|
||||
django = "==3.2.8"
|
||||
django-crispy-forms = "==1.13.0"
|
||||
django-debug-toolbar = "==3.2.2"
|
||||
django-extensions = "==3.1.3"
|
||||
django-tables2 = "==2.4.1"
|
||||
djangorestframework = "==3.12.4"
|
||||
requests = "==2.26.0"
|
||||
django-simple-task = "==0.1.2"
|
||||
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": {}
|
||||
}
|
@ -1 +0,0 @@
|
||||
default_app_config = 'billard.apps.BillardConfig'
|
@ -32,14 +32,12 @@ class LocationAdmin(admin.ModelAdmin):
|
||||
@admin.register(Client)
|
||||
class ClientAdmin(admin.ModelAdmin):
|
||||
list_display = ('uuid', 'location', 'report_user', 'last_seen')
|
||||
list_filter = ('location', 'report_user')
|
||||
fields = ['location', 'uuid', 'report_user', 'last_seen']
|
||||
|
||||
|
||||
@admin.register(ClientData)
|
||||
class ClientDataAdmin(admin.ModelAdmin):
|
||||
list_display = ('uuid', 'last_seen')
|
||||
list_filter = ('uuid', 'last_seen')
|
||||
fields = ['location', 'last_seen']
|
||||
|
||||
|
||||
@ -60,7 +58,6 @@ class LocationDataAdmin(admin.ModelAdmin):
|
||||
return redirect('admin:billard_locationdata_changelist')
|
||||
|
||||
list_display = ('client_id', 'desk_no', 'tst', 'on_off', 'processed', 'error_msg')
|
||||
list_filter = ('client_id', 'desk_no', 'processed')
|
||||
fields = ['client_id', 'desk_no', 'tst', 'on_off', 'processed', 'error_msg']
|
||||
|
||||
|
||||
@ -80,21 +77,14 @@ class DeskAdminForm(forms.ModelForm):
|
||||
class DeskAdmin(admin.ModelAdmin):
|
||||
form = DeskAdminForm
|
||||
list_display = ('client', 'desk_no', 'name', 'enabled', 'prize', 'prize_hh')
|
||||
list_filter = ('client', 'desk_no', 'enabled', 'prize', 'prize_hh')
|
||||
|
||||
|
||||
@admin.register(Accounting)
|
||||
class AccountingAdmin(admin.ModelAdmin):
|
||||
list_display = ('desk', 'time_from', 'time_to', 'prize', 'billed', 'account_user', 'account_tst')
|
||||
list_filter = ('desk__client__location', 'account_user', 'account_tst', 'billed')
|
||||
actions = ['mark_billed']
|
||||
|
||||
def has_add_permission(self, request):
|
||||
if request.user.username == 'reinsle':
|
||||
return True
|
||||
return False
|
||||
|
||||
@admin.action(description='Ausgewählte Buchhaltungseinträge als Abgerechnet markieren')
|
||||
def mark_billed(self, request, queryset):
|
||||
queryset.update(billed=True)
|
||||
|
||||
|
@ -2,8 +2,4 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class BillardConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'billard'
|
||||
|
||||
def ready(self):
|
||||
import billard.signals #noqa
|
||||
|
@ -1,9 +0,0 @@
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from billard.tasks import process_location_data
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Process location data objects'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
process_location_data
|
@ -1,43 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2021-10-24 11:06
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('billard', '0027_clientdata'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='accounting',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='client',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='clientdata',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='desk',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='locationdata',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||
),
|
||||
]
|
@ -1,11 +0,0 @@
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from django_simple_task import defer
|
||||
|
||||
from billard.models import LocationData
|
||||
from billard.tasks import process_location_data
|
||||
|
||||
|
||||
@receiver(post_save, sender=LocationData)
|
||||
def update_location_data(sender, instance, **kwargs):
|
||||
defer(process_location_data(sender=sender, kwargs=kwargs))
|
@ -1,2 +1,2 @@
|
||||
{% load static %}
|
||||
{% load static from staticfiles %}
|
||||
<a href="{% url 'billard:accounting_detail' record.id %}" class="btn btn-outline-danger btn-sm">Abrechnen</a>
|
@ -1,3 +1,3 @@
|
||||
{% load static %}
|
||||
{% 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>
|
@ -1,4 +1,4 @@
|
||||
from datetime import datetime, timedelta, date
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from django import template
|
||||
from django.db.models import Sum
|
||||
@ -10,14 +10,8 @@ register = template.Library()
|
||||
|
||||
@register.filter(is_safe=True)
|
||||
def display_daily_sale(location):
|
||||
date = datetime.now().replace(hour=6, minute=0, second=0, microsecond=0)
|
||||
now = datetime.now()
|
||||
if now < date:
|
||||
start_date = date - timedelta(days=1)
|
||||
end_date = date
|
||||
else:
|
||||
start_date = date
|
||||
end_date = date + timedelta(days=1)
|
||||
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:
|
||||
|
@ -1,18 +0,0 @@
|
||||
"""
|
||||
ASGI config for caromserver project.
|
||||
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
from django_simple_task import django_simple_task_middlware
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'caromserver.settings')
|
||||
|
||||
application = get_asgi_application()
|
||||
application = django_simple_task_middlware(application)
|
@ -1,9 +1,9 @@
|
||||
import os
|
||||
|
||||
SECRET_KEY = '@-9++2z_6%^vr(f0wax0aq8-pd@0u$*))w!5l^sv#wxrn7k!v-'
|
||||
DEBUG = False
|
||||
ALLOWED_HOSTS = ['*']
|
||||
ADMINS = [
|
||||
('Robert Einsle', 'robert@einsle.de'),
|
||||
]
|
||||
DEBUG = True
|
||||
ALLOWED_HOSTS = ['carom-dev.einsle.de']
|
||||
ADMINS = [('Robert Einsle', 'robert@einsle.de'),]
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
@ -18,16 +18,16 @@ DATABASES = {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC_ROOT = "/srv/../staticfiles/"
|
||||
STATIC_ROOT = "/srv/carom-dev/carom-server/staticfiles/"
|
||||
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
EMAIL_HOST = 'mail.server.tld'
|
||||
EMAIL_HOST = 'mail.einsle.de'
|
||||
EMAIL_PORT = 587
|
||||
EMAIL_HOST_USER = 'username'
|
||||
EMAIL_HOST_PASSWORD = 'password'
|
||||
EMAIL_HOST_USER = 'relay@einsle.de'
|
||||
EMAIL_HOST_PASSWORD = 'Boaghi0thaiH'
|
||||
EMAIL_USE_TLS = True
|
||||
DEFAULT_FROM_EMAIL = "noreply@carom.de"
|
||||
DEFAULT_FROM_EMAIL = "webmaster@einsle.de"
|
||||
|
||||
URL_LOCATION_PROCESSOR = 'https://<carom-server-tld>/billard/process_locationdata'
|
||||
URL_LOCATION_PROCESSOR = 'https://carom-dev.einsle.de/billard/process_locationdata'
|
||||
|
||||
PRODUCT_INFO = 'carom'
|
||||
PRODUCT_INFO = 'carom-dev'
|
||||
|
@ -22,7 +22,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
SECRET_KEY = '@-9++2z_6%^vr(f0wax0aq8-pd@0u$*))w!5l^sv#wxrn7k!v-'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
@ -38,7 +38,6 @@ INSTALLED_APPS = [
|
||||
# third party apps
|
||||
'crispy_forms',
|
||||
'debug_toolbar',
|
||||
'django_simple_task',
|
||||
'django_tables2',
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
@ -163,15 +162,13 @@ EMAIL_PORT = 25
|
||||
|
||||
URL_LOCATION_PROCESSOR = 'http://127.0.0.1:8000/billard/process_locationdata'
|
||||
|
||||
PRODUCT_INFO = 'CAROM'
|
||||
PRODUCT_VERSION = 'v 1.0.5'
|
||||
PRODUCT_INFO = 'CAROM-DEV'
|
||||
PRODUCT_VERSION = 'v 1.0.0'
|
||||
|
||||
INTERNAL_IPS = ['127.0.0.1']
|
||||
|
||||
DJANGO_TABLES2_TEMPLATE = 'django_tables2/bootstrap4.html'
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
|
||||
try:
|
||||
from local_settings import *
|
||||
except ImportError:
|
||||
|
@ -4,13 +4,13 @@ WSGI config for caromserver project.
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
|
||||
https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'caromserver.settings')
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "caromserver.settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
|
24
manage.py
24
manage.py
@ -1,22 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'caromserver.settings')
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "caromserver.settings")
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
except ImportError:
|
||||
# The above import may fail for some other reason. Ensure that the
|
||||
# issue is really that Django is missing to avoid masking other
|
||||
# exceptions on Python 2.
|
||||
try:
|
||||
import django
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
)
|
||||
raise
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
15052
static/css/bootstrap.css
vendored
15052
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
12
static/css/bootstrap.min.css
vendored
12
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
Binary file not shown.
Before Width: | Height: | Size: 66 KiB |
6327
static/js/bootstrap.js
vendored
6327
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
8
static/js/bootstrap.min.js
vendored
8
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
326
static/js/html5shiv.js
vendored
326
static/js/html5shiv.js
vendored
@ -1,326 +0,0 @@
|
||||
/**
|
||||
* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
|
||||
*/
|
||||
;(function(window, document) {
|
||||
/*jshint evil:true */
|
||||
/** version */
|
||||
var version = '3.7.3';
|
||||
|
||||
/** Preset options */
|
||||
var options = window.html5 || {};
|
||||
|
||||
/** Used to skip problem elements */
|
||||
var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
|
||||
|
||||
/** Not all elements can be cloned in IE **/
|
||||
var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
|
||||
|
||||
/** Detect whether the browser supports default html5 styles */
|
||||
var supportsHtml5Styles;
|
||||
|
||||
/** Name of the expando, to work with multiple documents or to re-shiv one document */
|
||||
var expando = '_html5shiv';
|
||||
|
||||
/** The id for the the documents expando */
|
||||
var expanID = 0;
|
||||
|
||||
/** Cached data for each document */
|
||||
var expandoData = {};
|
||||
|
||||
/** Detect whether the browser supports unknown elements */
|
||||
var supportsUnknownElements;
|
||||
|
||||
(function() {
|
||||
try {
|
||||
var a = document.createElement('a');
|
||||
a.innerHTML = '<xyz></xyz>';
|
||||
//if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
|
||||
supportsHtml5Styles = ('hidden' in a);
|
||||
|
||||
supportsUnknownElements = a.childNodes.length == 1 || (function() {
|
||||
// assign a false positive if unable to shiv
|
||||
(document.createElement)('a');
|
||||
var frag = document.createDocumentFragment();
|
||||
return (
|
||||
typeof frag.cloneNode == 'undefined' ||
|
||||
typeof frag.createDocumentFragment == 'undefined' ||
|
||||
typeof frag.createElement == 'undefined'
|
||||
);
|
||||
}());
|
||||
} catch(e) {
|
||||
// assign a false positive if detection fails => unable to shiv
|
||||
supportsHtml5Styles = true;
|
||||
supportsUnknownElements = true;
|
||||
}
|
||||
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Creates a style sheet with the given CSS text and adds it to the document.
|
||||
* @private
|
||||
* @param {Document} ownerDocument The document.
|
||||
* @param {String} cssText The CSS text.
|
||||
* @returns {StyleSheet} The style element.
|
||||
*/
|
||||
function addStyleSheet(ownerDocument, cssText) {
|
||||
var p = ownerDocument.createElement('p'),
|
||||
parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
|
||||
|
||||
p.innerHTML = 'x<style>' + cssText + '</style>';
|
||||
return parent.insertBefore(p.lastChild, parent.firstChild);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of `html5.elements` as an array.
|
||||
* @private
|
||||
* @returns {Array} An array of shived element node names.
|
||||
*/
|
||||
function getElements() {
|
||||
var elements = html5.elements;
|
||||
return typeof elements == 'string' ? elements.split(' ') : elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends the built-in list of html5 elements
|
||||
* @memberOf html5
|
||||
* @param {String|Array} newElements whitespace separated list or array of new element names to shiv
|
||||
* @param {Document} ownerDocument The context document.
|
||||
*/
|
||||
function addElements(newElements, ownerDocument) {
|
||||
var elements = html5.elements;
|
||||
if(typeof elements != 'string'){
|
||||
elements = elements.join(' ');
|
||||
}
|
||||
if(typeof newElements != 'string'){
|
||||
newElements = newElements.join(' ');
|
||||
}
|
||||
html5.elements = elements +' '+ newElements;
|
||||
shivDocument(ownerDocument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data associated to the given document
|
||||
* @private
|
||||
* @param {Document} ownerDocument The document.
|
||||
* @returns {Object} An object of data.
|
||||
*/
|
||||
function getExpandoData(ownerDocument) {
|
||||
var data = expandoData[ownerDocument[expando]];
|
||||
if (!data) {
|
||||
data = {};
|
||||
expanID++;
|
||||
ownerDocument[expando] = expanID;
|
||||
expandoData[expanID] = data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a shived element for the given nodeName and document
|
||||
* @memberOf html5
|
||||
* @param {String} nodeName name of the element
|
||||
* @param {Document|DocumentFragment} ownerDocument The context document.
|
||||
* @returns {Object} The shived element.
|
||||
*/
|
||||
function createElement(nodeName, ownerDocument, data){
|
||||
if (!ownerDocument) {
|
||||
ownerDocument = document;
|
||||
}
|
||||
if(supportsUnknownElements){
|
||||
return ownerDocument.createElement(nodeName);
|
||||
}
|
||||
if (!data) {
|
||||
data = getExpandoData(ownerDocument);
|
||||
}
|
||||
var node;
|
||||
|
||||
if (data.cache[nodeName]) {
|
||||
node = data.cache[nodeName].cloneNode();
|
||||
} else if (saveClones.test(nodeName)) {
|
||||
node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
|
||||
} else {
|
||||
node = data.createElem(nodeName);
|
||||
}
|
||||
|
||||
// Avoid adding some elements to fragments in IE < 9 because
|
||||
// * Attributes like `name` or `type` cannot be set/changed once an element
|
||||
// is inserted into a document/fragment
|
||||
// * Link elements with `src` attributes that are inaccessible, as with
|
||||
// a 403 response, will cause the tab/window to crash
|
||||
// * Script elements appended to fragments will execute when their `src`
|
||||
// or `text` property is set
|
||||
return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a shived DocumentFragment for the given document
|
||||
* @memberOf html5
|
||||
* @param {Document} ownerDocument The context document.
|
||||
* @returns {Object} The shived DocumentFragment.
|
||||
*/
|
||||
function createDocumentFragment(ownerDocument, data){
|
||||
if (!ownerDocument) {
|
||||
ownerDocument = document;
|
||||
}
|
||||
if(supportsUnknownElements){
|
||||
return ownerDocument.createDocumentFragment();
|
||||
}
|
||||
data = data || getExpandoData(ownerDocument);
|
||||
var clone = data.frag.cloneNode(),
|
||||
i = 0,
|
||||
elems = getElements(),
|
||||
l = elems.length;
|
||||
for(;i<l;i++){
|
||||
clone.createElement(elems[i]);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shivs the `createElement` and `createDocumentFragment` methods of the document.
|
||||
* @private
|
||||
* @param {Document|DocumentFragment} ownerDocument The document.
|
||||
* @param {Object} data of the document.
|
||||
*/
|
||||
function shivMethods(ownerDocument, data) {
|
||||
if (!data.cache) {
|
||||
data.cache = {};
|
||||
data.createElem = ownerDocument.createElement;
|
||||
data.createFrag = ownerDocument.createDocumentFragment;
|
||||
data.frag = data.createFrag();
|
||||
}
|
||||
|
||||
|
||||
ownerDocument.createElement = function(nodeName) {
|
||||
//abort shiv
|
||||
if (!html5.shivMethods) {
|
||||
return data.createElem(nodeName);
|
||||
}
|
||||
return createElement(nodeName, ownerDocument, data);
|
||||
};
|
||||
|
||||
ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
|
||||
'var n=f.cloneNode(),c=n.createElement;' +
|
||||
'h.shivMethods&&(' +
|
||||
// unroll the `createElement` calls
|
||||
getElements().join().replace(/[\w\-:]+/g, function(nodeName) {
|
||||
data.createElem(nodeName);
|
||||
data.frag.createElement(nodeName);
|
||||
return 'c("' + nodeName + '")';
|
||||
}) +
|
||||
');return n}'
|
||||
)(html5, data.frag);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Shivs the given document.
|
||||
* @memberOf html5
|
||||
* @param {Document} ownerDocument The document to shiv.
|
||||
* @returns {Document} The shived document.
|
||||
*/
|
||||
function shivDocument(ownerDocument) {
|
||||
if (!ownerDocument) {
|
||||
ownerDocument = document;
|
||||
}
|
||||
var data = getExpandoData(ownerDocument);
|
||||
|
||||
if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
|
||||
data.hasCSS = !!addStyleSheet(ownerDocument,
|
||||
// corrects block display not defined in IE6/7/8/9
|
||||
'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' +
|
||||
// adds styling not present in IE6/7/8/9
|
||||
'mark{background:#FF0;color:#000}' +
|
||||
// hides non-rendered elements
|
||||
'template{display:none}'
|
||||
);
|
||||
}
|
||||
if (!supportsUnknownElements) {
|
||||
shivMethods(ownerDocument, data);
|
||||
}
|
||||
return ownerDocument;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The `html5` object is exposed so that more elements can be shived and
|
||||
* existing shiving can be detected on iframes.
|
||||
* @type Object
|
||||
* @example
|
||||
*
|
||||
* // options can be changed before the script is included
|
||||
* html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
|
||||
*/
|
||||
var html5 = {
|
||||
|
||||
/**
|
||||
* An array or space separated string of node names of the elements to shiv.
|
||||
* @memberOf html5
|
||||
* @type Array|String
|
||||
*/
|
||||
'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video',
|
||||
|
||||
/**
|
||||
* current version of html5shiv
|
||||
*/
|
||||
'version': version,
|
||||
|
||||
/**
|
||||
* A flag to indicate that the HTML5 style sheet should be inserted.
|
||||
* @memberOf html5
|
||||
* @type Boolean
|
||||
*/
|
||||
'shivCSS': (options.shivCSS !== false),
|
||||
|
||||
/**
|
||||
* Is equal to true if a browser supports creating unknown/HTML5 elements
|
||||
* @memberOf html5
|
||||
* @type boolean
|
||||
*/
|
||||
'supportsUnknownElements': supportsUnknownElements,
|
||||
|
||||
/**
|
||||
* A flag to indicate that the document's `createElement` and `createDocumentFragment`
|
||||
* methods should be overwritten.
|
||||
* @memberOf html5
|
||||
* @type Boolean
|
||||
*/
|
||||
'shivMethods': (options.shivMethods !== false),
|
||||
|
||||
/**
|
||||
* A string to describe the type of `html5` object ("default" or "default print").
|
||||
* @memberOf html5
|
||||
* @type String
|
||||
*/
|
||||
'type': 'default',
|
||||
|
||||
// shivs the document according to the specified `html5` object options
|
||||
'shivDocument': shivDocument,
|
||||
|
||||
//creates a shived element
|
||||
createElement: createElement,
|
||||
|
||||
//creates a shived documentFragment
|
||||
createDocumentFragment: createDocumentFragment,
|
||||
|
||||
//extends list of elements
|
||||
addElements: addElements
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// expose html5
|
||||
window.html5 = html5;
|
||||
|
||||
// shiv the document
|
||||
shivDocument(document);
|
||||
|
||||
if(typeof module == 'object' && module.exports){
|
||||
module.exports = html5;
|
||||
}
|
||||
|
||||
}(typeof window !== "undefined" ? window : this, document));
|
1718
static/js/jquery-3.5.1.js → static/js/jquery-3.3.1.js
vendored
1718
static/js/jquery-3.5.1.js → static/js/jquery-3.3.1.js
vendored
File diff suppressed because it is too large
Load Diff
2
static/js/jquery-3.3.1.min.js
vendored
Normal file
2
static/js/jquery-3.3.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/js/jquery-3.3.1.min.map
Normal file
1
static/js/jquery-3.3.1.min.map
Normal file
File diff suppressed because one or more lines are too long
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
2
static/js/jquery-3.5.1.min.js
vendored
2
static/js/jquery-3.5.1.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
2
static/js/jquery-3.6.0.min.js
vendored
2
static/js/jquery-3.6.0.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
13
static/js/npm.js
Normal file
13
static/js/npm.js
Normal file
@ -0,0 +1,13 @@
|
||||
// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
|
||||
require('../../js/transition.js')
|
||||
require('../../js/alert.js')
|
||||
require('../../js/button.js')
|
||||
require('../../js/carousel.js')
|
||||
require('../../js/collapse.js')
|
||||
require('../../js/dropdown.js')
|
||||
require('../../js/modal.js')
|
||||
require('../../js/tooltip.js')
|
||||
require('../../js/popover.js')
|
||||
require('../../js/scrollspy.js')
|
||||
require('../../js/tab.js')
|
||||
require('../../js/affix.js')
|
4087
static/js/popper.js
4087
static/js/popper.js
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
9
static/js/popper.min.js
vendored
9
static/js/popper.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
@ -1,237 +0,0 @@
|
||||
/*! Respond.js v1.4.2: min/max-width media query polyfill
|
||||
* Copyright 2014 Scott Jehl
|
||||
* Licensed under MIT
|
||||
* https://j.mp/respondjs */
|
||||
|
||||
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
|
||||
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
|
||||
(function(w) {
|
||||
"use strict";
|
||||
w.matchMedia = w.matchMedia || function(doc, undefined) {
|
||||
var bool, docElem = doc.documentElement, refNode = docElem.firstElementChild || docElem.firstChild, fakeBody = doc.createElement("body"), div = doc.createElement("div");
|
||||
div.id = "mq-test-1";
|
||||
div.style.cssText = "position:absolute;top:-100em";
|
||||
fakeBody.style.background = "none";
|
||||
fakeBody.appendChild(div);
|
||||
return function(q) {
|
||||
div.innerHTML = '­<style media="' + q + '"> #mq-test-1 { width: 42px; }</style>';
|
||||
docElem.insertBefore(fakeBody, refNode);
|
||||
bool = div.offsetWidth === 42;
|
||||
docElem.removeChild(fakeBody);
|
||||
return {
|
||||
matches: bool,
|
||||
media: q
|
||||
};
|
||||
};
|
||||
}(w.document);
|
||||
})(this);
|
||||
|
||||
(function(w) {
|
||||
"use strict";
|
||||
var respond = {};
|
||||
w.respond = respond;
|
||||
respond.update = function() {};
|
||||
var requestQueue = [], xmlHttp = function() {
|
||||
var xmlhttpmethod = false;
|
||||
try {
|
||||
xmlhttpmethod = new w.XMLHttpRequest();
|
||||
} catch (e) {
|
||||
xmlhttpmethod = new w.ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
return function() {
|
||||
return xmlhttpmethod;
|
||||
};
|
||||
}(), ajax = function(url, callback) {
|
||||
var req = xmlHttp();
|
||||
if (!req) {
|
||||
return;
|
||||
}
|
||||
req.open("GET", url, true);
|
||||
req.onreadystatechange = function() {
|
||||
if (req.readyState !== 4 || req.status !== 200 && req.status !== 304) {
|
||||
return;
|
||||
}
|
||||
callback(req.responseText);
|
||||
};
|
||||
if (req.readyState === 4) {
|
||||
return;
|
||||
}
|
||||
req.send(null);
|
||||
}, isUnsupportedMediaQuery = function(query) {
|
||||
return query.replace(respond.regex.minmaxwh, "").match(respond.regex.other);
|
||||
};
|
||||
respond.ajax = ajax;
|
||||
respond.queue = requestQueue;
|
||||
respond.unsupportedmq = isUnsupportedMediaQuery;
|
||||
respond.regex = {
|
||||
media: /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,
|
||||
keyframes: /@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,
|
||||
comments: /\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,
|
||||
urls: /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,
|
||||
findStyles: /@media *([^\{]+)\{([\S\s]+?)$/,
|
||||
only: /(only\s+)?([a-zA-Z]+)\s?/,
|
||||
minw: /\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,
|
||||
maxw: /\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,
|
||||
minmaxwh: /\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,
|
||||
other: /\([^\)]*\)/g
|
||||
};
|
||||
respond.mediaQueriesSupported = w.matchMedia && w.matchMedia("only all") !== null && w.matchMedia("only all").matches;
|
||||
if (respond.mediaQueriesSupported) {
|
||||
return;
|
||||
}
|
||||
var doc = w.document, docElem = doc.documentElement, mediastyles = [], rules = [], appendedEls = [], parsedSheets = {}, resizeThrottle = 30, head = doc.getElementsByTagName("head")[0] || docElem, base = doc.getElementsByTagName("base")[0], links = head.getElementsByTagName("link"), lastCall, resizeDefer, eminpx, getEmValue = function() {
|
||||
var ret, div = doc.createElement("div"), body = doc.body, originalHTMLFontSize = docElem.style.fontSize, originalBodyFontSize = body && body.style.fontSize, fakeUsed = false;
|
||||
div.style.cssText = "position:absolute;font-size:1em;width:1em";
|
||||
if (!body) {
|
||||
body = fakeUsed = doc.createElement("body");
|
||||
body.style.background = "none";
|
||||
}
|
||||
docElem.style.fontSize = "100%";
|
||||
body.style.fontSize = "100%";
|
||||
body.appendChild(div);
|
||||
if (fakeUsed) {
|
||||
docElem.insertBefore(body, docElem.firstChild);
|
||||
}
|
||||
ret = div.offsetWidth;
|
||||
if (fakeUsed) {
|
||||
docElem.removeChild(body);
|
||||
} else {
|
||||
body.removeChild(div);
|
||||
}
|
||||
docElem.style.fontSize = originalHTMLFontSize;
|
||||
if (originalBodyFontSize) {
|
||||
body.style.fontSize = originalBodyFontSize;
|
||||
}
|
||||
ret = eminpx = parseFloat(ret);
|
||||
return ret;
|
||||
}, applyMedia = function(fromResize) {
|
||||
var name = "clientWidth", docElemProp = docElem[name], currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[name] || docElemProp, styleBlocks = {}, lastLink = links[links.length - 1], now = new Date().getTime();
|
||||
if (fromResize && lastCall && now - lastCall < resizeThrottle) {
|
||||
w.clearTimeout(resizeDefer);
|
||||
resizeDefer = w.setTimeout(applyMedia, resizeThrottle);
|
||||
return;
|
||||
} else {
|
||||
lastCall = now;
|
||||
}
|
||||
for (var i in mediastyles) {
|
||||
if (mediastyles.hasOwnProperty(i)) {
|
||||
var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw, minnull = min === null, maxnull = max === null, em = "em";
|
||||
if (!!min) {
|
||||
min = parseFloat(min) * (min.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
|
||||
}
|
||||
if (!!max) {
|
||||
max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
|
||||
}
|
||||
if (!thisstyle.hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max)) {
|
||||
if (!styleBlocks[thisstyle.media]) {
|
||||
styleBlocks[thisstyle.media] = [];
|
||||
}
|
||||
styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var j in appendedEls) {
|
||||
if (appendedEls.hasOwnProperty(j)) {
|
||||
if (appendedEls[j] && appendedEls[j].parentNode === head) {
|
||||
head.removeChild(appendedEls[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
appendedEls.length = 0;
|
||||
for (var k in styleBlocks) {
|
||||
if (styleBlocks.hasOwnProperty(k)) {
|
||||
var ss = doc.createElement("style"), css = styleBlocks[k].join("\n");
|
||||
ss.type = "text/css";
|
||||
ss.media = k;
|
||||
head.insertBefore(ss, lastLink.nextSibling);
|
||||
if (ss.styleSheet) {
|
||||
ss.styleSheet.cssText = css;
|
||||
} else {
|
||||
ss.appendChild(doc.createTextNode(css));
|
||||
}
|
||||
appendedEls.push(ss);
|
||||
}
|
||||
}
|
||||
}, translate = function(styles, href, media) {
|
||||
var qs = styles.replace(respond.regex.comments, "").replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0;
|
||||
href = href.substring(0, href.lastIndexOf("/"));
|
||||
var repUrls = function(css) {
|
||||
return css.replace(respond.regex.urls, "$1" + href + "$2$3");
|
||||
}, useMedia = !ql && media;
|
||||
if (href.length) {
|
||||
href += "/";
|
||||
}
|
||||
if (useMedia) {
|
||||
ql = 1;
|
||||
}
|
||||
for (var i = 0; i < ql; i++) {
|
||||
var fullq, thisq, eachq, eql;
|
||||
if (useMedia) {
|
||||
fullq = media;
|
||||
rules.push(repUrls(styles));
|
||||
} else {
|
||||
fullq = qs[i].match(respond.regex.findStyles) && RegExp.$1;
|
||||
rules.push(RegExp.$2 && repUrls(RegExp.$2));
|
||||
}
|
||||
eachq = fullq.split(",");
|
||||
eql = eachq.length;
|
||||
for (var j = 0; j < eql; j++) {
|
||||
thisq = eachq[j];
|
||||
if (isUnsupportedMediaQuery(thisq)) {
|
||||
continue;
|
||||
}
|
||||
mediastyles.push({
|
||||
media: thisq.split("(")[0].match(respond.regex.only) && RegExp.$2 || "all",
|
||||
rules: rules.length - 1,
|
||||
hasquery: thisq.indexOf("(") > -1,
|
||||
minw: thisq.match(respond.regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""),
|
||||
maxw: thisq.match(respond.regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || "")
|
||||
});
|
||||
}
|
||||
}
|
||||
applyMedia();
|
||||
}, makeRequests = function() {
|
||||
if (requestQueue.length) {
|
||||
var thisRequest = requestQueue.shift();
|
||||
ajax(thisRequest.href, function(styles) {
|
||||
translate(styles, thisRequest.href, thisRequest.media);
|
||||
parsedSheets[thisRequest.href] = true;
|
||||
w.setTimeout(function() {
|
||||
makeRequests();
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
}, ripCSS = function() {
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
var sheet = links[i], href = sheet.href, media = sheet.media, isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
|
||||
if (!!href && isCSS && !parsedSheets[href]) {
|
||||
if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
|
||||
translate(sheet.styleSheet.rawCssText, href, media);
|
||||
parsedSheets[href] = true;
|
||||
} else {
|
||||
if (!/^([a-zA-Z:]*\/\/)/.test(href) && !base || href.replace(RegExp.$1, "").split("/")[0] === w.location.host) {
|
||||
if (href.substring(0, 2) === "//") {
|
||||
href = w.location.protocol + href;
|
||||
}
|
||||
requestQueue.push({
|
||||
href: href,
|
||||
media: media
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
makeRequests();
|
||||
};
|
||||
ripCSS();
|
||||
respond.update = ripCSS;
|
||||
respond.getEmValue = getEmValue;
|
||||
function callMedia() {
|
||||
applyMedia(true);
|
||||
}
|
||||
if (w.addEventListener) {
|
||||
w.addEventListener("resize", callMedia, false);
|
||||
} else if (w.attachEvent) {
|
||||
w.attachEvent("onresize", callMedia);
|
||||
}
|
||||
})(this);
|
@ -8,7 +8,6 @@
|
||||
<meta name="description" content="carom billard management">
|
||||
<meta name="author" content="Robert Einsle <robert@einsle.de>">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="{% static 'img/billiard.ico' %}">
|
||||
{% block header %}
|
||||
{% endblock %}
|
||||
<!-- Bootstrap -->
|
||||
@ -25,43 +24,43 @@
|
||||
<body>
|
||||
{% block body %}
|
||||
<div class="wrapper">
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<nav class="navbar navbar-expand-sm navbar-dark bg-dark">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{% url 'index' %}">{% settings_value "PRODUCT_INFO" %}</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#mainMenu"
|
||||
aria-controls="mainMenu" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportetContent">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<div class="collapse navbar-collapse" id="mainMenu">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'billard:location_index' %}">Standorte</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% if user.is_authenticated %}
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="userMenu" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="userMenu" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
{{ user.username }}
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="userMenu">
|
||||
<li><a class="dropdown-item" href="{% url 'billard:my_account' %}">My account</a>
|
||||
</li>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userMenu">
|
||||
<a class="dropdown-item" href="{% url 'billard:my_account' %}">My account</a>
|
||||
{% if user.is_superuser %}
|
||||
<li><a class="dropdown-item" href="{% url 'admin:index' %}">Administration</a>
|
||||
</li>
|
||||
<a class="dropdown-item" href="/admin">Administration</a>
|
||||
{% endif %}
|
||||
<li><a class="dropdown-item" href="#">{% settings_value "PRODUCT_VERSION" %}</a>
|
||||
<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>
|
||||
</li>
|
||||
<li><a class="dropdown-item" href="{% url 'logout' %}">Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
<form class="form-inline ml-auto">
|
||||
<a href="{% url 'login' %}" class="btn btn-outline-secondary">Log in</a>
|
||||
</form>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@ -76,7 +75,7 @@
|
||||
<div class="push"></div>
|
||||
</div>
|
||||
{% endblock body %}
|
||||
<script src="{% static 'js/jquery-3.6.0.min.js' %}" type="text/javascript"></script>
|
||||
<script src="{% static 'js/jquery-3.3.1.min.js' %}" type="text/javascript"></script>
|
||||
<script src="{% static 'js/popper.min.js' %}" type="text/javascript"></script>
|
||||
<script src="{% static 'js/bootstrap.min.js' %}" type="text/javascript"></script>
|
||||
<script src="{% static 'js/carom.js' %}" type="text/javascript"></script>
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% extends '_base.html' %}
|
||||
{% load static %}
|
||||
{% load static from staticfiles %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load form_tags %}
|
||||
{% block title %}Anmelden{% endblock %}
|
||||
|
Loading…
Reference in New Issue
Block a user