Initial commit

This commit is contained in:
Jim Martens 2020-02-19 10:34:17 +01:00
commit 85d5f0b123
43 changed files with 15041 additions and 0 deletions

240
.gitignore vendored Normal file
View File

@ -0,0 +1,240 @@
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# ---> Node
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test

208
LICENSE Normal file
View File

@ -0,0 +1,208 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION,
AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution
as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct
or indirect, to cause the direction or management of such entity, whether
by contract or otherwise, or (ii) ownership of fifty percent (50%) or more
of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions
granted by this License.
"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical transformation
or translation of a Source form, including but not limited to compiled object
code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form,
made available under the License, as indicated by a copyright notice that
is included in or attached to the work (an example is provided in the Appendix
below).
"Derivative Works" shall mean any work, whether in Source or Object form,
that is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative
Works shall not include works that remain separable from, or merely link (or
bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative
Works thereof, that is intentionally submitted to Licensor for inclusion in
the Work by the copyright owner or by an individual or Legal Entity authorized
to submit on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication
sent to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor
for the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently incorporated
within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this
License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable copyright license to reproduce, prepare
Derivative Works of, publicly display, publicly perform, sublicense, and distribute
the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License,
each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section) patent
license to make, have made, use, offer to sell, sell, import, and otherwise
transfer the Work, where such license applies only to those patent claims
licensable by such Contributor that are necessarily infringed by their Contribution(s)
alone or by combination of their Contribution(s) with the Work to which such
Contribution(s) was submitted. If You institute patent litigation against
any entity (including a cross-claim or counterclaim in a lawsuit) alleging
that the Work or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses granted to You
under this License for that Work shall terminate as of the date such litigation
is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or
Derivative Works thereof in any medium, with or without modifications, and
in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy
of this License; and
(b) You must cause any modified files to carry prominent notices stating that
You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source
form of the Work, excluding those notices that do not pertain to any part
of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution,
then any Derivative Works that You distribute must include a readable copy
of the attribution notices contained within such NOTICE file, excluding those
notices that do not pertain to any part of the Derivative Works, in at least
one of the following places: within a NOTICE text file distributed as part
of the Derivative Works; within the Source form or documentation, if provided
along with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works
that You distribute, alongside or as an addendum to the NOTICE text from the
Work, provided that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction,
or distribution of Your modifications, or for any such Derivative Works as
a whole, provided Your use, reproduction, and distribution of the Work otherwise
complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any
Contribution intentionally submitted for inclusion in the Work by You to the
Licensor shall be under the terms and conditions of this License, without
any additional terms or conditions. Notwithstanding the above, nothing herein
shall supersede or modify the terms of any separate license agreement you
may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names,
trademarks, service marks, or product names of the Licensor, except as required
for reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to
in writing, Licensor provides the Work (and each Contributor provides its
Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied, including, without limitation, any warranties
or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR
A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness
of using or redistributing the Work and assume any risks associated with Your
exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether
in tort (including negligence), contract, or otherwise, unless required by
applicable law (such as deliberate and grossly negligent acts) or agreed to
in writing, shall any Contributor be liable to You for damages, including
any direct, indirect, special, incidental, or consequential damages of any
character arising as a result of this License or out of the use or inability
to use the Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all other commercial
damages or losses), even if such Contributor has been advised of the possibility
of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work
or Derivative Works thereof, You may choose to offer, and charge a fee for,
acceptance of support, warranty, indemnity, or other liability obligations
and/or rights consistent with this License. However, in accepting such obligations,
You may act only on Your own behalf and on Your sole responsibility, not on
behalf of any other Contributor, and only if You agree to indemnify, defend,
and hold each Contributor harmless for any liability incurred by, or claims
asserted against, such Contributor by reason of your accepting any such warranty
or additional liability. END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "[]" replaced with your own identifying
information. (Don't include the brackets!) The text should be enclosed in
the appropriate comment syntax for the file format. We also recommend that
a file or class name and description of purpose be included on the same "printed
page" as the copyright notice for easier identification within third-party
archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

9
README.md Normal file
View File

@ -0,0 +1,9 @@
# Django template
Template repository for Django applications
## ToDos
- change ``app``into something more appropriate wherever you find it
- change ``Django template`` and ``DjangoTemplate`` into something more appropriate wherever you find it

2
app/__init__.py Normal file
View File

@ -0,0 +1,2 @@
# coding=utf-8
default_app_config = 'chaos_dating.apps.ChaosDatingConfig'

39
app/account_urls.py Normal file
View File

@ -0,0 +1,39 @@
# coding=utf-8
from django.contrib.auth import views as auth_views
from django.urls import path
from chaos_dating import views as chaos_views
extra_context = {
'site': {
'title': 'Django template'
},
}
urlpatterns = [
path('login/', chaos_views.user_login, name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('register/', chaos_views.register, name='register'),
path('password_change/',
auth_views.PasswordChangeView.as_view(extra_context=extra_context),
name='password_change'),
path('password_change/done/',
chaos_views.password_change_done,
name='password_change_done'),
path('password_reset/',
auth_views.PasswordResetView.as_view(extra_context=extra_context),
name='password_reset'),
path('password_reset/done/',
auth_views.PasswordResetDoneView.as_view(extra_context=extra_context),
name='password_reset_done'),
path('reset/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(extra_context=extra_context),
name='password_reset_confirm'),
path('reset/done/',
auth_views.PasswordResetCompleteView.as_view(extra_context=extra_context),
name='password_reset_complete'),
path('edit_profile/', chaos_views.edit_profile, name='edit_profile'),
]

20
app/admin.py Normal file
View File

@ -0,0 +1,20 @@
# coding=utf-8
from django.contrib import admin
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from app.models import Profile
# Register your models here.
admin.site.unregister(User)
class ProfileInline(admin.StackedInline):
model = Profile
class UserProfileAdmin(UserAdmin):
inlines = [ProfileInline, ]
admin.site.register(User, UserProfileAdmin)

7
app/apps.py Normal file
View File

@ -0,0 +1,7 @@
# coding=utf-8
from django.apps import AppConfig
class DjangoTemplateConfig(AppConfig):
name = 'app'
verbose_name = 'Django template app'

44
app/forms.py Normal file
View File

@ -0,0 +1,44 @@
# coding=utf-8
from gettext import gettext as _
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.contrib.auth.forms import UsernameField
from django.contrib.auth.models import User
from django.urls import reverse
from app.models import Profile
class UserForm(forms.ModelForm):
password = ReadOnlyPasswordHashField(
label=_("Password"),
help_text=_(
'Raw passwords are not stored, so there is no way to see the '
'password, but you can change the password using '
'<a href="{}">this form</a>.'
),
)
class Meta:
model = User
fields = ['username', 'password', 'email', 'first_name', 'last_name']
field_classes = {'username': UsernameField}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
password = self.fields.get('password')
if password:
password.help_text = password.help_text.format(reverse('password_change'))
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial.get('password')
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile

View File

@ -0,0 +1 @@
# coding=utf-8

11
app/models.py Normal file
View File

@ -0,0 +1,11 @@
# coding=utf-8
from django.contrib.auth.models import User
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(User, models.CASCADE)
def __str__(self):
return self.user.username

View File

View File

@ -0,0 +1,60 @@
{% extends "base.html" %}
{% load i18n %}
{% block header %}
<nav id="mainNavbar" class="navbar navbar-expand-lg navbar-light fixed-top">
<div class="container">
<a class="navbar-brand" href="{% url "chaos_dating:index" %}">
<span class="fal fa-comment-alt-dots d-inline-block align-top"></span>
{{ site.title }}
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-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="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
{% if request.user.is_authenticated %}
<li class="nav-item{% if active == "edit_profile" %} active{% endif %}">
<a class="nav-link" href="{% url "edit_profile" %}">
{% trans "Edit Profile" %}{% if active == "edit_profile" %}
<span class="sr-only">(current)</span>
{% endif %}
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url "logout" %}">
{% trans "Logout" %}
</a>
</li>
{% else %}
<li class="nav-item{% if active == "login" %} active{% endif %}">
<a class="nav-link" href="{% url "login" %}">
{% trans "Login" %}{% if active == "login" %}
<span class="sr-only">(current)</span>
{% endif %}
</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
{% endblock %}
{% block footer %}
<div class="col">
<nav>
<ul class="nav">
<li class="nav-item">
<a class="nav-link" href="{% url "chaos_dating:legal" %}">{% trans "Legal Notice" %}</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url "chaos_dating:privacy" %}">{% trans "Privacy Policy" %}</a>
</li>
</ul>
</nav>
</div>
{% endblock %}

