update to bootstrap 4

This commit is contained in:
Robert Einsle 2018-02-10 13:44:14 +01:00
parent 9036e4b59a
commit e1d96b9b76
54 changed files with 2739 additions and 131 deletions

View File

@ -0,0 +1,35 @@
# Generated by Django 2.0.2 on 2018-02-10 11:05
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('billard', '0023_accounting_account_tst'),
]
operations = [
migrations.AlterField(
model_name='accounting',
name='desk',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='billard.Desk', verbose_name='Tisch'),
),
migrations.AlterField(
model_name='client',
name='location',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='clients', to='billard.Location', verbose_name='Standort'),
),
migrations.AlterField(
model_name='client',
name='report_user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='reporting_clients', to=settings.AUTH_USER_MODEL, verbose_name='Reporting Benutzer'),
),
migrations.AlterField(
model_name='desk',
name='client',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='desks', to='billard.Client', verbose_name='Client'),
),
]

View File

@ -48,8 +48,8 @@ class Location(models.Model):
class Client(models.Model): class Client(models.Model):
uuid = models.UUIDField(unique=True, default=uuid.uuid4, verbose_name="Identifier") uuid = models.UUIDField(unique=True, default=uuid.uuid4, verbose_name="Identifier")
location = models.ForeignKey(Location, related_name="clients", verbose_name="Standort") location = models.ForeignKey(Location, related_name="clients", verbose_name="Standort", on_delete=models.DO_NOTHING)
report_user = models.ForeignKey(User, blank=True, null=True, verbose_name="Reporting Benutzer", related_name='reporting_clients') report_user = models.ForeignKey(User, blank=True, null=True, verbose_name="Reporting Benutzer", related_name='reporting_clients', on_delete=models.DO_NOTHING)
def __str__(self): def __str__(self):
return '{}, {}'.format(self.location.name, self.uuid) return '{}, {}'.format(self.location.name, self.uuid)
@ -60,7 +60,7 @@ class Client(models.Model):
class Desk(models.Model): class Desk(models.Model):
client = models.ForeignKey(Client, verbose_name='Client', related_name='desks') client = models.ForeignKey(Client, verbose_name='Client', related_name='desks', on_delete=models.DO_NOTHING)
desk_no = models.IntegerField(verbose_name='Tischnummer') desk_no = models.IntegerField(verbose_name='Tischnummer')
name = models.CharField(max_length=32, blank=True, null=True, verbose_name='Tischbezeichnung') name = models.CharField(max_length=32, blank=True, null=True, verbose_name='Tischbezeichnung')
enabled = models.BooleanField(verbose_name='Tisch aktiv') enabled = models.BooleanField(verbose_name='Tisch aktiv')
@ -77,7 +77,7 @@ class Desk(models.Model):
class Accounting(models.Model): class Accounting(models.Model):
desk = models.ForeignKey(Desk, verbose_name="Tisch") desk = models.ForeignKey(Desk, verbose_name="Tisch", on_delete=models.DO_NOTHING)
time_from = models.DateTimeField(verbose_name="Beginn") time_from = models.DateTimeField(verbose_name="Beginn")
time_to = models.DateTimeField(blank=True, null=True, verbose_name="Ende") time_to = models.DateTimeField(blank=True, null=True, verbose_name="Ende")
prize = models.DecimalField(max_digits=6, decimal_places=2, blank=True, null=True, verbose_name="Preis") prize = models.DecimalField(max_digits=6, decimal_places=2, blank=True, null=True, verbose_name="Preis")

View File

@ -1,21 +0,0 @@
body > .container {
padding: 60px 15px 0;
}
.container .text-muted {
margin: 20px 0;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
/* Set the fixed height of the footer here */
height: 60px;
background-color: #f5f5f5;
}
.footer > .container {
padding-right: 15px;
padding-left: 15px;
}

View File

@ -1,8 +1,14 @@
{% extends 'billard/base.html' %} {% extends '_base.html' %}
{% load display_client %} {% load display_client %}
{% block title %}Abrechnung{% endblock %} {% block title %}Abrechnung{% endblock %}
{% block breadcrumb %}
<li class="breadcrumb-item"><a href="{% url 'billard:location_index' %}">Standorte</a></li>
<li class="breadcrumb-item"><a href="{% url 'billard:location_detail' location.id %}">{{ location.code }}</a></li>
<li class="breadcrumb-item active">Abrechnung</li>
{% endblock %}
{% block content %} {% block content %}
<div class="alert alert-success" role="alert">Gesamt-Summe: {{ acc_sum }}</div> <div class="alert alert-success" role="alert">Gesamt-Summe: {{ acc_sum }}</div>

