Compare commits
25 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e0c6800e79 | ||
f915043fce | |||
34da538ebe | |||
e035678ff0 | |||
da4794b9db | |||
4e4b8a43e9 | |||
22f3da6add | |||
3eb963736d | |||
93903e23fb | |||
eaccacf453 | |||
cdee337831 | |||
|
4162823863 | ||
|
7387f9b66f | ||
|
6060e5c2b0 | ||
|
7d312cf830 | ||
|
0f578c0611 | ||
|
11d7300d75 | ||
|
8c3b49636a | ||
|
d8bb44dae2 | ||
|
987bb1a7d3 | ||
|
95a28f7cc5 | ||
|
fae852221a | ||
2b941b91ef | |||
|
ae5c503a49 | ||
|
e3b1047484 |
15
Pipfile
15
Pipfile
@ -6,10 +6,11 @@ verify_ssl = true
|
||||
[dev-packages]
|
||||
|
||||
[packages]
|
||||
django = "==3.2.7"
|
||||
django-crispy-forms = "==1.12.0"
|
||||
django-debug-toolbar = "==3.2.2"
|
||||
django-extensions = "==3.1.3"
|
||||
django-tables2 = "==2.4.0"
|
||||
djangorestframework = "==3.12.4"
|
||||
requests = "==2.26.0"
|
||||
django = "==3.2.12"
|
||||
django-crispy-forms = "==1.14.0"
|
||||
django-debug-toolbar = "==3.2.4"
|
||||
django-extensions = "==3.1.5"
|
||||
django-simple-task = "==0.1.2"
|
||||
django-tables2 = "==2.4.1"
|
||||
djangorestframework = "==3.13.1"
|
||||
requests = "==2.27.1"
|
||||
|
@ -0,0 +1 @@
|
||||
default_app_config = 'billard.apps.BillardConfig'
|
@ -2,4 +2,8 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class BillardConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'billard'
|
||||
|
||||
def ready(self):
|
||||
import billard.signals #noqa
|
||||
|
0
billard/management/__init__.py
Normal file
0
billard/management/__init__.py
Normal file
0
billard/management/commands/__init__.py
Normal file
0
billard/management/commands/__init__.py
Normal file
9
billard/management/commands/process_location_data.py
Normal file
9
billard/management/commands/process_location_data.py
Normal file
@ -0,0 +1,9 @@
|
||||
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
|
43
billard/migrations/0028_auto_20211024_1106.py
Normal file
43
billard/migrations/0028_auto_20211024_1106.py
Normal file
@ -0,0 +1,43 @@
|
||||
# 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'),
|
||||
),
|
||||
]
|
11
billard/signals.py
Normal file
11
billard/signals.py
Normal file
@ -0,0 +1,11 @@
|
||||
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))
|
18
caromserver/asgi.py
Normal file
18
caromserver/asgi.py
Normal file
@ -0,0 +1,18 @@
|
||||
"""
|
||||
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)
|
@ -38,6 +38,7 @@ INSTALLED_APPS = [
|
||||
# third party apps
|
||||
'crispy_forms',
|
||||
'debug_toolbar',
|
||||
'django_simple_task',
|
||||
'django_tables2',
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
@ -163,7 +164,7 @@ EMAIL_PORT = 25
|
||||
URL_LOCATION_PROCESSOR = 'http://127.0.0.1:8000/billard/process_locationdata'
|
||||
|
||||
PRODUCT_INFO = 'CAROM'
|
||||
PRODUCT_VERSION = 'v 1.0.2'
|
||||
PRODUCT_VERSION = 'v 1.0.6-dev'
|
||||
|
||||
INTERNAL_IPS = ['127.0.0.1']
|
||||
|
||||
|
@ -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/1.10/howto/deployment/wsgi/
|
||||
https://docs.djangoproject.com/en/3.2/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()
|
||||
|
32
manage.py
32
manage.py
@ -1,22 +1,22 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "caromserver.settings")
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'caromserver.settings')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
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?"
|
||||
)
|
||||
raise
|
||||
except ImportError as exc:
|
||||
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
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
2
static/js/jquery-3.5.1.slim.min.js
vendored
2
static/js/jquery-3.5.1.slim.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
File diff suppressed because it is too large
Load Diff
2
static/js/jquery-3.6.0.min.js
vendored
Normal file
2
static/js/jquery-3.6.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/js/jquery-3.6.0.min.map
Normal file
1
static/js/jquery-3.6.0.min.map
Normal file
File diff suppressed because one or more lines are too long
@ -1,13 +0,0 @@
|
||||
// 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')
|
File diff suppressed because it is too large
Load Diff
1
static/js/popper.js.map
Normal file
1
static/js/popper.js.map
Normal file
File diff suppressed because one or more lines are too long
4
static/js/popper.min.js
vendored
4
static/js/popper.min.js
vendored
File diff suppressed because one or more lines are too long
1
static/js/popper.min.js.map
Normal file
1
static/js/popper.min.js.map
Normal file
File diff suppressed because one or more lines are too long
237
static/js/respond.src.js
Normal file
237
static/js/respond.src.js
Normal file
@ -0,0 +1,237 @@
|
||||
/*! 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);
|
@ -25,43 +25,43 @@
|
||||
<body>
|
||||
{% block body %}
|
||||
<div class="wrapper">
|
||||
<nav class="navbar navbar-expand-sm navbar-dark bg-dark">
|
||||
<nav class="navbar navbar-expand-lg 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-toggle="collapse" data-target="#mainMenu"
|
||||
aria-controls="mainMenu" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="mainMenu">
|
||||
<ul class="navbar-nav">
|
||||
<div class="collapse navbar-collapse" id="navbarSupportetContent">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<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">
|
||||
{% if user.is_authenticated %}
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="userMenu" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="userMenu" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
{{ user.username }}
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userMenu">
|
||||
<a class="dropdown-item" href="{% url 'billard:my_account' %}">My account</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="userMenu">
|
||||
<li><a class="dropdown-item" href="{% url 'billard:my_account' %}">My account</a>
|
||||
</li>
|
||||
{% if user.is_superuser %}
|
||||
<a class="dropdown-item" href="/admin">Administration</a>
|
||||
<li><a class="dropdown-item" href="{% url 'admin:index' %}">Administration</a>
|
||||
</li>
|
||||
{% 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>
|
||||
<li><a class="dropdown-item" href="#">{% settings_value "PRODUCT_VERSION" %}</a>
|
||||
</li>
|
||||
<li><a class="dropdown-item" href="{% url 'logout' %}">Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
{% else %}
|
||||
<form class="form-inline ml-auto">
|
||||
<a href="{% url 'login' %}" class="btn btn-outline-secondary">Log in</a>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% 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 +76,7 @@
|
||||
<div class="push"></div>
|
||||
</div>
|
||||
{% endblock body %}
|
||||
<script src="{% static 'js/jquery-3.5.1.min.js' %}" type="text/javascript"></script>
|
||||
<script src="{% static 'js/jquery-3.6.0.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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user