View File

@ -0,0 +1,9 @@
{% extends "app/base.html" %}
{% load i18n %}
{% block title %}{{ site.title }} - {% trans "Home" %}{% endblock %}
{% block content %}
<h1>{% trans "Home" %}</h1>
{% endblock %}

View File

@ -0,0 +1,38 @@
{% extends "app/base.html" %}
{% load i18n %}
{% block title %}{{ site.title }}{% endblock %}
{% block content %}
<h1>{{ site.title }}</h1>
<h2>{% trans "Everything else is crap" %}</h2>
<p>
{% blocktrans %}
Lorem ipsum
{% endblocktrans %}
</p>
<h2>{% trans "Our radical new approach" %}</h2>
<p>
{% blocktrans %}
Lorem ipsum
{% endblocktrans %}
</p>
<p>
{% blocktrans %}
Lorem ipsum
{% endblocktrans %}
</p>
<p>
{% blocktrans %}
Lorem ipsum
{% endblocktrans %}
</p>
<a class="btn btn-primary" href="{% url "register" %}">{% trans "Join the community" %}</a>
{% endblock %}

View File

@ -0,0 +1,48 @@
{% extends "app/base.html" %}
{% load i18n %}
{% block title %}{{ site.title }} - {% trans "Legal Notice" %}{% endblock %}
{% block content %}
<h1>FIXME</h1>
<h1>{% trans "Legal Notice" %}</h1>
{% blocktrans %}
<h2>Information provided according to Sec. 5 German Telemedia Act (TMG):</h2>
<p>Jim Richard Martens<br />
Bindfeldweg 47d<br />
22459 Hamburg</p>
<h2>Contact:</h2>
<p>Email: admin@2martens.de</p>
<h2>Responsible for contents acc. to Sec. 55, para. 2 German Federal Broadcasting Agreement (RstV):</h2>
<p>Jim Martens<br />
Bindfeldweg 47d<br />
22459 Hamburg</p>
<h2>Liability for Contents</h2>
<p>As service providers, we are liable for own contents of these websites according to Sec. 7, paragraph 1 German
Telemedia Act (TMG). However, according to Sec. 8 to 10 German Telemedia Act (TMG), service providers are not
obligated to permanently monitor submitted or stored information or to search for evidences that indicate illegal
activities.</p> <p>Legal obligations to removing information or to blocking the use of information remain unchallenged.
In this case, liability is only possible at the time of knowledge about a specific violation of law. Illegal contents
will be removed immediately at the time we get knowledge of them.</p>
<h2>Liability for Links</h2>
<p>Our offer includes links to external third party websites. We have no influence on the contents of those websites,
therefore we cannot guarantee for those contents. Providers or administrators of linked websites are always responsible
for their own contents.</p>
<p>The linked websites had been checked for possible violations of law at the time of the establishment of the link.
Illegal contents were not detected at the time of the linking. A permanent monitoring of the contents of linked
websites cannot be imposed without reasonable indications that there has been a violation of law. Illegal links
will be removed immediately at the time we get knowledge of them.</p>
<h2>Copyright</h2>
<p>Contents and compilations published on these websites by the providers are subject to German copyright laws.
Reproduction, editing, distribution as well as the use of any kind outside the scope of the copyright law require a
written permission of the author or originator. Downloads and copies of these websites are permitted for private use
only.<br /> The commercial use of our contents without permission of the originator is prohibited.</p>
<p>Copyright laws of third parties are respected as long as the contents on these websites do not originate from the
provider. Contributions of third parties on this site are indicated as such. However, if you notice any violations of
copyright law, please inform us. Such contents will be removed immediately.</p>
<p> </p>
{% endblocktrans %}
{% endblock %}