View File

@ -1,69 +0,0 @@
{% load static %}
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>carom - {% block title %}TITLE SETZEN{% endblock %}</title>
<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">
{% block header %}
{% endblock %}
<!-- Bootstrap -->
<link href="{% static 'billard/css/bootstrap.min.css' %}" rel="stylesheet" type="text/css">
<link href="{% static 'billard/css/billard.css' %}" rel="stylesheet" type="text/css">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="{% static 'billard/js/html5shiv.min.js' %}"></script>
<script src="{% static 'billard/js/respond.min.js' %}" type="text/javascript"></script>
<![endif]-->
</head>
<body>
<header class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Navigation ein-/ausblenden</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Billard</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="{% ifequal request.path '/billard/' %}active{% endifequal %}"><a href="{% url "billard:location_index" %}">Standorte</a></li>
{% if user.is_superuser %}
<li class="{% ifequal request.path '/logout/' %}active{% endifequal %}"><a href="/admin/">Administration</a></li>
{% endif %}
{% if user.is_authenticated %}
<li class="dropdown-toggle">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">({{ user.get_username }}) <span class="caret" /></a>
<ul class="dropdown-menu">
<li class="{% ifequal request.path '/logout/' %}active{% endifequal %}"><a href="{% url 'logout' %}">Abmelden</a></li>
</ul>
</li>
{% else %}
<li class="{% ifequal request.path '/login/' %}active{% endifequal %}"><a href="{% url 'login' %}">Anmelden</a></li>
{% endif %}
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">c@0.2.3</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</header>
<div class="container" id="content">
{% block content %}
{% endblock %}
</div><!-- /.container -->
<script src="{% static 'billard/js/jquery-3.3.1.min.js' %}" type="text/javascript"></script>
<script src="{% static 'billard/js/bootstrap.min.js' %}" type="text/javascript"></script>
<script src="{% static 'billard/js/carom.js' %}" type="text/javascript"></script>
{% block js %}
{% endblock %}
</body>
</html>

View File

@ -1,4 +1,4 @@
{% extends 'billard/base.html' %} {% extends '_base.html' %}
{% load display_client %} {% load display_client %}
{% block title %}Location Data{% endblock %} {% block title %}Location Data{% endblock %}

View File

@ -1,9 +1,14 @@
{% extends 'billard/base.html' %} {% extends '_base.html' %}
{% block title %}Standort{% endblock %} {% block title %}Standort{% endblock %}
{% block breadcrumb %}
<li class="breadcrumb-item"><a href="{% url 'billard:location_index' %}">Standorte</a></li>
<li class="breadcrumb-item active">{{ location.code }}</li>
{% endblock %}
{% block content %} {% block content %}
<div id="desk_data"> <div class="row">
{% include 'billard/location_detail_ajax.html' %} {% include 'billard/location_detail_ajax.html' %}
</div> </div>
<div id="modal-wrapper"> <div id="modal-wrapper">

View File

@ -6,7 +6,7 @@
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
{% else %} {% else %}
<div class="col-md-12"> <div class="col">
<div class="col-md-12 alert alert-danger">Keine Tische angelegt!</div> <div class="alert alert-danger">Keine Tische angelegt!</div>
</div> </div>
{% endif %} {% endif %}

View File

@ -1,7 +1,11 @@
{% extends 'billard/base.html' %} {% extends '_base.html' %}
{% block title %}Standortliste{% endblock %} {% block title %}Standortliste{% endblock %}
{% block breadcrumb %}
<li class="breadcrumb-item active">Standorte</li>
{% endblock %}
{% block content %} {% block content %}
{% if location_list %} {% if location_list %}

View File

@ -1,4 +1,4 @@
{% extends 'billard/base.html' %} {% extends '_base.html' %}
{% block title %}Location Data{% endblock %} {% block title %}Location Data{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends 'billard/base.html' %} {% extends '_base.html' %}
{% block title %}Location Data{% endblock %} {% block title %}Location Data{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends 'billard/base.html' %} {% extends '_base.html' %}
{% block title %}Location Data{% endblock %} {% block title %}Location Data{% endblock %}

View File

@ -1,16 +0,0 @@
{% extends 'billard/base.html' %}
{% load crispy_forms_tags %}
{% block title %}Login{% endblock %}
{% block content %}
<form action="{% url "login" %}" method="post" accept-charset="utf-8">
{% csrf_token %}
{{ form|crispy }}
<input type="hidden" name="next" value="{{ next }}" />
<input class="btn btn-default" type="submit" value="Login" />
</form>
{% endblock %}

