Compare commits
No commits in common. "develop" and "v1.0.2" have entirely different histories.
15
Pipfile
15
Pipfile
@ -6,11 +6,10 @@ verify_ssl = true
|
||||
[dev-packages]
|
||||
|
||||
[packages]
|
||||
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"
|
||||
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"
|
||||
|
@ -1 +0,0 @@
|
||||
default_app_config = 'billard.apps.BillardConfig'
|
@ -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,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)
|
@ -38,7 +38,6 @@ INSTALLED_APPS = [
|
||||
# third party apps
|
||||
'crispy_forms',
|
||||
'debug_toolbar',
|
||||
'django_simple_task',
|
||||
'django_tables2',
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
@ -164,7 +163,7 @@ EMAIL_PORT = 25
|
||||
URL_LOCATION_PROCESSOR = 'http://127.0.0.1:8000/billard/process_locationdata'
|
||||
|
||||
PRODUCT_INFO = 'CAROM'
|
||||
PRODUCT_VERSION = 'v 1.0.6-dev'
|
||||
PRODUCT_VERSION = 'v 1.0.2'
|
||||
|
||||
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/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()
|
||||
|
32
manage.py
32
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:
|
||||
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
|
||||
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
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
File diff suppressed because it is too large
Load Diff
2
static/js/jquery-3.5.1.slim.min.js
vendored
Normal file
2
static/js/jquery-3.5.1.slim.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/js/jquery-3.5.1.slim.min.map
Normal file
1
static/js/jquery-3.5.1.slim.min.map
Normal file
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')
|
File diff suppressed because it is too large
Load Diff
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
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);
|
@ -25,43 +25,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>
|
||||
{% if user.is_authenticated %}
|
||||
</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>
|
||||
</li>
|
||||
<li><a class="dropdown-item" href="{% url 'logout' %}">Logout</a></li>
|
||||
</ul>
|
||||
<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>
|
||||
{% else %}
|
||||
<form class="form-inline ml-auto">
|
||||
<a href="{% url 'login' %}" class="btn btn-outline-secondary">Log in</a>
|
||||
</form>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</ul>
|
||||
{% else %}
|
||||
<form class="form-inline ml-auto">
|
||||
<a href="{% url 'login' %}" class="btn btn-outline-secondary">Log in</a>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@ -76,7 +76,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.5.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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user