View File

@ -0,0 +1,88 @@
{% extends "app/base.html" %}
{% load i18n %}
{% block title %}{{ site.title }} - {% trans "Privacy Policy" %}{% endblock %}
{% block content %}
<h1>FIXME</h1>
<h1>{% trans "Privacy Policy" %}</h1>
{% blocktrans %}
<h2>1. An overview of data protection</h2>
<h3>General</h3>
<p>The following gives a simple overview of what happens to your personal information when you visit our website.
Personal information is any data with which you could be personally identified. Detailed information on the subject
of data protection can be found in our privacy policy found below.</p>
<h3>Data collection on our website</h3>
<p><strong>Who is responsible for the data collection on this website?</strong></p>
<p>The data collected on this website are processed by the website operator. The operator's contact details can be found
in the website's required legal notice.</p>
<p><strong>How do we collect your data?</strong></p>
<p>Some data are collected when you provide it to us. This could, for example, be data you enter on a contact form.</p>
<p>Other data are collected automatically by our IT systems when you visit the website. These data are primarily technical
data such as the browser and operating system you are using or when you accessed the page. These data are collected
automatically as soon as you enter our website.</p>
<p><strong>What do we use your data for?</strong></p>
<p>Part of the data is collected to ensure the proper functioning of the website. Other data can be used to analyze how
visitors use the site.</p>
<p><strong>What rights do you have regarding your data?</strong></p>
<p>You always have the right to request information about your stored data, its origin, its recipients, and the purpose
of its collection at no charge. You also have the right to request that it be corrected, blocked, or deleted. You can
contact us at any time using the address given in the legal notice if you have further questions about the issue of
privacy and data protection. You may also, of course, file a complaint with the competent regulatory authorities.</p>
<h2>2. General information and mandatory information</h2>
<h3>Data protection</h3>
<p>The operators of this website take the protection of your personal data very seriously. We treat your personal data as
confidential and in accordance with the statutory data protection regulations and this privacy policy.</p>
<p>If you use this website, various pieces of personal data will be collected. Personal information is any data with which
you could be personally identified. This privacy policy explains what information we collect and what we use it for.
It also explains how and for what purpose this happens.</p>
<p>Please note that data transmitted via the internet (e.g. via email communication) may be subject to security breaches.
Complete protection of your data from third-party access is not possible.</p>
<h3>Notice concerning the party responsible for this website</h3>
<p>The party responsible for processing data on this website is:</p>
<p>Jim Martens<br />
Bindfeldweg 47d<br />
22459 Hamburg</p>
<p>Telephone: +49 40 55504288<br />
Email: admin@2martens.de</p>
<p>The responsible party is the natural or legal person who alone or jointly with others decides on the purposes and means
of processing personal data (names, email addresses, etc.).</p>
<h3>SSL or TLS encryption</h3> <p>This site uses SSL or TLS encryption for security reasons and for the protection of the
transmission of confidential content, such as the inquiries you send to us as the site operator. You can recognize an
encrypted connection in your browser's address line when it changes from "http://" to "https://" and the lock icon is
displayed in your browser's address bar.</p>
<p>If SSL or TLS encryption is activated, the data you transfer to us cannot be read by third parties.</p>
<h3>Opposition to promotional emails</h3> <p>We hereby expressly prohibit the use of contact data published in the context
of website legal notice requirements with regard to sending promotional and informational materials not expressly
requested. The website operator reserves the right to take specific legal action if unsolicited advertising material,
such as email spam, is received.</p>
<h2>3. Data collection on our website</h2>
<h3>Server log files</h3>
<p>The website provider automatically collects and stores information that your browser automatically transmits to us in
"server log files". These are:</p>
<ul>
<li>Browser type and browser version</li>
<li>Operating system used</li>
<li>Referrer URL</li>
<li>Host name of the accessing computer</li>
<li>Time of the server request</li>
<li>IP address</li>
</ul>
<p>These data will not be combined with data from other sources.</p>
<p>The basis for data processing is Art. 6 (1) (b) GDPR, which allows the processing of data to fulfill a contract or
for measures preliminary to a contract.</p>
<h2>4. Plugins and tools</h2>
<h3>YouTube</h3>
<p>Our website uses plugins from YouTube, which is operated by Google. The operator of the pages is
YouTube LLC, 901 Cherry Ave., San Bruno, CA 94066, USA.</p>
<p>If you visit one of our pages featuring a YouTube plugin, a connection to the YouTube servers is established. Here
the YouTube server is informed about which of our pages you have visited.</p>
<p>If you're logged in to your YouTube account, YouTube allows you to associate your browsing behavior directly with your
personal profile. You can prevent this by logging out of your YouTube account.</p>
<p>YouTube is used to help make our website appealing. This constitutes a justified interest pursuant to
Art. 6 (1) (f) GDPR.</p>
<p>Further information about handling user data, can be found in the data protection declaration of YouTube under
<a href="https://www.google.de/intl/en/policies/privacy" target="_blank">https://www.google.de/intl/en/policies/privacy</a>.</p>
{% endblocktrans %}
{% endblock %}