View File

@ -32,8 +32,8 @@ def display_client(client, desk_no):
prize = '{0:.2f}'.format(prize) prize = '{0:.2f}'.format(prize)
if prize != a.prize: if prize != a.prize:
a.prize = prize a.prize = prize
html = '<div class="col-md-6">\n' html = '<div class="col col-md-6">\n'
html += ' <div class="col-md-12 table-info alert {}">\n'.format(alert) html += ' <div class="table-info alert {}">\n'.format(alert)
html += ' <h4 style="text-align: center">({}) {}</h4>\n'.format(desk_no, desk.name) html += ' <h4 style="text-align: center">({}) {}</h4>\n'.format(desk_no, desk.name)
if loc.happy_hour_start is not None and desk.prize_hh is not None: if loc.happy_hour_start is not None and desk.prize_hh is not None:
html += ' <h6 style="text-align: center">Preis: {:.2f} € / Stunde | {} - {}: {:.2f} / € Stunde</h6>\n'\ html += ' <h6 style="text-align: center">Preis: {:.2f} € / Stunde | {} - {}: {:.2f} / € Stunde</h6>\n'\

View File

@ -0,0 +1,19 @@
from django import template
register = template.Library()
@register.filter
def field_type(bound_field):
return bound_field.field.widget.__class__.__name__
@register.filter
def input_class(bound_field):
css_class = ''
if bound_field.form.is_bound:
if bound_field.errors:
css_class = 'is-invalid'
elif field_type(bound_field) != 'PasswordInput':
css_class = 'is-valid'
return 'form-control {}'.format(css_class)

View File

@ -58,6 +58,7 @@ class AccountingView(generic.ListView):
else: else:
result.context_data['acc_sum'] = acc_sum['prize__sum'] result.context_data['acc_sum'] = acc_sum['prize__sum']
result.context_data['acc_ids'] = [acc.id for acc in self.get_queryset().all()] result.context_data['acc_ids'] = [acc.id for acc in self.get_queryset().all()]
result.context_data['location'] = Location.objects.get(pk=self.kwargs['pk'])
return result return result

View File

@ -38,6 +38,7 @@ INSTALLED_APPS = [
'rest_framework', 'rest_framework',
'rest_framework.authtoken', 'rest_framework.authtoken',
'crispy_forms', 'crispy_forms',
'widget_tweaks',
'billard', 'billard',
] ]
@ -56,7 +57,9 @@ ROOT_URLCONF = 'caromserver.urls'
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [], 'DIRS': [
os.path.join(BASE_DIR, 'templates')
],
'APP_DIRS': True, 'APP_DIRS': True,
'OPTIONS': { 'OPTIONS': {
'context_processors': [ 'context_processors': [
@ -81,7 +84,6 @@ DATABASES = {
} }
} }
# Password validation # Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
@ -100,7 +102,6 @@ AUTH_PASSWORD_VALIDATORS = [
}, },
] ]
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/ # https://docs.djangoproject.com/en/1.10/topics/i18n/
@ -118,6 +119,11 @@ USE_TZ = False
# https://docs.djangoproject.com/en/1.10/howto/static-files/ # https://docs.djangoproject.com/en/1.10/howto/static-files/
STATIC_URL = '/static/' STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'staticfiles')
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
REST_FRAMEWORK = { REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions, # Use Django's standard `django.contrib.auth` permissions,
@ -132,7 +138,7 @@ REST_FRAMEWORK = {
), ),
} }
CRISPY_TEMPLATE_PACK = 'bootstrap3' CRISPY_TEMPLATE_PACK = 'bootstrap4'
LOGIN_URL = 'login' LOGIN_URL = 'login'
LOGOUT_URL = 'logout' LOGOUT_URL = 'logout'
LOGIN_REDIRECT_URL = 'billard:location_index' LOGIN_REDIRECT_URL = 'billard:location_index'
@ -152,8 +158,6 @@ EMAIL_PORT = 25
URL_LOCATION_PROCESSOR = 'http://127.0.0.1:8000/billard/process_locationdata' URL_LOCATION_PROCESSOR = 'http://127.0.0.1:8000/billard/process_locationdata'
STATIC_ROOT = "/srv/carom/carom-server/static/"
try: try:
from local_settings import * from local_settings import *
except ImportError: except ImportError:

View File

@ -22,8 +22,8 @@ urlpatterns = [
url(r'^admin/', admin.site.urls), url(r'^admin/', admin.site.urls),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^billard/', include('billard.urls')), url(r'^billard/', include('billard.urls')),
url(r'^login/$', auth_views.login), url(r'^login/$', auth_views.login, name='login'),
url(r'^logout/$', auth_views.logout), url(r'^logout/$', auth_views.logout, name='logout'),
url(r'^', include('django.contrib.auth.urls')), url(r'^', include('django.contrib.auth.urls')),
url(r'^$', RedirectView.as_view(url='billard/', permanent=False), name='index') url(r'^$', RedirectView.as_view(url='billard/', permanent=False), name='index')
] ]

25
static/css/billard.css Normal file
View File

@ -0,0 +1,25 @@
body > .container {
padding: 60px 15px 0;
}
.container .text-muted {
margin: 20px 0;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
/* Set the fixed height of the footer here */
height: 60px;
background-color: #f5f5f5;
}
.footer > .container {
padding-right: 15px;
padding-left: 15px;
}
.navbar-brand {
font-family: 'Peralta', cursive;
}

16
static/css/login.css Normal file
View File

@ -0,0 +1,16 @@
body {
background-image: url("../img/shattered.png");
}
.logo {
font-family: 'Peralta', cursive;
}
.logo a {
color: rgba(0,0,0,.9);
}
.logo a:hover,
.logo a:active {
text-decoration: none;
}

BIN
static/img/shattered.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

2445
static/js/popper.js Normal file

File diff suppressed because it is too large Load Diff

5
static/js/popper.min.js vendored Normal file

File diff suppressed because one or more lines are too long

85
templates/_base.html Normal file
View File

@ -0,0 +1,85 @@
{% load static %}<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>carom - {% block title %}TITLE SETZEN{% endblock %}</title>
<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">
{% block header %}
{% endblock %}
<!-- Bootstrap -->
<link href="https://fonts.googleapis.com/css?family=Peralta" rel="stylesheet">
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet" type="text/css">
<link href="{% static 'css/billard.css' %}" rel="stylesheet" type="text/css">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="{% static 'js/html5shiv.min.js' %}"></script>
<script src="{% static 'js/respond.min.js' %}" type="text/javascript"></script>
<![endif]-->
{% block stylesheet %}{% endblock %}
</head>
<body>
{% block body %}
<div class="wrapper">
<nav class="navbar navbar-expand-sm navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="{% url 'index' %}">carom</a>
<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="mainMenu">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="{% url 'billard:location_index' %}">Standorte</a>
</li>
{% if user.is_superuser %}
<li class="nav-item">
<a class="nav-link" href="/admin">Administration</a>
</li>
{% endif %}
</ul>
{% if user.is_authenticated %}
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="userMenu" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
{{ user.username }}
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userMenu">
<a class="dropdown-item" href="#">My account</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="{% url 'logout' %}">Log out</a>
</div>
</li>
</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>
<div class="container-fluid">
<ol class="breadcrumb my-4">
{% block breadcrumb %}
{% endblock breadcrumb %}
</ol>
{% block content %}
{% endblock content %}
</div>
<div class="push"></div>
</div>
{% endblock body %}
<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>
{% block js %}
{% endblock %}
</body>
</html>

View File

@ -0,0 +1,17 @@
{% extends '_base.html' %}
{% load static %}
{% block stylesheet %}
<link rel="stylesheet" href="{% static 'css/login.css' %}">
{% endblock %}
{% block body %}
<div class="container">
<h1 class="text-center logo my-4">
<a href="{% url 'billard:location_index' %}">carom</a>
</h1>
{% block content %}
{% endblock %}
</div>
{% endblock %}

View File

@ -0,0 +1,26 @@
{% load form_tags widget_tweaks %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
<p{% if forloop.last %} class="mb-0"{% endif %}>{{ error }}</p>
{% endfor %}
</div>
{% endif %}
{% for field in form %}
<div class="form-group">
{{ field.label_tag }}
{% render_field field class=field|input_class %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% if field.help_text %}
<small class="form-text text-muted">
{{ field.help_text|safe }}
</small>
{% endif %}
</div>
{% endfor %}

View File

@ -0,0 +1,21 @@
{% extends '_base_accounts.html' %}
{% block title %}login{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-lg-4 col-md-6 col-sm-8">
<div class="card">
<div class="card-body">
<h3 class="card-title">Log in</h3>
<form method="post" novalidate>
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}">
{% include 'includes/form.html' %}
<button type="submit" class="btn btn-primary btn-block">Log in</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}