View File

@ -0,0 +1,17 @@
{% extends "app/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{{ site.title }} - {{ title }}{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<form method="post" action="{% url "edit_profile" %}">
{% csrf_token %}
{{ user_form|crispy }}
{{ profile_form|crispy }}
<button type="submit" class="btn btn-primary">{% trans "Submit" %}</button>
</form>
{% endblock %}

View File

@ -0,0 +1,17 @@
{% extends "app/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{{ site.title }} - {{ title }}{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<form method="post" action="{% url "login" %}">
{% csrf_token %}
{{ form|crispy }}
<input type="hidden" name="next" value="{{ next }}" />
<button type="submit" class="btn btn-primary">{% trans "Login" %}</button>
<a href="{% url "password_reset" %}">{% trans "Forgot password?" %}</a>
</form>
{% endblock %}

View File

@ -0,0 +1,15 @@
{% extends "app/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{{ site_name }} - {{ title }}{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">{% trans "Change password" %}</button>
</form>
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends "app/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{{ site.title }} - {{ title }}{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<p>{% trans "Your password has been set. You may go ahead and log in now." %}</p>
<p><a href="{{ login_url }}">{% trans 'Log in' %}</a></p>
{% endblock %}

View File

@ -0,0 +1,19 @@
{% extends "app/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{{ site.title }} - {{ title }}{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
{% if validlink %}
<p>{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}</p>
<form method="post" action="{% url "password_reset" %}">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">{% trans "Change my password" %}</button>
</form>
{% else %}
<p>{% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}</p>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends "app/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{{ site.title }} - {{ title }}{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<p>{% trans 'Weve emailed you instructions for setting your password. If an account exists with the email you entered you should receive them shortly.' %}</p>
<p>{% trans 'If you dont receive an email, please make sure youve entered the address you registered with, and check your spam folder.' %}</p>
{% endblock %}

View File

@ -0,0 +1,17 @@
{% extends "app/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{{ site.title }} - {{ title }}{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<p>{% trans 'Forgotten your password? Enter your email address below, and well email instructions for setting a new one.' %}</p>
<form method="post" action="{% url "password_reset" %}">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">{% trans "Password reset" %}</button>
</form>
{% endblock %}

View File

@ -0,0 +1,16 @@
{% extends "app/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{{ site.title }} - {% trans "Register" %}{% endblock %}
{% block content %}
<h1>{% trans "Register a new user" %}</h1>
<form method="post" action="{% url "register" %}">
{% csrf_token %}
{{ user_form|crispy }}
{{ profile_form|crispy }}
<button type="submit" class="btn btn-primary">{% trans "Register" %}</button>
</form>
{% endblock %}

5
app/tests.py Normal file
View File

@ -0,0 +1,5 @@
# coding=utf-8
from django.test import TestCase
# Create your tests here.

24
app/translation.py Normal file
View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Copyright 2020 Jim Martens
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from modeltranslation import translator
from modeltranslation.translator import TranslationOptions
# example for translation
# @translator.register(Gender)
# class GenderTranslationOptions(TranslationOptions):
# fields = ('name',)

11
app/urls.py Normal file
View File

@ -0,0 +1,11 @@
# coding=utf-8
from django.urls import path
from . import views
app_name = 'app'
urlpatterns = [
path('', views.index, name='index'),
path('legal-notice/', views.legal, name='legal'),
path('privacy/', views.privacy, name='privacy'),
]

122
app/views.py Normal file
View File

@ -0,0 +1,122 @@
# coding=utf-8
from gettext import gettext as _
from django.contrib import messages
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.views import LoginView
from django.db import transaction
from django.http import HttpResponse
from django.shortcuts import redirect
from django.shortcuts import render
from django.urls import reverse
from app.forms import ProfileForm
from app.forms import UserForm
def index(request) -> HttpResponse:
context = {
'site': {
'title': 'Django template'
}
}
if request.user.is_authenticated:
return render(request, template_name='app/home.html', context=context)
else:
return render(request, template_name='app/landing.html', context=context)
@transaction.atomic
def register(request) -> HttpResponse:
if request.user.is_authenticated:
return redirect('app:index')
user_form = UserCreationForm(data=request.POST or None)
profile_form = ProfileForm(data=request.POST or None, files=request.FILES or None)
context = {
'site': {
'title': 'Django template'
},
'user_form': user_form,
'profile_form': profile_form
}
if request.method == "POST" and user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
profile = profile_form.save(commit=False)
profile.user = user
if 'profile_pic' in request.FILES:
profile.profile_pic = request.FILES['profile_pic']
profile.save()
login(request, user=user)
messages.success(request, _('User was successfully registered'))
return redirect('edit_profile')
return render(request, template_name='registration/register.html', context=context)
def user_login(request) -> HttpResponse:
login_view = LoginView()
login_view.setup(request)
login_view.redirect_authenticated_user = True
login_view.extra_context = {
'active': 'login',
'title': _('Login'),
'site': {
'title': 'Django template'
},
}
return login_view.dispatch(request)
@login_required()
@transaction.atomic
def edit_profile(request) -> HttpResponse:
user_form = UserForm(data=request.POST or None, instance=request.user)
profile_form = ProfileForm(data=request.POST or None, files=request.FILES or None,
instance=request.user.profile)
user_form.fields['email'].help_text = _('The email address is required for password recovery.')
context = {
'active': 'edit_profile',
'title': _('Edit User Profile'),
'site': {
'title': 'Django template'
},
'user_form': user_form,
'profile_form': profile_form
}
if request.method == "POST" and user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile = profile_form.save(commit=False)
if 'profile_pic' in request.FILES:
profile.profile_pic = request.FILES['profile_pic']
profile.save()
messages.success(request, _('Profile was successfully updated'))
return render(request, template_name='registration/edit_profile.html', context=context)
@login_required()
def password_change_done(request) -> HttpResponse:
messages.success(request, _('Your password was successfully changed.'))
return redirect(reverse('edit_profile'))
def legal(request) -> HttpResponse:
context = {
'site': {
'title': 'Django template'
}
}
return render(request, template_name='app/legal.html', context=context)
def privacy(request) -> HttpResponse:
context = {
'site': {
'title': 'Django template'
}
}
return render(request, template_name='app/privacy.html', context=context)

22
manage.py Normal file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env python
# coding=utf-8
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'chaos_dating_project.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
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

30
package.json Normal file
View File

@ -0,0 +1,30 @@
{
"name": "django-template",
"version": "1.0.0",
"description": "Django template",
"main": "index.js",
"dependencies": {
"bootstrap": "^4.4.1",
"jquery": "^3.4.1",
"js-yaml": "3.13.1",
"popper.js": "^1.16.0"
},
"devDependencies": {
"autoprefixer": "^9.7.3",
"node-sass": "^4.12.0",
"sass-lint": "^1.13.1",
"eslint": "^4.18.2"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"compile:css": "node-sass -o static/css static/sass",
"compile:css:watch": "node-sass -o static/css static/sass --watch",
"lint:css": "sass-lint static/sass/** -v -q"
},
"repository": {
"type": "git",
"url": "https://git.2martens.de/2martens/django-template.git"
},
"author": "Jim Martens",
"license": "Apache-2.0"
}

1
project/__init__.py Normal file
View File

@ -0,0 +1 @@
# coding=utf-8

17
project/asgi.py Normal file
View File

@ -0,0 +1,17 @@
# coding=utf-8
"""
ASGI config for 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.0/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
application = get_asgi_application()

150
project/settings.py Normal file
View File

@ -0,0 +1,150 @@
# coding=utf-8
"""
Django settings for project.
Generated by 'django-admin startproject' using Django 3.0.1.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""
import os
from django.utils.translation import gettext_lazy as _
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'w$#!92p2fg8lykxr*aqi-&0llq81xq+7pe^733p(qt*n!0g_ci')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.environ.get('DJANGO_DEBUG', 'True') != 'False'
# extend with allowed production hosts
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '[::1]']
# Application definition
INSTALLED_APPS = [
'app.apps.DjangoTemplateConfig', # TODO: change to your app config class
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'crispy_forms',
'modeltranslation',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'project.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, "templates"),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
CRISPY_TEMPLATE_PACK = 'bootstrap4'
WSGI_APPLICATION = 'project.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
AUTH_PROFILE_MODULE = 'app.Profile'
LOGIN_REDIRECT_URL = 'app:index'
LOGOUT_REDIRECT_URL = 'app:index'
LOGIN_URL = 'login'
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'Europe/Berlin'
USE_I18N = True
USE_L10N = True
USE_TZ = True
LANGUAGES = [
('en-us', _('English')),
('de-de', _('German')),
]
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
# Security settings
SECURE_SSL_REDIRECT = not DEBUG
SESSION_COOKIE_SECURE = not DEBUG
CSRF_COOKIE_SECURE = not DEBUG
SECURE_REFERRER_POLICY = 'same-origin'

27
project/urls.py Normal file
View File

@ -0,0 +1,27 @@
# coding=utf-8
"""project URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include
from django.urls import path
from app import views
urlpatterns = [
path('admin/', admin.site.urls),
path('app/', include('app.urls')),
path('accounts/', include('app.account_urls')),
path('', views.index)
]

17
project/wsgi.py Normal file
View File

@ -0,0 +1,17 @@
# coding=utf-8
"""
WSGI config for 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.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
application = get_wsgi_application()

3
requirements.txt Normal file
View File

@ -0,0 +1,3 @@
django==3.0.3
django-crispy-forms==1.8.1
django-modeltranslation==0.14.2

10786
static/js/all.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,11 @@
/*!
* Bootstrap v4.3.1 (https://getbootstrap.com/)
* Copyright 2011-2019 The Bootstrap Authors
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
// overwrite variables
$body-bg: #fdfdfd;
$enable-responsive-font-sizes: true;
@import "../../node_modules/bootstrap/scss/bootstrap";

View File

@ -0,0 +1,342 @@
svg:not(:root).svg-inline--fa {
overflow: visible; }
.svg-inline--fa {
display: inline-block;
font-size: inherit;
height: 1em;
overflow: visible;
vertical-align: -.125em; }
.svg-inline--fa.fa-lg {
vertical-align: -.225em; }
.svg-inline--fa.fa-w-1 {
width: 0.0625em; }
.svg-inline--fa.fa-w-2 {
width: 0.125em; }
.svg-inline--fa.fa-w-3 {
width: 0.1875em; }
.svg-inline--fa.fa-w-4 {
width: 0.25em; }
.svg-inline--fa.fa-w-5 {
width: 0.3125em; }
.svg-inline--fa.fa-w-6 {
width: 0.375em; }
.svg-inline--fa.fa-w-7 {
width: 0.4375em; }
.svg-inline--fa.fa-w-8 {
width: 0.5em; }
.svg-inline--fa.fa-w-9 {
width: 0.5625em; }
.svg-inline--fa.fa-w-10 {
width: 0.625em; }
.svg-inline--fa.fa-w-11 {
width: 0.6875em; }
.svg-inline--fa.fa-w-12 {
width: 0.75em; }
.svg-inline--fa.fa-w-13 {
width: 0.8125em; }
.svg-inline--fa.fa-w-14 {
width: 0.875em; }
.svg-inline--fa.fa-w-15 {
width: 0.9375em; }
.svg-inline--fa.fa-w-16 {
width: 1em; }
.svg-inline--fa.fa-w-17 {
width: 1.0625em; }
.svg-inline--fa.fa-w-18 {
width: 1.125em; }
.svg-inline--fa.fa-w-19 {
width: 1.1875em; }
.svg-inline--fa.fa-w-20 {
width: 1.25em; }
.svg-inline--fa.fa-pull-left {
margin-right: .3em;
width: auto; }
.svg-inline--fa.fa-pull-right {
margin-left: .3em;
width: auto; }
.svg-inline--fa.fa-border {
height: 1.5em; }
.svg-inline--fa.fa-li {
width: 2em; }
.svg-inline--fa.fa-fw {
width: 1.25em; }
.fa-layers svg.svg-inline--fa {
bottom: 0;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0; }
.fa-layers {
display: inline-block;
height: 1em;
position: relative;
text-align: center;
vertical-align: -.125em;
width: 1em; }
.fa-layers svg.svg-inline--fa {
-webkit-transform-origin: center center;
transform-origin: center center; }
.fa-layers-text, .fa-layers-counter {
display: inline-block;
position: absolute;
text-align: center; }
.fa-layers-text {
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
-webkit-transform-origin: center center;
transform-origin: center center; }
.fa-layers-counter {
background-color: #ff253a;
border-radius: 1em;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: #fff;
height: 1.5em;
line-height: 1;
max-width: 5em;
min-width: 1.5em;
overflow: hidden;
padding: .25em;
right: 0;
text-overflow: ellipsis;
top: 0;
-webkit-transform: scale(0.25);
transform: scale(0.25);
-webkit-transform-origin: top right;
transform-origin: top right; }
.fa-layers-bottom-right {
bottom: 0;
right: 0;
top: auto;
-webkit-transform: scale(0.25);
transform: scale(0.25);
-webkit-transform-origin: bottom right;
transform-origin: bottom right; }
.fa-layers-bottom-left {
bottom: 0;
left: 0;
right: auto;
top: auto;
-webkit-transform: scale(0.25);
transform: scale(0.25);
-webkit-transform-origin: bottom left;
transform-origin: bottom left; }
.fa-layers-top-right {
right: 0;
top: 0;
-webkit-transform: scale(0.25);
transform: scale(0.25);
-webkit-transform-origin: top right;
transform-origin: top right; }
.fa-layers-top-left {
left: 0;
right: auto;
top: 0;
-webkit-transform: scale(0.25);
transform: scale(0.25);
-webkit-transform-origin: top left;
transform-origin: top left; }
.fa-lg {
font-size: 1.33333em;
line-height: 0.75em;
vertical-align: -.0667em; }
.fa-xs {
font-size: .75em; }
.fa-sm {
font-size: .875em; }
.fa-1x {
font-size: 1em; }
.fa-2x {
font-size: 2em; }
.fa-3x {
font-size: 3em; }
.fa-4x {
font-size: 4em; }
.fa-5x {
font-size: 5em; }
.fa-6x {
font-size: 6em; }
.fa-7x {
font-size: 7em; }
.fa-8x {
font-size: 8em; }
.fa-9x {
font-size: 9em; }
.fa-10x {
font-size: 10em; }
.fa-fw {
text-align: center;
width: 1.25em; }
.fa-ul {
list-style-type: none;
margin-left: 2.5em;
padding-left: 0; }
.fa-ul > li {
position: relative; }
.fa-li {
left: -2em;
position: absolute;
text-align: center;
width: 2em;
line-height: inherit; }
.fa-border {
border: solid 0.08em #eee;
border-radius: .1em;
padding: .2em .25em .15em; }
.fa-pull-left {
float: left; }
.fa-pull-right {
float: right; }
.fa.fa-pull-left,
.fas.fa-pull-left,
.far.fa-pull-left,
.fal.fa-pull-left,
.fab.fa-pull-left {
margin-right: .3em; }
.fa.fa-pull-right,
.fas.fa-pull-right,
.far.fa-pull-right,
.fal.fa-pull-right,
.fab.fa-pull-right {
margin-left: .3em; }
.fa-spin {
-webkit-animation: fa-spin 2s infinite linear;
animation: fa-spin 2s infinite linear; }
.fa-pulse {
-webkit-animation: fa-spin 1s infinite steps(8);
animation: fa-spin 1s infinite steps(8); }
@-webkit-keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); }
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg); } }
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); }
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg); } }
.fa-rotate-90 {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
-webkit-transform: rotate(90deg);
transform: rotate(90deg); }
.fa-rotate-180 {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
-webkit-transform: rotate(180deg);
transform: rotate(180deg); }
.fa-rotate-270 {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
-webkit-transform: rotate(270deg);
transform: rotate(270deg); }
.fa-flip-horizontal {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
-webkit-transform: scale(-1, 1);
transform: scale(-1, 1); }
.fa-flip-vertical {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
-webkit-transform: scale(1, -1);
transform: scale(1, -1); }
.fa-flip-both, .fa-flip-horizontal.fa-flip-vertical {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
-webkit-transform: scale(-1, -1);
transform: scale(-1, -1); }
:root .fa-rotate-90,
:root .fa-rotate-180,
:root .fa-rotate-270,
:root .fa-flip-horizontal,
:root .fa-flip-vertical,
:root .fa-flip-both {
-webkit-filter: none;
filter: none; }
.fa-stack {
display: inline-block;
height: 2em;
position: relative;
width: 2.5em; }
.fa-stack-1x,
.fa-stack-2x {
bottom: 0;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0; }
.svg-inline--fa.fa-stack-1x {
height: 1em;
width: 1.25em; }
.svg-inline--fa.fa-stack-2x {
height: 2em;
width: 2.5em; }
.fa-inverse {
color: #fff; }
.sr-only {
border: 0;
clip: rect(0, 0, 0, 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px; }
.sr-only-focusable:active, .sr-only-focusable:focus {
clip: auto;
height: auto;
margin: 0;
overflow: visible;
position: static;
width: auto; }

59
static/sass/main.scss Normal file
View File

@ -0,0 +1,59 @@
@charset "UTF-8";
@import "bootstrap-custom";
@import "fa-svg-with-js";
.site-header > .navbar {
//border-top: 5px solid $dark;
border-bottom: 2px solid $light;
}
// nav tabs
.nav-tabs {
margin-bottom: 1rem;
}
.euro {
text-align: right;
}
// back-to-top button
#back-to-top {
cursor: pointer;
position: -webkit-sticky;
position: sticky;
bottom: 40px;
display:none;
}
$navbarHeight: 58px;
#main {
margin-top: $navbarHeight + 15px;
margin-bottom: $navbarHeight + 15px;
}
#main.submenu {
margin-top: 2*$navbarHeight + 15px;
}
#countdown:before {
display: inline;
}
.site-header > .navbar {
background-color: $body-bg;
}
.site-footer {
border-top: 2px solid $light;
background-color: $body-bg;
}
.anchor {
position: relative;
display: block;
top: -$navbarHeight;
visibility: hidden;
}

0
templates/.gitkeep Normal file
View File

68
templates/base.html Normal file
View File

@ -0,0 +1,68 @@
{% load static %}
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
{% block meta %}{% endblock %}
<!-- FontAwesome -->
<script defer src="{% static "js/all.js" %}"></script>
<link type="text/css" href="{% static 'css/main.css' %}" rel="stylesheet" media="screen">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<header class="site-header">
{% block header %}{% endblock %}
</header>
<div id="main">
<div class="container">
<div class="row">
<div class="col">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
</div>
</div>
<div class="row">
<main class="col">
{% block content %}{% endblock %}
</main>
</div>
<button id="back-to-top"
class="btn btn-primary btn-lg"
title="Click to return to the start of the page" data-toggle="tooltip" data-placement="left">
<span class="fas fa-chevron-up"></span>
</button>
</div>
</div>
<footer class="site-footer small text-muted py-3">
<div class="container">
<div class="row">
{% block footer %}{% endblock %}
</div>
</div>
</footer>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
crossorigin="anonymous"></script>
{% block javascripts %}{% endblock %}
</body>
</html>

2395
yarn.lock Normal file

File diff suppressed because it is too large Load Diff